You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2026/02/28 00:09:14 UTC
(camel-karavan) branch main updated (1323636c -> 2b90ed4b)
This is an automated email from the ASF dual-hosted git repository.
marat pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
from 1323636c Camel Runtime 4.14.5
new ae55144b Java Code for 4.18.0
new bbfe6c20 Resources for 4.18.0
new cea7f0aa Dockerfile for 4.18.0
new d902703a Front-end config for 4.18.0
new 629650b6 Front-end API for 4.18.0
new 6203d0a2 Karavan-core for 4.18.0
new cb81ad8a Front-end Utils for 4.18.0
new ea211168 Front-end Stores for 4.18.0
new fa98128d Front-end Stores for 4.18.0
new c8369132 Front-end Configs for 4.18.0
new 20f173dc Front-end Shared UI for 4.18.0
new 2c4df962 Front-end Poller for 4.18.0
new 38c0258a Front-end Shared Icons for 4.18.0
new 01ac80a6 Front-end Services for 4.18.0
new a407a1a9 Front-end Models for 4.18.0
new 09ea30ee Front-end App for 4.18.0
new c8490c42 Front-end Fix for 4.18.0
new aeb8cc83 Front-end Project Designr and Developer for 4.18.0
new 19960ff7 Fix Backend for 4.18.0
new 803698eb Front-end Login for 4.18.0
new 838e0091 Front-end Login for 4.18.0
new 0b4e525b Front-end Navigation for 4.18.0
new 694e264d Front-end Access for 4.18.0
new 70eff99b Front-end Documentation for 4.18.0
new cabd7e6d Front-end Project for 4.18.0
new d6b33a42 Front-end Project for 4.18.0
new 2d790e4e Front-end Projects for 4.18.0
new 1991a4fc Backend for 4.18.0
new 6d7f93af Fron-end fixes for 4.18.0
new f57f88aa Fron-end fixes for 4.18.0
new ebcb4022 Fron-end fixes for 4.18.0
new 13f72216 4.18.0
new 2b90ed4b 4.18.0
The 33 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.github/DISCUSSION_TEMPLATE/q-a.yml | 2 +-
.github/ISSUE_TEMPLATE/bug_report.yml | 2 +-
.github/workflows/app.yml | 2 +-
.github/workflows/docker-devmode.yml | 2 +-
.github/workflows/vscode.yml | 2 +-
docs/VSCODE_HOWTO.md | 4 +-
docs/install/karavan-docker/docker-compose.yaml | 2 +-
docs/install/karavan-helm/Chart.yaml | 2 +-
docs/install/karavan-helm/values.yaml | 4 +-
docs/install/karavan-kubernetes/deployment.yaml | 4 +-
docs/install/karavan-kubernetes/kustomization.yaml | 2 +-
karavan-app/Dockerfile.dockerignore | 2 +-
karavan-app/pom.xml | 64 +-
karavan-app/src/main/docker/Dockerfile | 21 +-
.../org/apache/camel/karavan/KaravanConstants.java | 11 +-
.../org/apache/camel/karavan/KaravanEvents.java | 5 +
.../apache/camel/karavan/api/AccessResource.java | 36 +-
.../apache/camel/karavan/api/ActivityFilter.java | 10 +-
.../apache/camel/karavan/api/ActivityResource.java | 18 +-
.../org/apache/camel/karavan/api/AuthResource.java | 21 +-
.../camel/karavan/api/ContainerResource.java | 29 +-
.../karavan/api/CookieSessionAuthMechanism.java | 1 +
.../camel/karavan/api/GitCommitResource.java | 65 +
.../apache/camel/karavan/api/LogWatchResource.java | 89 +-
.../camel/karavan/api/ProjectFileResource.java | 36 +-
.../apache/camel/karavan/api/ProjectResource.java | 15 +-
.../camel/karavan/api/ProjectZipResource.java | 13 +-
.../apache/camel/karavan/api/PublicResource.java | 14 +-
.../apache/camel/karavan/cache/AccessPassword.java | 16 -
.../org/apache/camel/karavan/cache/AccessRole.java | 12 -
.../apache/camel/karavan/cache/AccessSession.java | 33 +-
.../org/apache/camel/karavan/cache/AccessUser.java | 27 -
.../org/apache/camel/karavan/cache/CacheEvent.java | 8 +
.../org/apache/camel/karavan/cache/CacheUtils.java | 25 +
.../apache/camel/karavan/cache/CamelStatus.java | 15 -
.../camel/karavan/cache/CamelStatusValue.java | 19 -
.../apache/camel/karavan/cache/ContainerPort.java | 14 -
.../apache/camel/karavan/cache/ContainerType.java | 18 -
.../camel/karavan/cache/DeploymentStatus.java | 26 -
.../org/apache/camel/karavan/cache/GroupedKey.java | 7 -
.../apache/camel/karavan/cache/KaravanCache.java | 458 +-
.../camel/karavan/cache/KaravanStoreSchema.java | 36 -
.../camel/karavan/cache/PodContainerStatus.java | 69 -
.../apache/camel/karavan/cache/ProjectFile.java | 17 -
.../camel/karavan/cache/ProjectFileCommitDiff.java | 48 +-
.../camel/karavan/cache/ProjectFileCommited.java | 62 +-
.../apache/camel/karavan/cache/ProjectFolder.java | 79 +-
.../camel/karavan/cache/ProjectFolderCommit.java | 24 +-
.../ProjectFolderCommited.java} | 43 +-
.../apache/camel/karavan/cache/ServiceStatus.java | 25 -
...{ProjectFolderCommit.java => SystemCommit.java} | 50 +-
.../camel/karavan/complexity/ComplexityFile.java | 10 +-
.../karavan/complexity/ComplexityProject.java | 19 +
.../camel/karavan/complexity/ComplexityRoute.java | 18 +
.../camel/karavan/docker/DockerEventHandler.java | 3 +-
.../camel/karavan/docker/DockerForKaravan.java | 10 +-
.../apache/camel/karavan/docker/DockerService.java | 476 +-
.../apache/camel/karavan/docker/DockerUtils.java | 10 +-
.../karavan/kubernetes/KubernetesService.java | 18 +-
.../camel/karavan/kubernetes/PodEventHandler.java | 6 +-
.../camel/karavan/listener/ActivityListener.java | 11 +-
.../camel/karavan/listener/CommitListener.java | 22 +-
.../karavan/listener/NotificationListener.java | 2 +
.../apache/camel/karavan/loader/CacheLoader.java | 61 +
.../GitLoader.java} | 102 +-
.../apache/camel/karavan/loader/StartupLoader.java | 99 +
.../apache/camel/karavan/model/ActivityUser.java | 31 +-
.../apache/camel/karavan/model/CommitResult.java | 9 +
.../camel/karavan/model/PathCommitDetails.java | 3 +
.../karavan/persistence/AccessCacheEntity.java | 28 +
.../karavan/persistence/PersistenceService.java | 108 +
.../karavan/persistence/ProjectCacheEntity.java | 29 +
.../karavan/persistence/SessionCacheEntity.java | 33 +
.../karavan/scheduler/ActivityCleanupService.java | 35 +
.../karavan/scheduler/CamelStatusScheduler.java | 2 +-
.../karavan/scheduler/DockerStatusScheduler.java | 22 +-
.../karavan/scheduler/KaravanSkipPredicate.java | 25 -
.../karavan/scheduler/SessionCleanupService.java | 23 +
.../apache/camel/karavan/service/AuthService.java | 48 +-
.../apache/camel/karavan/service/CodeService.java | 76 +-
.../camel/karavan/service/ComplexityService.java | 34 +-
.../camel/karavan/service/GitHistoryService.java | 310 +
.../apache/camel/karavan/service/GitService.java | 200 +-
.../camel/karavan/service/LogStreamingService.java | 165 +
.../camel/karavan/service/ProjectService.java | 163 +-
.../src/main/resources/application.properties | 44 +-
.../configuration/docker/components-blocklist.txt | 0
.../configuration/docker/kamelets-blocklist.txt | 0
.../kubernetes/components-blocklist.txt | 0
.../kubernetes/kamelets-blocklist.txt | 0
.../main/resources/contracts/docker/.gitignore} | 10 +-
.../resources/contracts/kubernetes/.gitignore} | 10 +-
.../src/main/resources/database/V1_0__karavan.sql | 33 +
karavan-app/src/main/resources/infinispan.xml | 120 -
.../src/main/resources/metadata/components.json | 765 +
.../src/main/resources/metadata/kamelets.yaml | 22588 +++++++++++++++++++
.../src/main/resources/metadata/spiBeans.json | 4253 ++++
.../templates/docker/application.properties | 2 +
.../docker/messaging-bean-template.camel.yaml | 9 -
....camel.yaml => wizard-bean-database.camel.yaml} | 0
.../docker/wizard-bean-messaging.camel.yaml | 11 +
.../templates/kubernetes/application.properties | 13 +-
.../kubernetes/messaging-bean-template.camel.yaml | 9 -
....camel.yaml => wizard-bean-database.camel.yaml} | 0
.../kubernetes/wizard-bean-messaging.camel.yaml | 11 +
karavan-app/src/main/webui/eslint.config.mjs | 8 +
karavan-app/src/main/webui/{src => }/index.css | 90 +-
karavan-app/src/main/webui/index.html | 17 +-
karavan-app/src/main/webui/{src => }/index.tsx | 0
karavan-app/src/main/webui/package-lock.json | 2988 +--
karavan-app/src/main/webui/package.json | 68 +-
karavan-app/src/main/webui/public/logo.svg | 178 +
.../src/main/webui/public/silent-check-sso.html | 8 +
karavan-app/src/main/webui/src/index.css | 90 +-
.../src/karavan-core/api/CamelDefinitionApi.ts | 92 +-
.../src/karavan-core/api/CamelDefinitionApiExt.ts | 31 +-
.../src/karavan-core/api/CamelDefinitionYaml.ts | 12 +-
.../karavan-core/api/CamelDefinitionYamlStep.ts | 129 +-
.../main/webui/src/karavan-core/api/CamelUtil.ts | 43 +-
.../webui/src/karavan-core/api/TopologyUtils.ts | 99 +-
.../src/main/webui/src/karavan-core/contants.ts | 8 +-
.../src/karavan-core/model/CamelDefinition.ts | 220 +-
.../webui/src/karavan-core/model/CamelMetadata.ts | 387 +-
.../src/karavan-core/model/TopologyDefinition.ts | 4 +-
.../src/main/webui/src/karavan/api/AccessApi.tsx | 31 +
.../src/main/webui/src/karavan/api/CustomApi.ts | 21 -
.../main/webui/src/karavan/api/DeveloperApi.tsx | 22 -
.../src/main/webui/src/karavan/api/KaravanApi.tsx | 129 +-
.../src/main/webui/src/karavan/api/LogWatchApi.tsx | 2 +-
.../main/webui/src/karavan/api/NotificationApi.tsx | 2 -
.../src/main/webui/src/karavan/api/SearchApi.tsx | 2 +-
.../src/main/webui/src/karavan/api/SystemApi.tsx | 1 -
karavan-app/src/main/webui/src/karavan/app/App.tsx | 20 +-
.../src/main/webui/src/karavan/app/MainHook.tsx | 31 +-
.../main/webui/src/karavan/app/ReadinessPanel.tsx | 29 +-
.../main/webui/src/karavan/app/login/LoginPage.css | 336 +-
.../main/webui/src/karavan/app/login/LoginPage.tsx | 180 +-
.../webui/src/karavan/app/login/OrbitLines.tsx | 68 +
.../webui/src/karavan/app/login/UserPopupOidc.tsx | 1 -
.../src/karavan/app/navigation/MainRoutes.tsx | 52 +-
.../src/karavan/app/navigation/NavigationMenu.tsx | 50 +-
.../karavan/app/navigation/NotAuthorizedPage.tsx | 16 +
.../src/karavan/app/navigation/PageNavigation.css | 185 +-
.../src/karavan/app/navigation/PageNavigation.tsx | 141 +-
.../src/karavan/app/navigation/PlatformLogo.tsx | 28 +
.../karavan/app/navigation/ProjectFunctionHook.tsx | 126 +-
.../webui/src/karavan/app/navigation/Routes.ts | 27 +-
.../webui/src/karavan/app/theme/DarkModeToggle.tsx | 16 +
.../webui/src/karavan/app/theme/ThemeContext.tsx | 45 +-
.../src/karavan/features/access/AccessPage.css | 0
.../src/karavan/features/access/AccessPage.tsx | 85 +-
.../karavan/features/access/roles/RoleModal.tsx | 18 +-
.../karavan/features/access/roles/RolesTable.tsx | 25 +-
.../features/access/roles/RolesTableRow.tsx | 26 +-
.../features/access/users/ChangePassword.tsx | 18 +-
.../features/access/users/PasswordModal.tsx | 18 +-
.../karavan/features/access/users/UserModal.tsx | 18 +-
.../karavan/features/access/users/UserProfile.tsx | 18 +-
.../features/access/users/UserProfileTab.tsx | 16 +
.../karavan/features/access/users/UsersTable.tsx | 25 +-
.../features/access/users/UsersTableRow.tsx | 17 +-
.../features/diagnostics/camel/CamelStatusRow.tsx | 53 -
.../diagnostics/camel/CamelStatusesTable.tsx | 52 -
.../features/documentation/Documentation.css | 1 -
.../features/documentation/DocumentationPage.tsx | 10 +-
.../documentation/components/ComponentCard.tsx | 2 +-
.../documentation/components/ComponentModal.tsx | 4 +-
.../karavan/features/documentation/eip/EipCard.tsx | 2 +-
.../features/documentation/eip/EipModal.tsx | 4 +-
.../documentation/kamelets/KameletCard.tsx | 2 +-
.../documentation/kamelets/KameletModal.tsx | 2 +-
.../features/integration/DesignerSwitch.css | 23 -
.../karavan/features/integration/ProjectPanel.tsx | 102 -
.../designer/KaravanDesignerViewSwitch.tsx | 73 -
.../integration/designer/editor/CodeEditor.tsx | 69 -
.../integration/developer/DeveloperManager.tsx | 53 -
.../integration/developer/DeveloperToolbar.tsx | 22 -
.../features/integration/developer/EditorConfig.ts | 26 -
.../integration/developer/EditorToolbar.tsx | 58 -
.../developer/MonacoEditorWrapperStateless.tsx | 97 -
.../features/integration/files/FileComplexity.tsx | 134 -
.../integration-topology/CustomNode.tsx | 145 -
.../integration-topology/TopologyStore.ts | 182 -
.../integration-topology/TopologyToolbar.tsx | 134 -
.../graph/TopologyDagreLayout.ts | 98 -
.../integration-topology/graph/TopologyGroup.ts | 3 -
.../integration-topology/graph/TopologyLink.ts | 72 -
.../integration-topology/graph/TopologyNode.ts | 4 -
.../integration/toolbar/DevModeToolbar.css | 39 -
.../karavan/features/integrations/ProjectsTab.tsx | 132 -
.../{integration => project}/ContainerLogTab.tsx | 36 +-
.../{integration => project}/DesignerToggle.tsx | 41 +-
.../FileSearchToolbarItem.tsx | 4 +-
.../ImageDownloadToolbar.tsx | 4 +-
.../{integration => project}/Project.types.ts | 4 +-
.../ProjectContainerContextToolbar.tsx | 4 +-
.../ProjectContainersContextProvider.tsx | 7 +-
.../{integration => project}/ProjectContext.tsx | 0
.../{integration => project}/ProjectPage.css | 5 +
.../{integration => project}/ProjectPage.tsx | 19 +-
.../ProjectPageNavigation.tsx | 61 +-
.../src/karavan/features/project/ProjectPanel.tsx | 86 +
.../{integration => project}/ProjectTitle.tsx | 1 -
.../{integration => project}/RenameFileModal.tsx | 2 +-
.../beans/BeanFilesDropdown.tsx | 0
.../{integration => project}/beans/BeanWizard.tsx | 73 +-
.../{integration => project}/designer/CodeStore.ts | 0
.../designer/DesignerStore.ts | 12 +-
.../designer/ErrorBoundaryWrapper.tsx | 0
.../designer/KaravanDesigner.css | 14 +-
.../designer/KaravanDesigner.tsx | 19 +-
.../project/designer/KaravanDesignerViewSwitch.tsx | 45 +
.../designer/beans/BeanCard.tsx | 0
.../designer/beans/BeansDesigner.tsx | 0
.../designer/beans/bean.css | 0
.../designer/icons/ComponentIcons.tsx | 8 +-
.../designer/icons/EipIcons.tsx | 0
.../designer/icons/KaravanIcons.tsx | 7 +-
.../designer/icons/OtherIcons.tsx | 0
.../designer/kamelet/KameletAnnotationsPanel.tsx | 2 +-
.../kamelet/KameletDefinitionPropertyCard.tsx | 0
.../designer/kamelet/KameletDefinitionsPanel.tsx | 2 +-
.../designer/kamelet/KameletDependenciesCard.tsx | 2 +-
.../designer/kamelet/KameletDesigner.tsx | 5 +-
.../designer/kamelet/KameletInput.tsx | 2 +-
.../designer/kamelet/KameletTypesOutCard.tsx | 2 +-
.../designer/kamelet/kamelet.css | 0
.../{integration => project}/designer/karavan.css | 0
.../designer/property/DslProperties.css | 2 +-
.../designer/property/DslProperties.tsx | 10 +-
.../designer/property/MainPropertiesPanel.tsx | 40 +-
.../designer/property/PropertiesHeader.tsx | 0
.../designer/property/PropertyStore.ts | 6 +-
.../property/expression/ExpressionBottomPanel.tsx | 0
.../property/expression/ExpressionContextModel.tsx | 0
.../property/expression/ExpressionEditor.css | 0
.../property/expression/ExpressionEditor.tsx | 2 +
.../designer/property/property/BeanProperties.css | 0
.../designer/property/property/BeanProperties.tsx | 10 +-
.../property/property/ComponentPropertyField.css | 0
.../property/property/ComponentPropertyField.tsx | 7 +-
.../property/ConfigurationSelectorModal.css | 0
.../property/ConfigurationSelectorModal.tsx | 4 +-
.../designer/property/property/DataFormatField.tsx | 0
.../property/property/DslPropertyField.css | 0
.../property/property/DslPropertyField.tsx | 20 +-
.../property/property/DslPropertyFieldSelect.tsx | 4 +-
.../property/DslPropertyFieldSelectScrollable.tsx | 2 +-
.../designer/property/property/ExpressionField.tsx | 2 +-
.../property/property/FileReferenceDropdown.css | 0
.../property/property/FileReferenceDropdown.tsx | 2 +-
.../property/property/KameletPropertyField.css | 0
.../property/property/KameletPropertyField.tsx | 2 +-
.../designer/property/property/ObjectField.tsx | 0
.../property/PropertyPlaceholderDropdown.css | 0
.../property/PropertyPlaceholderDropdown.tsx | 0
.../designer/property/property/PropertyUtil.tsx | 0
.../property/property/VariablesDropdown.css | 0
.../property/property/VariablesDropdown.tsx | 2 +-
.../designer/property/usePropertiesHook.tsx | 2 +-
.../designer/rest/RestCard.tsx | 2 +-
.../designer/rest/RestConfigurationCard.tsx | 2 +-
.../designer/rest/RestDesigner.tsx | 2 +-
.../designer/rest/RestMethodCard.tsx | 2 +-
.../designer/rest/RestMethodSelector.tsx | 2 -
.../designer/rest/rest.css | 0
.../designer/route/DeleteConfirmation.tsx | 0
.../designer/route/DslConnections.css | 0
.../designer/route/DslConnections.tsx | 2 +-
.../designer/route/RouteDesigner.css | 0
.../designer/route/RouteDesigner.tsx | 0
.../designer/route/element/DslElement.css | 0
.../designer/route/element/DslElement.tsx | 0
.../designer/route/element/DslElementHeader.tsx | 6 +-
.../designer/route/element/DslElementMoveModal.tsx | 0
.../route/element/RouteTemplateElement.css | 0
.../route/element/RouteTemplateElement.tsx | 2 +-
.../designer/route/useResizeObserver.tsx | 0
.../designer/route/useRouteDesignerHook.tsx | 17 +-
.../designer/selector/DslCard.tsx | 8 +-
.../designer/selector/DslFastCard.tsx | 8 +-
.../designer/selector/DslPreferences.tsx | 0
.../designer/selector/DslSelector.css | 0
.../designer/selector/DslSelector.tsx | 14 +-
.../designer/utils/CamelDefaultStepProperty.tsx | 0
.../designer/utils/CamelUi.tsx | 14 +-
.../designer/utils/DslMetaModel.ts | 0
.../designer/utils/ElementIcon.css | 0
.../designer/utils/ElementIcons.tsx | 0
.../designer/utils/EventBus.ts | 9 +-
.../designer/utils/InfrastructureAPI.ts | 0
.../designer/utils/IntegrationHeader.tsx | 0
.../designer/utils/MediaTypes.ts | 0
.../designer/utils/Notification.tsx | 2 +-
.../designer/utils/ValidatorUtils.ts | 0
.../developer/CodeEditor.tsx | 27 +-
.../developer/DataEditor.css | 0
.../developer/DesignerEditor.tsx | 21 +-
.../developer/DeveloperEditor.tsx | 39 +-
.../developer/DeveloperManager.css | 2 +
.../project/developer/DeveloperManager.tsx | 95 +
.../project/developer/DeveloperToolbar.tsx} | 28 +-
.../features/project/developer/EditorConfig.ts} | 49 +-
.../developer/EditorErrorBoundaryWrapper.tsx | 18 +-
.../developer/EditorOverlayWidget.css | 0
.../developer/EditorOverlayWidget.tsx | 16 +
.../features/project/developer/EditorToolbar.tsx | 74 +
.../features/project/developer/MarkdownEditor.tsx | 72 +
.../developer/MonacoEditorWrapper.tsx | 26 +-
.../features/{integration => project}/devmode.css | 0
.../files/CreateFileModal.tsx | 24 +-
.../files/CreateProjectModal.tsx} | 4 +-
.../files/DeleteFileModal.tsx | 2 +-
.../files/DiffFileModal.css | 0
.../files/DiffFileModal.tsx | 68 +-
.../files/FileCopyForEnvModal.tsx | 2 +-
.../files/FilesSubTab.tsx} | 253 +-
.../files/FilesTab.tsx} | 39 +-
.../features/project/files/FilesTabUtils.tsx | 119 +
.../files/FilesToolbar.tsx | 102 +-
.../features/project/files/SourcesDrawerPanel.tsx | 19 +
.../karavan/features/project/files/SourcesTab.css | 22 +
.../karavan/features/project/files/SourcesTab.tsx | 35 +
.../files/UploadFileModal.tsx | 47 +-
.../project-build}/BuildTab.tsx | 6 +-
.../project-containers}/ContainerButtons.tsx | 7 +-
.../ContainerEnvironmentPanel.tsx | 9 +-
.../project-containers}/ContainersTab.tsx | 17 +-
.../project-containers}/ContainersTable.tsx | 4 +-
.../project-containers}/ContainersTableRow.tsx | 0
.../project-containers}/ContainersToolbar.tsx | 0
.../project-containers}/DeploymentButtons.tsx | 4 +-
.../project-containers}/DeploymentPanel.tsx | 2 +-
.../project-containers}/ImagesPanel.tsx | 2 +-
.../project-pod}/PodEventsLogTable.tsx | 0
.../features/project/project-pod/PodTab.tsx | 16 +
.../project-topology}/CustomComponentFactory.tsx | 8 +-
.../project-topology}/CustomEdge.tsx | 0
.../project-topology}/CustomGroup.tsx | 0
.../project/project-topology/CustomNode.tsx | 178 +
.../project-topology}/GetCustomMenu.tsx | 0
.../project-topology}/TopologyApi.tsx | 153 +-
.../project-topology}/TopologyBeans.css | 0
.../project-topology}/TopologyBeans.tsx | 2 +-
.../project/project-topology/TopologyElkLayout.ts | 222 +
.../project-topology}/TopologyLegend.css | 0
.../project-topology}/TopologyLegend.tsx | 4 +-
.../project-topology}/TopologyTab.tsx | 74 +-
.../project/project-topology/TopologyToolbar.tsx | 102 +
.../project-topology}/topology.css | 72 +-
.../project-topology}/useTopologyHook.tsx | 2 +-
.../{integration => project}/readme/ReadmeTab.tsx | 0
.../toolbar/BuildToolbar.tsx | 7 +-
.../features/project/toolbar/DevModeToolbar.css | 60 +
.../toolbar/DevModeToolbar.tsx | 39 +-
.../toolbar/ProjectToolbar.tsx | 30 +-
.../{integration => project}/useProjectHook.tsx | 8 +-
.../{integrations => projects}/Complexity.css | 17 +-
.../{integrations => projects}/ComplexityApi.tsx | 0
.../{integrations => projects}/ComplexityModels.ts | 5 +
.../CreateProjectModal.tsx | 16 +-
.../DeleteProjectModal.tsx | 0
.../ProjectStatusLabel.tsx | 35 +-
.../{integrations => projects}/ProjectZipApi.tsx | 0
.../ProjectsPage.tsx} | 45 +-
.../src/karavan/features/projects/ProjectsTab.tsx | 146 +
.../ProjectsTableRow.tsx | 87 +-
.../ProjectsTableRowActivity.tsx | 0
.../ProjectsTableRowComplexity.tsx | 18 +-
.../features/projects/ProjectsTableRowTimeLine.css | 43 +
.../features/projects/ProjectsTableRowTimeLine.tsx | 48 +
.../{integrations => projects}/ProjectsToolbar.tsx | 32 +-
.../{integrations => projects}/SettingsToolbar.tsx | 5 +-
.../UploadProjectModal.tsx | 2 +-
.../src/karavan/features/settings/SettingsPage.tsx | 110 +
.../src/karavan/features/system/SystemPage.tsx | 79 +-
.../system/containers/ContainerTableRow.tsx | 8 +-
.../features/system/containers/ContainersTable.tsx | 9 +-
.../main/webui/src/karavan/models/AccessModels.ts | 16 +
.../main/webui/src/karavan/models/ProjectModels.ts | 49 +-
.../main/webui/src/karavan/models/SearchModels.ts | 17 +
.../main/webui/src/karavan/models/ServiceModels.ts | 11 -
.../main/webui/src/karavan/models/SystemModels.ts | 17 +
.../webui/src/karavan/services/AccessService.ts | 20 +-
.../src/karavan/services/NotificationService.ts | 7 +-
.../webui/src/karavan/services/ProjectService.ts | 69 +-
.../webui/src/karavan/services/SystemService.ts | 16 +
.../webui/src/karavan/shared/icons/application.svg | 13 +
.../main/webui/src/karavan/shared/icons/apps.svg | 72 +
.../webui/src/karavan/shared/icons/asyncapi.svg | 183 -
.../main/webui/src/karavan/shared/icons/groovy.svg | 40 +-
.../main/webui/src/karavan/shared/icons/jib.png | Bin 0 -> 42246 bytes
.../webui/src/karavan/shared/icons/jkube-logo.svg | 38 +
.../main/webui/src/karavan/shared/icons/jkube.svg | 41 +
.../webui/src/karavan/shared/icons/json-schema.svg | 28 -
.../main/webui/src/karavan/shared/icons/logout.svg | 30 +
.../webui/src/karavan/shared/icons/settings.svg | 28 +
.../main/webui/src/karavan/shared/monaco-setup.ts | 29 +-
.../src/karavan/shared/polling/useDataPolling.ts | 48 +-
.../src/karavan/shared/ui/ContainerButton.tsx | 4 +-
.../webui/src/karavan/shared/ui/MainToolbar.css | 25 +
.../webui/src/karavan/shared/ui/MainToolbar.tsx | 9 +-
.../src/karavan/shared/ui/ModalConfirmation.tsx | 29 +-
.../webui/src/karavan/shared/ui/PlatformLogos.css | 37 +
.../webui/src/karavan/shared/ui/PlatformLogos.tsx | 66 +
.../webui/src/karavan/shared/ui/RightPanel.css | 6 +-
.../webui/src/karavan/shared/ui/RightPanel.tsx | 2 +-
.../main/webui/src/karavan/stores/AccessStore.ts | 16 +
.../src/karavan/stores/ContainerStatusesStore.ts | 48 +
.../webui/src/karavan/stores/DeveloperStore.ts | 14 -
.../src/main/webui/src/karavan/stores/LogStore.ts | 58 +
.../main/webui/src/karavan/stores/ProjectStore.ts | 151 +-
.../main/webui/src/karavan/stores/SearchStore.ts | 18 +-
.../main/webui/src/karavan/stores/SettingsStore.ts | 88 +
.../main/webui/src/karavan/stores/SystemStore.ts | 16 +
.../main/webui/src/karavan/stores/TopologyStore.ts | 63 +
.../src/main/webui/src/karavan/util/CodeUtils.ts | 109 +-
.../src/main/webui/src/karavan/util/StringUtils.ts | 62 +
karavan-app/src/main/webui/tsconfig.json | 1 +
karavan-app/src/main/webui/vite-env.d.ts | 2 +-
karavan-app/src/main/webui/vite.config.ts | 81 +-
karavan-core/package-lock.json | 4 +-
karavan-core/package.json | 2 +-
karavan-devmode/Dockerfile | 12 +-
karavan-generator/dependency-reduced-pom.xml | 82 -
karavan-generator/pom.xml | 6 +-
karavan-vscode/CHANGELOG.md | 7 +
karavan-vscode/README.md | 4 +-
karavan-vscode/package-lock.json | 4 +-
karavan-vscode/package.json | 6 +-
430 files changed, 36932 insertions(+), 8097 deletions(-)
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/api/GitCommitResource.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheEvent.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheUtils.java
delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanStoreSchema.java
copy karavan-app/src/main/java/org/apache/camel/karavan/{model/GitRepoFile.java => cache/ProjectFolderCommited.java} (59%)
copy karavan-app/src/main/java/org/apache/camel/karavan/cache/{ProjectFolderCommit.java => SystemCommit.java} (63%)
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/loader/CacheLoader.java
rename karavan-app/src/main/java/org/apache/camel/karavan/{KaravanStartupLoader.java => loader/GitLoader.java} (53%)
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/loader/StartupLoader.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/CommitResult.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/PathCommitDetails.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/persistence/AccessCacheEntity.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/persistence/PersistenceService.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/persistence/ProjectCacheEntity.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/persistence/SessionCacheEntity.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/scheduler/ActivityCleanupService.java
delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/scheduler/KaravanSkipPredicate.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/scheduler/SessionCleanupService.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/service/GitHistoryService.java
create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/service/LogStreamingService.java
delete mode 100644 karavan-app/src/main/resources/configuration/docker/components-blocklist.txt
delete mode 100644 karavan-app/src/main/resources/configuration/docker/kamelets-blocklist.txt
delete mode 100644 karavan-app/src/main/resources/configuration/kubernetes/components-blocklist.txt
delete mode 100644 karavan-app/src/main/resources/configuration/kubernetes/kamelets-blocklist.txt
copy karavan-app/{.dockerignore => src/main/resources/contracts/docker/.gitignore} (90%)
copy karavan-app/{.dockerignore => src/main/resources/contracts/kubernetes/.gitignore} (90%)
create mode 100644 karavan-app/src/main/resources/database/V1_0__karavan.sql
delete mode 100644 karavan-app/src/main/resources/infinispan.xml
create mode 100644 karavan-app/src/main/resources/metadata/components.json
create mode 100644 karavan-app/src/main/resources/metadata/kamelets.yaml
create mode 100644 karavan-app/src/main/resources/metadata/spiBeans.json
delete mode 100644 karavan-app/src/main/resources/templates/docker/messaging-bean-template.camel.yaml
rename karavan-app/src/main/resources/templates/docker/{database-bean-template.camel.yaml => wizard-bean-database.camel.yaml} (100%)
create mode 100644 karavan-app/src/main/resources/templates/docker/wizard-bean-messaging.camel.yaml
delete mode 100644 karavan-app/src/main/resources/templates/kubernetes/messaging-bean-template.camel.yaml
rename karavan-app/src/main/resources/templates/kubernetes/{database-bean-template.camel.yaml => wizard-bean-database.camel.yaml} (100%)
create mode 100644 karavan-app/src/main/resources/templates/kubernetes/wizard-bean-messaging.camel.yaml
create mode 100644 karavan-app/src/main/webui/eslint.config.mjs
copy karavan-app/src/main/webui/{src => }/index.css (76%)
copy karavan-app/src/main/webui/{src => }/index.tsx (100%)
create mode 100644 karavan-app/src/main/webui/public/logo.svg
create mode 100644 karavan-app/src/main/webui/public/silent-check-sso.html
delete mode 100644 karavan-app/src/main/webui/src/karavan/api/CustomApi.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/api/DeveloperApi.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/app/login/OrbitLines.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/access/AccessPage.css
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusRow.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusesTable.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/DesignerSwitch.css
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/ProjectPanel.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesignerViewSwitch.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/designer/editor/CodeEditor.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/developer/DeveloperManager.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/developer/DeveloperToolbar.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/developer/EditorConfig.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/developer/EditorToolbar.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/developer/MonacoEditorWrapperStateless.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/files/FileComplexity.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/CustomNode.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/TopologyStore.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/TopologyToolbar.tsx
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/graph/TopologyDagreLayout.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/graph/TopologyGroup.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/graph/TopologyLink.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/integration-topology/graph/TopologyNode.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integration/toolbar/DevModeToolbar.css
delete mode 100644 karavan-app/src/main/webui/src/karavan/features/integrations/ProjectsTab.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ContainerLogTab.tsx (73%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/DesignerToggle.tsx (65%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/FileSearchToolbarItem.tsx (92%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ImageDownloadToolbar.tsx (94%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/Project.types.ts (73%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectContainerContextToolbar.tsx (94%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectContainersContextProvider.tsx (94%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectContext.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectPage.css (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectPage.tsx (85%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectPageNavigation.tsx (71%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/ProjectPanel.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/ProjectTitle.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/RenameFileModal.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/beans/BeanFilesDropdown.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/beans/BeanWizard.tsx (90%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/CodeStore.ts (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/DesignerStore.ts (97%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/ErrorBoundaryWrapper.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/KaravanDesigner.css (82%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/KaravanDesigner.tsx (93%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesignerViewSwitch.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/beans/BeanCard.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/beans/BeansDesigner.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/beans/bean.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/icons/ComponentIcons.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/icons/EipIcons.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/icons/KaravanIcons.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/icons/OtherIcons.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletAnnotationsPanel.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletDefinitionPropertyCard.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletDefinitionsPanel.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletDependenciesCard.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletDesigner.tsx (91%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletInput.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/KameletTypesOutCard.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/kamelet/kamelet.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/karavan.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/DslProperties.css (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/DslProperties.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/MainPropertiesPanel.tsx (58%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/PropertiesHeader.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/PropertyStore.ts (93%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/expression/ExpressionBottomPanel.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/expression/ExpressionContextModel.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/expression/ExpressionEditor.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/expression/ExpressionEditor.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/BeanProperties.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/BeanProperties.tsx (95%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ComponentPropertyField.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ComponentPropertyField.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ConfigurationSelectorModal.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ConfigurationSelectorModal.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/DataFormatField.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/DslPropertyField.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/DslPropertyField.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/DslPropertyFieldSelect.tsx (95%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/DslPropertyFieldSelectScrollable.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ExpressionField.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/FileReferenceDropdown.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/FileReferenceDropdown.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/KameletPropertyField.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/KameletPropertyField.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/ObjectField.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/PropertyPlaceholderDropdown.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/PropertyPlaceholderDropdown.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/PropertyUtil.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/VariablesDropdown.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/property/VariablesDropdown.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/property/usePropertiesHook.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/RestCard.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/RestConfigurationCard.tsx (97%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/RestDesigner.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/RestMethodCard.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/RestMethodSelector.tsx (96%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/rest/rest.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/DeleteConfirmation.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/DslConnections.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/DslConnections.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/RouteDesigner.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/RouteDesigner.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/DslElement.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/DslElement.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/DslElementHeader.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/DslElementMoveModal.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/RouteTemplateElement.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/element/RouteTemplateElement.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/useResizeObserver.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/route/useRouteDesignerHook.tsx (96%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/selector/DslCard.tsx (93%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/selector/DslFastCard.tsx (94%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/selector/DslPreferences.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/selector/DslSelector.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/selector/DslSelector.tsx (97%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/CamelDefaultStepProperty.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/CamelUi.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/DslMetaModel.ts (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/ElementIcon.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/ElementIcons.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/EventBus.ts (92%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/InfrastructureAPI.ts (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/IntegrationHeader.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/MediaTypes.ts (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/Notification.tsx (97%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/designer/utils/ValidatorUtils.ts (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/CodeEditor.tsx (54%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/DataEditor.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/DesignerEditor.tsx (86%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/DeveloperEditor.tsx (54%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/DeveloperManager.css (98%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/developer/DeveloperManager.tsx
copy karavan-app/src/main/webui/src/karavan/{shared/ui/MainToolbar.tsx => features/project/developer/DeveloperToolbar.tsx} (64%)
copy karavan-app/src/main/webui/src/{karavan-core/model/ProjectModel.ts => karavan/features/project/developer/EditorConfig.ts} (53%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/EditorErrorBoundaryWrapper.tsx (68%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/EditorOverlayWidget.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/EditorOverlayWidget.tsx (52%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/developer/EditorToolbar.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/developer/MarkdownEditor.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/developer/MonacoEditorWrapper.tsx (89%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/devmode.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/CreateFileModal.tsx (81%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/files/CreateIntegrationModal.tsx => project/files/CreateProjectModal.tsx} (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/DeleteFileModal.tsx (97%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/DiffFileModal.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/DiffFileModal.tsx (56%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/FileCopyForEnvModal.tsx (98%)
copy karavan-app/src/main/webui/src/karavan/features/{integration/files/FilesTabWithComplexity.tsx => project/files/FilesSubTab.tsx} (65%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/files/FilesTabWithComplexity.tsx => project/files/FilesTab.tsx} (93%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/files/FilesTabUtils.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/FilesToolbar.tsx (73%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/files/SourcesDrawerPanel.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.css
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/files/UploadFileModal.tsx (79%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-build => project/project-build}/BuildTab.tsx (83%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainerButtons.tsx (96%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainerEnvironmentPanel.tsx (94%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainersTab.tsx (51%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainersTable.tsx (91%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainersTableRow.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ContainersToolbar.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/DeploymentButtons.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/DeploymentPanel.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-containers}/ImagesPanel.tsx (99%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-containers => project/project-pod}/PodEventsLogTable.tsx (100%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodTab.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/CustomComponentFactory.tsx (92%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/CustomEdge.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/CustomGroup.tsx (100%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomNode.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/GetCustomMenu.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyApi.tsx (86%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyBeans.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyBeans.tsx (97%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyElkLayout.ts
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyLegend.css (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyLegend.tsx (91%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/TopologyTab.tsx (69%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyToolbar.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/topology.css (65%)
rename karavan-app/src/main/webui/src/karavan/features/{integration/integration-topology => project/project-topology}/useTopologyHook.tsx (98%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/readme/ReadmeTab.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/toolbar/BuildToolbar.tsx (96%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.css
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/toolbar/DevModeToolbar.tsx (85%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/toolbar/ProjectToolbar.tsx (62%)
rename karavan-app/src/main/webui/src/karavan/features/{integration => project}/useProjectHook.tsx (96%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/Complexity.css (54%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ComplexityApi.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ComplexityModels.ts (93%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/CreateProjectModal.tsx (88%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/DeleteProjectModal.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectStatusLabel.tsx (77%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectZipApi.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations/IntegrationsPage.tsx => projects/ProjectsPage.tsx} (60%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTab.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectsTableRow.tsx (53%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectsTableRowActivity.tsx (100%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectsTableRowComplexity.tsx (68%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.css
create mode 100644 karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.tsx
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/ProjectsToolbar.tsx (76%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/SettingsToolbar.tsx (90%)
rename karavan-app/src/main/webui/src/karavan/features/{integrations => projects}/UploadProjectModal.tsx (98%)
create mode 100644 karavan-app/src/main/webui/src/karavan/features/settings/SettingsPage.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/application.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/apps.svg
delete mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/asyncapi.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/jib.png
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/jkube-logo.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/jkube.svg
delete mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/json-schema.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/logout.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/icons/settings.svg
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.css
create mode 100644 karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
create mode 100644 karavan-app/src/main/webui/src/karavan/stores/ContainerStatusesStore.ts
delete mode 100644 karavan-app/src/main/webui/src/karavan/stores/DeveloperStore.ts
create mode 100644 karavan-app/src/main/webui/src/karavan/stores/LogStore.ts
create mode 100644 karavan-app/src/main/webui/src/karavan/stores/SettingsStore.ts
create mode 100644 karavan-app/src/main/webui/src/karavan/stores/TopologyStore.ts
delete mode 100644 karavan-generator/dependency-reduced-pom.xml
(camel-karavan) 15/33: Front-end Models for 4.18.0
Posted by ma...@apache.org.
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 a407a1a9cc6ad81526dd313e57c719fd014f56c9
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:32:27 2026 -0500
Front-end Models for 4.18.0
---
.../main/webui/src/karavan/models/AccessModels.ts | 16 +++++++
.../main/webui/src/karavan/models/ProjectModels.ts | 49 ++++++++++++++--------
.../main/webui/src/karavan/models/SearchModels.ts | 17 ++++++++
.../main/webui/src/karavan/models/ServiceModels.ts | 11 -----
.../main/webui/src/karavan/models/SystemModels.ts | 17 ++++++++
5 files changed, 81 insertions(+), 29 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/models/AccessModels.ts b/karavan-app/src/main/webui/src/karavan/models/AccessModels.ts
index b96460bf..f633a328 100644
--- a/karavan-app/src/main/webui/src/karavan/models/AccessModels.ts
+++ b/karavan-app/src/main/webui/src/karavan/models/AccessModels.ts
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
export class AccessUser {
username: string = '';
firstName: string = '';
diff --git a/karavan-app/src/main/webui/src/karavan/models/ProjectModels.ts b/karavan-app/src/main/webui/src/karavan/models/ProjectModels.ts
index 5ed841eb..269f7d45 100644
--- a/karavan-app/src/main/webui/src/karavan/models/ProjectModels.ts
+++ b/karavan-app/src/main/webui/src/karavan/models/ProjectModels.ts
@@ -15,9 +15,6 @@
* limitations under the License.
*/
-
-import {ASYNCAPI_FILE_NAME_JSON, ASYNCAPI_FILE_NAME_YAML} from "@karavan-core/contants";
-
export type FileOperation =
| "create"
| "select"
@@ -37,7 +34,17 @@ export const DOCKER_STACK = "docker-stack.yaml";
export const KUBERNETES_YAML = "kubernetes.yaml";
export const APPLICATION_PROPERTIES = 'application.properties';
export const BUILD_SH = 'build.sh';
-export const BUILD_IN_FILES = [APPLICATION_PROPERTIES, DOCKER_COMPOSE, DOCKER_STACK, KUBERNETES_YAML, ASYNCAPI_FILE_NAME_JSON, ASYNCAPI_FILE_NAME_YAML, BUILD_SH];
+export const BUILD_DOCKER_COMPOSE = 'builder.' + DOCKER_COMPOSE;
+export const BUILD_DOCKER_STACK = 'builder.' + DOCKER_STACK;
+export const BUILD_IN_FILES = [
+ APPLICATION_PROPERTIES,
+ DOCKER_COMPOSE,
+ DOCKER_STACK,
+ KUBERNETES_YAML,
+ BUILD_SH,
+ BUILD_DOCKER_COMPOSE,
+ BUILD_DOCKER_STACK
+];
export class AppConfig {
title: string = '';
@@ -59,8 +66,6 @@ export enum ProjectType {
configuration = 'configuration',
documentation = 'documentation',
services = 'services',
- shared = 'shared',
- cache = 'cache',
integration = 'integration',
}
@@ -69,17 +74,21 @@ export const BUILD_IN_PROJECTS: string[] = [
ProjectType.templates.toString(),
ProjectType.configuration.toString(),
ProjectType.services.toString(),
- ProjectType.shared.toString(),
ProjectType.documentation.toString()
];
export const RESERVED_WORDS: string[] = [...BUILD_IN_PROJECTS, 'karavan'];
+export interface ProjectCommited {
+ projectId: string;
+ lastCommit: string;
+ lastCommitTimestamp: number;
+}
+
export class Project {
projectId: string = '';
name: string = '';
- lastCommit: string = '';
- lastCommitTimestamp: number = 0;
+ lastUpdate: number = 0;
type: string = ProjectType.integration;
public constructor(projectId: string, name: string, lastCommit: string, type: string);
@@ -91,9 +100,8 @@ export class Project {
} else {
this.projectId = args[0];
this.name = args[1];
- this.lastCommit = args[2];
- this.lastCommitTimestamp = args[3];
- this.type = args[4];
+ this.lastUpdate = args[2];
+ this.type = args[3];
return;
}
}
@@ -108,7 +116,7 @@ export class DeploymentStatus {
replicas: number = 0;
readyReplicas: number = 0;
unavailableReplicas: number = 0;
- type: 'devmode' | 'devservice' | 'packaged' | 'internal' | 'build' | 'unknown' = 'unknown';
+ type: 'devmode' | 'packaged' | 'internal' | 'build' | 'unknown' = 'unknown';
}
export class ServiceStatus {
@@ -128,7 +136,7 @@ export class ContainerPort {
type: string = '';
}
-export type ContainerType = 'devmode' | 'devservice' | 'packaged' | 'internal' | 'build' | 'unknown';
+export type ContainerType = 'devmode' | 'packaged' | 'internal' | 'build' | 'unknown';
export class ContainerStatus {
containerName: string = '';
@@ -196,6 +204,15 @@ export class ProjectFile {
}
}
+export interface ProjectFileCommited {
+ name: string;
+ projectId: string;
+ code: string;
+ commitTime: number;
+ syncDate: number;
+}
+
+
export class ProjectFileType {
name: string = '';
title: string = '';
@@ -224,8 +241,6 @@ export const ProjectFileTypes: ProjectFileType[] = [
new ProjectFileType("PROPERTIES", "Properties", "properties"),
new ProjectFileType("JSON", "JSON", "json"),
new ProjectFileType("OPENAPI", "OpenAPI", "json"),
- new ProjectFileType("ASYNCAPI", "AsyncAPI", "yaml"),
- new ProjectFileType("ASYNCAPI", "AsyncAPI", "json"),
new ProjectFileType("YAML", "YAML", "yaml"),
new ProjectFileType("DOCKER", "Docker Compose", "yaml"),
new ProjectFileType("SH", "Script", "sh"),
@@ -241,8 +256,6 @@ export function getProjectFileTypeByName(fileName: string): ProjectFileType[] {
if (fileName.endsWith(".camel.yaml")) return ProjectFileTypes.filter(p => p.name === "INTEGRATION")
if (fileName.endsWith(".kamelet.yaml")) return ProjectFileTypes.filter(p => p.name === "KAMELET")
if (fileName === "openapi.json") return ProjectFileTypes.filter(p => p.name === "OPENAPI")
- if (fileName === "asyncapi.json") return ProjectFileTypes.filter(p => p.name === "ASYNCAPI")
- if (fileName === "asyncapi.yaml") return ProjectFileTypes.filter(p => p.name === "ASYNCAPI")
if (fileName.endsWith(".json")) return ProjectFileTypes.filter(p => p.name === "JSON")
if (fileName.endsWith(".yaml")) return ProjectFileTypes.filter(p => p.name === "YAML")
if (fileName.endsWith(".yml")) return ProjectFileTypes.filter(p => p.name === "YAML")
diff --git a/karavan-app/src/main/webui/src/karavan/models/SearchModels.ts b/karavan-app/src/main/webui/src/karavan/models/SearchModels.ts
index 9ed9f384..7d320b71 100644
--- a/karavan-app/src/main/webui/src/karavan/models/SearchModels.ts
+++ b/karavan-app/src/main/webui/src/karavan/models/SearchModels.ts
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
export class SearchResult {
projectId: string = '';
files: string[] = [];
diff --git a/karavan-app/src/main/webui/src/karavan/models/ServiceModels.ts b/karavan-app/src/main/webui/src/karavan/models/ServiceModels.ts
index ba6428d5..6578e17e 100644
--- a/karavan-app/src/main/webui/src/karavan/models/ServiceModels.ts
+++ b/karavan-app/src/main/webui/src/karavan/models/ServiceModels.ts
@@ -68,14 +68,3 @@ export class ServicesYaml {
return result;
}
}
-
-export class DevService {
- name: string = '';
- image: string = '';
- environments: any = {};
- ports: string [] = [];
-
- public constructor(init?: Partial<DevService>) {
- Object.assign(this, init);
- }
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/models/SystemModels.ts b/karavan-app/src/main/webui/src/karavan/models/SystemModels.ts
index 326efbf2..a4d1d12a 100644
--- a/karavan-app/src/main/webui/src/karavan/models/SystemModels.ts
+++ b/karavan-app/src/main/webui/src/karavan/models/SystemModels.ts
@@ -1,3 +1,20 @@
+/*
+ * 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.
+ */
+
export class KubernetesSecret {
name: string = '';
data: any = {}
(camel-karavan) 10/33: Front-end Configs for 4.18.0
Posted by ma...@apache.org.
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 c8369132260ccdefba6e1bd3846547e1e436590e
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:24:25 2026 -0500
Front-end Configs for 4.18.0
---
karavan-app/src/main/webui/eslint.config.mjs | 8 +++
karavan-app/src/main/webui/{src => }/index.css | 90 +++++++++++++++++++++++---
karavan-app/src/main/webui/index.tsx | 38 +++++++++++
karavan-app/src/main/webui/package-lock.json | 36 ++++++++++-
karavan-app/src/main/webui/src/index.css | 90 +++++++++++++++++++++++---
5 files changed, 243 insertions(+), 19 deletions(-)
diff --git a/karavan-app/src/main/webui/eslint.config.mjs b/karavan-app/src/main/webui/eslint.config.mjs
new file mode 100644
index 00000000..d0fdedb3
--- /dev/null
+++ b/karavan-app/src/main/webui/eslint.config.mjs
@@ -0,0 +1,8 @@
+// @ts-check
+
+import eslint from '@eslint/js';
+import tseslint from 'typescript-eslint';
+
+export default tseslint.config(
+ eslint.configs.recommended
+);
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/index.css b/karavan-app/src/main/webui/index.css
similarity index 76%
copy from karavan-app/src/main/webui/src/index.css
copy to karavan-app/src/main/webui/index.css
index 1cdde350..70a1cae5 100644
--- a/karavan-app/src/main/webui/src/index.css
+++ b/karavan-app/src/main/webui/index.css
@@ -16,6 +16,7 @@
*/
:root {
+ --pf-t--global--border--radius--300: 10px;
.pf-v6-c-text-input-group__text-input {
--pf-v6-c-text-input-group__text-input--OutlineOffset: -2px;
}
@@ -29,15 +30,53 @@
.pf-v6-c-table.pf-m-compact {
--pf-v6-c-table__thead--cell--FontSize: var(--pf-t--global--font--size--sm);
--pf-v6-c-table--cell--FontSize: var(--pf-v6-c-table__thead--cell--FontSize);
+ /*--pf-v6-c-table--BackgroundColor: transparent;*/
+
+ .pf-v6-c-table__td {
+ --pf-v6-c-table--cell--PaddingInlineStart: var(--pf-t--global--spacer--sm);
+ --pf-v6-c-table--cell--PaddingInlineEnd: var(--pf-t--global--spacer--sm);
+ }
}
.pf-v6-c-form-control > :is(input, select, textarea) {
padding-inline-start: var(--pf-t--global--spacer--sm);
padding-inline-end: var(--pf-t--global--spacer--sm);
}
+
+ .pf-v6-c-form.pf-m-horizontal .pf-v6-c-form__group-label {
+ align-self: center;
+ padding: 0;
+ }
+ --get-color: #61affe;
+ --post-color: #49cc90;
+ --put-color: #fca130;
+ --delete-color: #f93e3e;
+ --patch-color: #ff5ca7;
+ --options-color: #0d5aa7;
+ --head-color: #9012fe;
+ --trace-color: #7f8c8d;
+
+ --pf-t--color--blue--5: #f0f8ff;
+ --pf-t--color--blue--10: #e0f0ff;
+ --pf-t--color--blue--20: #b9dafc;
+ --pf-t--color--blue--30: #92c5f9;
+ --pf-t--color--blue--40: #4394e5;
+ --pf-t--color--blue--50: #0066cc;
+ --pf-t--color--blue--60: #004d99;
+ --pf-t--color--blue--70: #003366;
+ --pf-t--color--blue--75: #022a54;
+ --pf-t--color--blue--80: #032142;
+ --pf-t--color--blue--950: #011021;
}
.karavan {
+ .text-field-with-prefix {
+ align-items: center;
+ gap: 0;
+ .pf-v6-c-text-input-group__text-input {
+ padding-left: 1px;
+ }
+ }
--pf-v6-c-content--MarginBlockEnd: 0;
.pf-v6-c-content--h1,
@@ -81,6 +120,7 @@ html, body, #root {
.karavan .pf-v6-c-button {
padding-inline-start: var(--pf-t--global--spacer--300);
padding-inline-end: var(--pf-t--global--spacer--300);
+ gap: var(--pf-t--global--spacer--xs);
}
.karavan {
@@ -94,6 +134,7 @@ html, body, #root {
padding-inline-start: var(--pf-t--global--spacer--lg);
padding-inline-end: var(--pf-t--global--spacer--sm);
}
+
.pf-v6-c-text-input-group__icon {
inset-inline-start: var(--pf-t--global--spacer--sm);
}
@@ -108,6 +149,7 @@ html, body, #root {
.karavan .pf-v6-c-log-viewer__header {
margin: 0;
}
+
.karavan .pf-v6-c-log-viewer__main {
border: none;
}
@@ -218,6 +260,7 @@ svg.carbon {
transform: rotate(360deg);
}
}
+
@keyframes rotate-icon-backward {
from {
transform: rotate(360deg);
@@ -228,10 +271,20 @@ svg.carbon {
}
@keyframes logline {
- 0% { opacity: 0; transform: translateX(-2px); }
- 20% { opacity: 1; transform: translateX(0); }
- 80% { opacity: 1; }
- 100% { opacity: 0; }
+ 0% {
+ opacity: 0;
+ transform: translateX(-2px);
+ }
+ 20% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ 80% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
}
@keyframes steam-movement {
@@ -253,9 +306,28 @@ svg.carbon {
}
@keyframes steam-opacity {
- 0% { opacity: 0.7; }
- 25% { opacity: 1; }
- 50% { opacity: 0.85; }
- 75% { opacity: 1; }
- 100% { opacity: 0.7; }
+ 0% {
+ opacity: 0.7;
+ }
+ 25% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.85;
+ }
+ 75% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0.7;
+ }
+}
+
+@keyframes heartbeat-pulse {
+ 0% { transform: scale(1); }
+ 14% { transform: scale(1.25); }
+ 28% { transform: scale(1); }
+ 42% { transform: scale(1.25); }
+ 70% { transform: scale(1); }
+ 100% { transform: scale(1); }
}
diff --git a/karavan-app/src/main/webui/index.tsx b/karavan-app/src/main/webui/index.tsx
new file mode 100644
index 00000000..920f0f25
--- /dev/null
+++ b/karavan-app/src/main/webui/index.tsx
@@ -0,0 +1,38 @@
+/*
+ * 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 ReactDOM from 'react-dom/client';
+import "@patternfly/patternfly/patternfly.css";
+import "@patternfly/patternfly/patternfly-charts.css";
+import './index.css';
+import {App} from "@app/App";
+import {BrowserRouter} from "react-router-dom";
+import {ThemeProvider} from "@app/theme/ThemeContext";
+import {AuthProvider} from "@api/auth/AuthProvider";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+ <React.StrictMode>
+ <BrowserRouter>
+ <ThemeProvider>
+ <AuthProvider>
+ <App />
+ </AuthProvider>
+ </ThemeProvider>
+ </BrowserRouter>
+ </React.StrictMode>
+);
diff --git a/karavan-app/src/main/webui/package-lock.json b/karavan-app/src/main/webui/package-lock.json
index 656e9568..d7873994 100644
--- a/karavan-app/src/main/webui/package-lock.json
+++ b/karavan-app/src/main/webui/package-lock.json
@@ -92,6 +92,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -1877,6 +1878,7 @@
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -2346,6 +2348,7 @@
"integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -2367,6 +2370,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
@@ -2444,6 +2448,7 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -2712,6 +2717,7 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2881,6 +2887,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -3464,6 +3471,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -3835,6 +3843,7 @@
"integrity": "sha512-20MV9SUdeN6Jd84xESsKhRly+/vxI+hwvpBMA93s+9dAcjdCuCojn4IqUGS3lvVaqjVYGYHSRMCpeFtF2rQYxQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
@@ -5922,6 +5931,7 @@
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.0.tgz",
"integrity": "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mobx"
@@ -5978,7 +5988,8 @@
"version": "0.52.2",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
"integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/ms": {
"version": "2.1.3",
@@ -6327,6 +6338,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -6339,6 +6351,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -6760,6 +6773,7 @@
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -7046,6 +7060,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7229,6 +7244,7 @@
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
@@ -7349,6 +7365,7 @@
"resolved": "https://registry.npmjs.org/victory-area/-/victory-area-37.3.6.tgz",
"integrity": "sha512-wVC8LKrZJLiSySNuJLRCB449qZTsPiRyzLlNoJwe21y+XA/a2HJbmJSeywmo8P153aX8viKe1H8ygDsTFXQhHw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6",
@@ -7366,6 +7383,7 @@
"resolved": "https://registry.npmjs.org/victory-axis/-/victory-axis-37.3.6.tgz",
"integrity": "sha512-Vi0dZvgmXmnCdoqc49WckeG5cMXnl7FTtqVhXu9JweA9cgCnkZabBd5mRvAjblb3Lo4j0HZCSPKHYWUPW70qZg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7382,6 +7400,7 @@
"resolved": "https://registry.npmjs.org/victory-bar/-/victory-bar-37.3.6.tgz",
"integrity": "sha512-jdATFRWL1LUW/yEpKWx/aId2BiU2o1pPF9+Kh1TFISBduJoI4ZqvZD90H1QK4f/z50PikqiqiDECaKoKM1jfOQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6",
@@ -7399,6 +7418,7 @@
"resolved": "https://registry.npmjs.org/victory-box-plot/-/victory-box-plot-37.3.6.tgz",
"integrity": "sha512-GOucnD63h14ScBuISC/nd1GBTEx6gIZfLE+0P0gyeH1poBKq0trTTvpQDvAMuGR8zICfEETG3ltmUMCwRrFyUg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6",
@@ -7483,6 +7503,7 @@
"resolved": "https://registry.npmjs.org/victory-chart/-/victory-chart-37.3.6.tgz",
"integrity": "sha512-IkPo/W4AJ7bPu902TGER09OseR9ODm+FQAKfOBw4JsdEhZZ7BiG9zgd/25+x0r5EsTLu81CYGQVkBa+ZazcOlA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"react-fast-compare": "^3.2.0",
@@ -7503,6 +7524,7 @@
"resolved": "https://registry.npmjs.org/victory-core/-/victory-core-37.3.6.tgz",
"integrity": "sha512-aFgO6KokxPbUCPznZP5UPhOdI22pMuwDXKDt6eoQOnkVim66Ia+K95TQar2nwVKGYV5j26aKVf/n9blwphGJRw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.21",
"react-fast-compare": "^3.2.0",
@@ -7520,6 +7542,7 @@
"resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-37.3.6.tgz",
"integrity": "sha512-Uf5bFQvqUsXCjqpvBW4LhrdrHkM6dBqxYgub6FCsBb86f84xZQ3vY7jFkg/JfvF0oGKMoWXYYrYLC1sk+fcWVA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-brush-container": "37.3.6",
@@ -7541,6 +7564,7 @@
"resolved": "https://registry.npmjs.org/victory-cursor-container/-/victory-cursor-container-37.3.6.tgz",
"integrity": "sha512-+Oiw57d5nE+iq8As8RvepknzmNtKq1Gsc50u1X3IRd4jXtX8zqZrgXGlVZ+BP/tkLsWnGYVjKulwKBf2oaEUuw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7573,6 +7597,7 @@
"resolved": "https://registry.npmjs.org/victory-group/-/victory-group-37.3.6.tgz",
"integrity": "sha512-kgy/Azl5BxwlJAV0KDPGypv35TMrOD1J2ZxnJW2Wyyq+e8i0GGBIv5MoBzou64BRsDlS9V0CYRIjnkHgrBpB5w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"react-fast-compare": "^3.2.0",
@@ -7610,6 +7635,7 @@
"resolved": "https://registry.npmjs.org/victory-legend/-/victory-legend-37.3.6.tgz",
"integrity": "sha512-vRRrhj3/ENqKVLdaBMzEmR83N6BOjox1bthYT1eJjN2H5SIK35bxn30IkiV/Pz3y627EqZe4TAWaxc0jiJlCiA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7626,6 +7652,7 @@
"resolved": "https://registry.npmjs.org/victory-line/-/victory-line-37.3.6.tgz",
"integrity": "sha512-Ke817uf/qFbN9jU7Dba7CrcHXYO5wAZuKKnyeHJmLDeQeFST0773xejnIuC+dBgZipjFr4KIbSd+VcUafFNE1g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6",
@@ -7643,6 +7670,7 @@
"resolved": "https://registry.npmjs.org/victory-pie/-/victory-pie-37.3.6.tgz",
"integrity": "sha512-tvdgAZ/HQWlo3KDDe0XAVbizHuaNMbgkkiF7zfA7Ww+3bHSs+0P9dsDtK2xP365D8gBCOv8pWmuzvKRhzNbqeA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6",
@@ -7676,6 +7704,7 @@
"resolved": "https://registry.npmjs.org/victory-scatter/-/victory-scatter-37.3.6.tgz",
"integrity": "sha512-fp95zMTPXgW1cmTowzDXhn+KxePMVDrzU0lotsHQMdBV7eB+ioXdu9hORlx4VHmMYg2ihsGwRTF+VAZ7rGxphA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7726,6 +7755,7 @@
"resolved": "https://registry.npmjs.org/victory-stack/-/victory-stack-37.3.6.tgz",
"integrity": "sha512-ldod04RdqGJGH5p5eWXCofdTkbhZqIp3iwW7NpxSbMDLs8zPQIVvDFVtuJgMwQiC5vnIpbhMmxVeFbr8m64ZKA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"react-fast-compare": "^3.2.0",
@@ -7744,6 +7774,7 @@
"resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-37.3.6.tgz",
"integrity": "sha512-vqaJS9noauOqDDBBAV9Ln9duOY/i17h1DCfCPAqhwPFyvFbwKvAub9zPTeYWAm/14VvWX5O/0yekFCVbcC7hjg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7799,6 +7830,7 @@
"resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-37.3.6.tgz",
"integrity": "sha512-qAAG0rMuK7A4EoJ4cyUk5wNdOW+HuCXNKPOko+hYK6wWOYXJvFhiglYyA85a695YyAXECc6JyJS/crm4IOEFag==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"delaunay-find": "0.0.6",
"lodash": "^4.17.19",
@@ -7818,6 +7850,7 @@
"resolved": "https://registry.npmjs.org/victory-zoom-container/-/victory-zoom-container-37.3.6.tgz",
"integrity": "sha512-AGL+k20mI44OL5b0VgIxlmnNSefIoFmbbim5NraPmIxbtns9qQW/56ivIncJcYomBungIx99gUpsEpcQaMNHgQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"lodash": "^4.17.19",
"victory-core": "37.3.6"
@@ -7835,6 +7868,7 @@
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
diff --git a/karavan-app/src/main/webui/src/index.css b/karavan-app/src/main/webui/src/index.css
index 1cdde350..70a1cae5 100644
--- a/karavan-app/src/main/webui/src/index.css
+++ b/karavan-app/src/main/webui/src/index.css
@@ -16,6 +16,7 @@
*/
:root {
+ --pf-t--global--border--radius--300: 10px;
.pf-v6-c-text-input-group__text-input {
--pf-v6-c-text-input-group__text-input--OutlineOffset: -2px;
}
@@ -29,15 +30,53 @@
.pf-v6-c-table.pf-m-compact {
--pf-v6-c-table__thead--cell--FontSize: var(--pf-t--global--font--size--sm);
--pf-v6-c-table--cell--FontSize: var(--pf-v6-c-table__thead--cell--FontSize);
+ /*--pf-v6-c-table--BackgroundColor: transparent;*/
+
+ .pf-v6-c-table__td {
+ --pf-v6-c-table--cell--PaddingInlineStart: var(--pf-t--global--spacer--sm);
+ --pf-v6-c-table--cell--PaddingInlineEnd: var(--pf-t--global--spacer--sm);
+ }
}
.pf-v6-c-form-control > :is(input, select, textarea) {
padding-inline-start: var(--pf-t--global--spacer--sm);
padding-inline-end: var(--pf-t--global--spacer--sm);
}
+
+ .pf-v6-c-form.pf-m-horizontal .pf-v6-c-form__group-label {
+ align-self: center;
+ padding: 0;
+ }
+ --get-color: #61affe;
+ --post-color: #49cc90;
+ --put-color: #fca130;
+ --delete-color: #f93e3e;
+ --patch-color: #ff5ca7;
+ --options-color: #0d5aa7;
+ --head-color: #9012fe;
+ --trace-color: #7f8c8d;
+
+ --pf-t--color--blue--5: #f0f8ff;
+ --pf-t--color--blue--10: #e0f0ff;
+ --pf-t--color--blue--20: #b9dafc;
+ --pf-t--color--blue--30: #92c5f9;
+ --pf-t--color--blue--40: #4394e5;
+ --pf-t--color--blue--50: #0066cc;
+ --pf-t--color--blue--60: #004d99;
+ --pf-t--color--blue--70: #003366;
+ --pf-t--color--blue--75: #022a54;
+ --pf-t--color--blue--80: #032142;
+ --pf-t--color--blue--950: #011021;
}
.karavan {
+ .text-field-with-prefix {
+ align-items: center;
+ gap: 0;
+ .pf-v6-c-text-input-group__text-input {
+ padding-left: 1px;
+ }
+ }
--pf-v6-c-content--MarginBlockEnd: 0;
.pf-v6-c-content--h1,
@@ -81,6 +120,7 @@ html, body, #root {
.karavan .pf-v6-c-button {
padding-inline-start: var(--pf-t--global--spacer--300);
padding-inline-end: var(--pf-t--global--spacer--300);
+ gap: var(--pf-t--global--spacer--xs);
}
.karavan {
@@ -94,6 +134,7 @@ html, body, #root {
padding-inline-start: var(--pf-t--global--spacer--lg);
padding-inline-end: var(--pf-t--global--spacer--sm);
}
+
.pf-v6-c-text-input-group__icon {
inset-inline-start: var(--pf-t--global--spacer--sm);
}
@@ -108,6 +149,7 @@ html, body, #root {
.karavan .pf-v6-c-log-viewer__header {
margin: 0;
}
+
.karavan .pf-v6-c-log-viewer__main {
border: none;
}
@@ -218,6 +260,7 @@ svg.carbon {
transform: rotate(360deg);
}
}
+
@keyframes rotate-icon-backward {
from {
transform: rotate(360deg);
@@ -228,10 +271,20 @@ svg.carbon {
}
@keyframes logline {
- 0% { opacity: 0; transform: translateX(-2px); }
- 20% { opacity: 1; transform: translateX(0); }
- 80% { opacity: 1; }
- 100% { opacity: 0; }
+ 0% {
+ opacity: 0;
+ transform: translateX(-2px);
+ }
+ 20% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ 80% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
}
@keyframes steam-movement {
@@ -253,9 +306,28 @@ svg.carbon {
}
@keyframes steam-opacity {
- 0% { opacity: 0.7; }
- 25% { opacity: 1; }
- 50% { opacity: 0.85; }
- 75% { opacity: 1; }
- 100% { opacity: 0.7; }
+ 0% {
+ opacity: 0.7;
+ }
+ 25% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.85;
+ }
+ 75% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0.7;
+ }
+}
+
+@keyframes heartbeat-pulse {
+ 0% { transform: scale(1); }
+ 14% { transform: scale(1.25); }
+ 28% { transform: scale(1); }
+ 42% { transform: scale(1.25); }
+ 70% { transform: scale(1); }
+ 100% { transform: scale(1); }
}
(camel-karavan) 25/33: Front-end Project for 4.18.0
Posted by ma...@apache.org.
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 cabd7e6dbe1254ee2c0390a7a94be4264c322d8b
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:49:49 2026 -0500
Front-end Project for 4.18.0
---
.../features/project/files/FilesToolbar.tsx | 23 +---------------------
.../karavan/features/project/files/SourcesTab.tsx | 11 +++--------
2 files changed, 4 insertions(+), 30 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/files/FilesToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/files/FilesToolbar.tsx
index 683eb4d0..8232e330 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/files/FilesToolbar.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/files/FilesToolbar.tsx
@@ -18,7 +18,6 @@ import React, {useEffect, useState} from 'react';
import {
Alert,
Button,
- capitalize,
ClipboardCopy,
Content,
Form,
@@ -31,8 +30,6 @@ import {
ModalHeader,
ModalVariant,
TextInput,
- ToggleGroup,
- ToggleGroupItem,
Tooltip,
TooltipPosition
} from '@patternfly/react-core';
@@ -59,7 +56,7 @@ export function FilesToolbar() {
const [commitMessage, setCommitMessage] = useState('');
const isDev = config.environment === 'dev';
const timeAgo = new TimeAgo('en-US');
- const [diff, selectedFileNames, selector, setSelector] = useFilesStore((s) => [s.diff, s.selectedFileNames, s.selector, s.setSelector], shallow);
+ const [diff, selectedFileNames] = useFilesStore((s) => [s.diff, s.selectedFileNames], shallow);
const projectCommited = projectsCommited?.find(p => project.projectId);
@@ -171,23 +168,6 @@ export function FilesToolbar() {
)
}
- const toggle =
- <ToggleGroup aria-label="Source Toggle">
- {['files', 'commits'].map(value => {
- return (
- <ToggleGroupItem
- text={capitalize(value)}
- key={value}
- buttonId={value}
- isSelected={selector === value}
- onChange={(_, selected) => {
- if (selected) setSelector(value as 'files' | 'commits');
- }}
- />
- )
- })}
- </ToggleGroup>
-
function onRefresh() {
ProjectService.refreshProjectFiles(project.projectId);
@@ -199,7 +179,6 @@ export function FilesToolbar() {
return (
<div className="project-files-toolbar">
<ProjectTitle/>
- {toggle}
<Button icon={<RefreshIcon/>}
variant={"link"}
onClick={() => onRefresh()}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.tsx
index a332e8ae..2b47a496 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/files/SourcesTab.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect} from 'react';
+import React from 'react';
import {ProjectFile} from "@models/ProjectModels";
import {FilesToolbar} from "@features/project/files/FilesToolbar";
import {FilesSubTab} from "@features/project/files/FilesSubTab";
@@ -15,14 +15,9 @@ interface SourcesTabProps {
export function SourcesTab(props: SourcesTabProps) {
- const [selector, setSelector, showSideBar] = useFilesStore((s) => [s.selector, s.setSelector, s.showSideBar], shallow);
-
- useEffect(() => {
- return () => setSelector('files');
- }, []);
+ const [showSideBar] = useFilesStore((s) => [s.showSideBar], shallow);
return (
-
<Drawer isExpanded={showSideBar !== null} position="end" onExpand={_ => {
}}>
<DrawerContent panelContent={<SourcesDrawerPanel/>}>
@@ -30,7 +25,7 @@ export function SourcesTab(props: SourcesTabProps) {
<ErrorBoundaryWrapper onError={error => console.error(error)}>
<div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
<FilesToolbar/>
- {selector === 'files' && <FilesSubTab sortFiles={props.sortFiles}/>}
+ <FilesSubTab sortFiles={props.sortFiles}/>
</div>
</ErrorBoundaryWrapper>
</DrawerContentBody>
(camel-karavan) 18/33: Front-end Project Designr and Developer for 4.18.0
Posted by ma...@apache.org.
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 aeb8cc830a5b7d601d118ba9e185526181e94269
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:01:38 2026 -0500
Front-end Project Designr and Developer for 4.18.0
---
.../features/project/beans/BeanFilesDropdown.tsx | 78 +
.../karavan/features/project/beans/BeanWizard.tsx | 241 +++
.../karavan/features/project/designer/CodeStore.ts | 14 +
.../features/project/designer/DesignerStore.ts | 386 +++++
.../project/designer/ErrorBoundaryWrapper.tsx | 35 +
.../features/project/designer/KaravanDesigner.css | 33 +
.../features/project/designer/KaravanDesigner.tsx | 207 +++
.../project/designer/KaravanDesignerViewSwitch.tsx | 45 +
.../features/project/designer/beans/BeanCard.tsx | 61 +
.../project/designer/beans/BeansDesigner.tsx | 115 ++
.../features/project/designer/beans/bean.css | 102 ++
.../project/designer/editor/CodeEditor.tsx | 69 +
.../project/designer/icons/ComponentIcons.tsx | 1833 ++++++++++++++++++++
.../features/project/designer/icons/EipIcons.tsx | 293 ++++
.../project/designer/icons/KaravanIcons.tsx | 721 ++++++++
.../features/project/designer/icons/OtherIcons.tsx | 36 +
.../designer/kamelet/KameletAnnotationsPanel.tsx | 84 +
.../kamelet/KameletDefinitionPropertyCard.tsx | 299 ++++
.../designer/kamelet/KameletDefinitionsPanel.tsx | 126 ++
.../designer/kamelet/KameletDependenciesCard.tsx | 105 ++
.../project/designer/kamelet/KameletDesigner.tsx | 36 +
.../project/designer/kamelet/KameletInput.tsx | 139 ++
.../designer/kamelet/KameletTypesOutCard.tsx | 105 ++
.../features/project/designer/kamelet/kamelet.css | 48 +
.../karavan/features/project/designer/karavan.css | 456 +++++
.../project/designer/property/DslProperties.css | 406 +++++
.../project/designer/property/DslProperties.tsx | 268 +++
.../designer/property/MainPropertiesPanel.tsx | 60 +
.../project/designer/property/PropertiesHeader.tsx | 358 ++++
.../project/designer/property/PropertyStore.ts | 50 +
.../property/expression/ExpressionBottomPanel.tsx | 80 +
.../property/expression/ExpressionContextModel.tsx | 193 +++
.../property/expression/ExpressionEditor.css | 75 +
.../property/expression/ExpressionEditor.tsx | 77 +
.../designer/property/property/BeanProperties.css | 39 +
.../designer/property/property/BeanProperties.tsx | 345 ++++
.../property/property/ComponentPropertyField.css | 47 +
.../property/property/ComponentPropertyField.tsx | 513 ++++++
.../property/ConfigurationSelectorModal.css | 19 +
.../property/ConfigurationSelectorModal.tsx | 366 ++++
.../designer/property/property/DataFormatField.tsx | 161 ++
.../property/property/DslPropertyField.css | 55 +
.../property/property/DslPropertyField.tsx | 1057 +++++++++++
.../property/property/DslPropertyFieldSelect.tsx | 81 +
.../property/DslPropertyFieldSelectScrollable.tsx | 126 ++
.../designer/property/property/ExpressionField.tsx | 182 ++
.../property/property/FileReferenceDropdown.css | 48 +
.../property/property/FileReferenceDropdown.tsx | 293 ++++
.../property/property/KameletPropertyField.css | 47 +
.../property/property/KameletPropertyField.tsx | 293 ++++
.../designer/property/property/ObjectField.tsx | 89 +
.../property/PropertyPlaceholderDropdown.css | 42 +
.../property/PropertyPlaceholderDropdown.tsx | 196 +++
.../designer/property/property/PropertyUtil.tsx | 42 +
.../property/property/VariablesDropdown.css | 37 +
.../property/property/VariablesDropdown.tsx | 301 ++++
.../designer/property/usePropertiesHook.tsx | 246 +++
.../features/project/designer/rest/RestCard.tsx | 109 ++
.../designer/rest/RestConfigurationCard.tsx | 60 +
.../project/designer/rest/RestDesigner.tsx | 225 +++
.../project/designer/rest/RestMethodCard.tsx | 68 +
.../project/designer/rest/RestMethodSelector.tsx | 68 +
.../features/project/designer/rest/rest.css | 286 +++
.../project/designer/route/DeleteConfirmation.tsx | 48 +
.../project/designer/route/DslConnections.css | 124 ++
.../project/designer/route/DslConnections.tsx | 509 ++++++
.../project/designer/route/RouteDesigner.css | 164 ++
.../project/designer/route/RouteDesigner.tsx | 195 +++
.../project/designer/route/element/DslElement.css | 322 ++++
.../project/designer/route/element/DslElement.tsx | 330 ++++
.../designer/route/element/DslElementHeader.tsx | 449 +++++
.../designer/route/element/DslElementMoveModal.tsx | 89 +
.../route/element/RouteTemplateElement.css | 52 +
.../route/element/RouteTemplateElement.tsx | 106 ++
.../project/designer/route/useResizeObserver.tsx | 40 +
.../designer/route/useRouteDesignerHook.tsx | 386 +++++
.../features/project/designer/selector/DslCard.tsx | 110 ++
.../project/designer/selector/DslFastCard.tsx | 59 +
.../project/designer/selector/DslPreferences.tsx | 89 +
.../project/designer/selector/DslSelector.css | 218 +++
.../project/designer/selector/DslSelector.tsx | 426 +++++
.../designer/utils/CamelDefaultStepProperty.tsx | 38 +
.../features/project/designer/utils/CamelUi.tsx | 1056 +++++++++++
.../project/designer/utils/DslMetaModel.ts | 83 +
.../project/designer/utils/ElementIcon.css | 40 +
.../project/designer/utils/ElementIcons.tsx | 118 ++
.../features/project/designer/utils/EventBus.ts | 126 ++
.../project/designer/utils/InfrastructureAPI.ts | 71 +
.../project/designer/utils/IntegrationHeader.tsx | 44 +
.../features/project/designer/utils/MediaTypes.ts | 1525 ++++++++++++++++
.../project/designer/utils/Notification.tsx | 56 +
.../project/designer/utils/ValidatorUtils.ts | 87 +
.../features/project/developer/CodeEditor.tsx | 63 +
.../features/project/developer/DataEditor.css | 39 +
.../features/project/developer/DesignerEditor.tsx | 134 ++
.../features/project/developer/DeveloperEditor.tsx | 64 +
.../project/developer/DeveloperManager.css | 183 ++
.../project/developer/DeveloperManager.tsx | 95 +
.../project/developer/DeveloperToolbar.tsx | 36 +
.../features/project/developer/EditorConfig.ts | 42 +
.../developer/EditorErrorBoundaryWrapper.tsx | 82 +
.../project/developer/EditorOverlayWidget.css | 12 +
.../project/developer/EditorOverlayWidget.tsx | 45 +
.../features/project/developer/EditorToolbar.tsx | 74 +
.../features/project/developer/MarkdownEditor.tsx | 72 +
.../project/developer/MonacoEditorWrapper.tsx | 215 +++
.../developer/MonacoEditorWrapperStateless.tsx | 113 ++
.../features/project/files/CreateFileModal.tsx | 128 ++
.../features/project/files/CreateProjectModal.tsx | 185 ++
.../features/project/files/DeleteFileModal.tsx | 67 +
.../features/project/files/DiffFileModal.css | 20 +
.../features/project/files/DiffFileModal.tsx | 136 ++
.../features/project/files/FileCopyForEnvModal.tsx | 79 +
.../karavan/features/project/files/FilesSubTab.tsx | 408 +++++
.../karavan/features/project/files/FilesTab.tsx | 476 +++++
.../features/project/files/FilesTabUtils.tsx | 119 ++
.../features/project/files/FilesToolbar.tsx | 265 +++
.../features/project/files/SourcesDrawerPanel.tsx | 19 +
.../karavan/features/project/files/SourcesTab.css | 22 +
.../karavan/features/project/files/SourcesTab.tsx | 40 +
.../features/project/files/UploadFileModal.tsx | 159 ++
121 files changed, 23027 insertions(+)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanFilesDropdown.tsx b/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanFilesDropdown.tsx
new file mode 100644
index 00000000..11abdffe
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanFilesDropdown.tsx
@@ -0,0 +1,78 @@
+/*
+ * 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, {useState} from 'react';
+import {Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement} from '@patternfly/react-core';
+import {shallow} from "zustand/shallow";
+import EllipsisVIcon from "@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon";
+import {useFilesStore} from "@stores/ProjectStore";
+
+const CAMEL_YAML_EXT = ".camel.yaml";
+
+interface Props {
+ onSelect: (filename: string, event?: React.MouseEvent<Element, MouseEvent>) => void;
+}
+
+export function BeanFilesDropdown(props: Props) {
+
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [isOpenDropdown, setIsOpenDropdown] = useState<boolean>(false);
+
+ function onMenuToggleClick() {
+ setIsOpenDropdown(!isOpenDropdown)
+ }
+
+ function getToggle(toggleRef: React.Ref<MenuToggleElement>) {
+ return (
+ <MenuToggle className="bean-wizard-toggle"
+ id={'popoverId'}
+ ref={toggleRef}
+ aria-label="placeholder menu"
+ variant="default"
+ onClick={() => onMenuToggleClick()}
+ isExpanded={isOpenDropdown}
+ >
+ <EllipsisVIcon/>
+ </MenuToggle>
+ )
+ }
+
+ const camelYamlFiles = files.filter(f => f.name.endsWith(CAMEL_YAML_EXT)).map(f => f.name);
+
+ return (
+ (files && files.length > 0 ) ?
+ <Dropdown
+ popperProps={{position: "end"}}
+ isOpen={isOpenDropdown}
+ onSelect={(e, value) => {
+ if (value) {
+ props.onSelect(value?.toString().replace(CAMEL_YAML_EXT, ''), e);
+ }
+ setIsOpenDropdown(false);
+ }}
+ onOpenChange={(isOpen: boolean) => setIsOpenDropdown(isOpen)}
+ toggle={(toggleRef: React.Ref<MenuToggleElement>) => getToggle(toggleRef)}
+ shouldFocusToggleOnSelect
+ >
+ <DropdownList>
+ {camelYamlFiles.map((pp, index) =>
+ <DropdownItem value={pp} key={index}>{pp}</DropdownItem>
+ )}
+ </DropdownList>
+ </Dropdown>
+ : <></>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanWizard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanWizard.tsx
new file mode 100644
index 00000000..39728a00
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/beans/BeanWizard.tsx
@@ -0,0 +1,241 @@
+/*
+ * 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, {useEffect, useMemo, useState} from 'react';
+import {
+ Alert,
+ capitalize,
+ Content,
+ Flex,
+ Form,
+ FormAlert,
+ FormGroup,
+ InputGroup,
+ InputGroupItem,
+ Modal,
+ ModalBody,
+ ModalHeader,
+ ModalVariant,
+ Radio,
+ TextInput,
+ Wizard,
+ WizardStep
+} from '@patternfly/react-core';
+import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
+import {CodeUtils} from "@util/CodeUtils";
+import {ProjectFile} from "@models/ProjectModels";
+import {useFilesStore, useFileStore, useProjectStore, useWizardStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ProjectService} from "@services/ProjectService";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {Integration} from "@karavan-core/model/IntegrationDefinition";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {BeanFilesDropdown} from "./BeanFilesDropdown";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {useTemplatesStore} from "@stores/SettingsStore";
+import {KaravanApi} from "@api/KaravanApi";
+import {KARAVAN_DOT_EXTENSION, WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX} from "@karavan-core/contants";
+
+const EMPTY_BEAN = "empty";
+
+export function BeanWizard() {
+
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const [setFile, designerTab] = useFileStore((s) => [s.setFile, s.designerTab], shallow);
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [showWizard, setShowWizard] = useWizardStore((s) => [s.showWizard, s.setShowWizard], shallow)
+ const [templateNames, setTemplateNames] = useState<string[]>([]);
+ const [templateName, setTemplateName] = useState<string>('');
+ const [templateBeanName, setTemplateBeanName] = useState<string>('');
+ const [bean, setBean] = useState<BeanFactoryDefinition | undefined>();
+ const [filename, setFilename] = useState<string>('');
+ const [backendError, setBackendError] = React.useState<string>();
+
+ const templateFiles = useTemplatesStore(s => s.templateFiles);
+ const fetchTemplateFiles = useTemplatesStore(s => s.fetchTemplateFiles);
+
+
+ useEffect(() => {
+ if (showWizard) {
+ setBackendError(undefined);
+ setFilename('')
+ setTemplateName('');
+ setTemplateBeanName('');
+ setBean(undefined);
+ fetchTemplateFiles();
+ }
+ }, [showWizard]);
+
+ useEffect(() => {
+ const templateNames = templateFiles.filter(f => f.name.startsWith(WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX))
+ .map(file => file.name.replace(WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX, '').replace(KARAVAN_DOT_EXTENSION.CAMEL_YAML, ''));
+ setTemplateNames([...templateNames]);
+ }, [templateFiles]);
+
+ useEffect(() => {
+ getBeans.filter(b => b.name === templateBeanName).forEach(b => {
+ setBean(new BeanFactoryDefinition({...b}))
+ });
+ }, [templateBeanName]);
+
+
+ function handleOnFormSubmitSuccess(file: ProjectFile) {
+ const message = "File successfully created.";
+ EventBus.sendAlert("Success", message, "success");
+ ProjectService.refreshProjectData(file.projectId);
+ setFile('select', file, designerTab);
+ setShowWizard(false);
+ }
+
+ function handleFormSubmit() {
+ const file = files.filter(f=> f.name === (filename + KARAVAN_DOT_EXTENSION.CAMEL_YAML)).at(0);
+ if (file && bean !== undefined) {
+ const i = CamelDefinitionYaml.yamlToIntegration(file.name, file.code);
+ const i2 = CamelDefinitionApiExt.addBeanToIntegration(i, bean);
+ const file2 = {...file} as ProjectFile;
+ file2.code = CamelDefinitionYaml.integrationToYaml(i2);
+ ProjectService.updateFile(file2, false);
+ handleOnFormSubmitSuccess(file2);
+ } else {
+ let code = '{}';
+ if (bean !== undefined && templateName !== EMPTY_BEAN) {
+ const i = Integration.createNew("temp");
+ const i2 = CamelDefinitionApiExt.addBeanToIntegration(i, bean);
+ code = CamelDefinitionYaml.integrationToYaml(i2);
+ }
+ const fullFileName = filename + KARAVAN_DOT_EXTENSION.CAMEL_YAML;
+ const file = new ProjectFile(fullFileName, project.projectId, code, Date.now());
+ KaravanApi.saveProjectFile(file, (result, file) => {
+ if (result) {
+ handleOnFormSubmitSuccess(file);
+ } else {
+ setBackendError(file?.response?.data);
+ }
+ })
+ }
+ }
+
+ function getBeanFactoryDefinitions(): BeanFactoryDefinition[] {
+ const fs = templateFiles.filter(f => f.name === WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX.concat(templateName).concat(KARAVAN_DOT_EXTENSION.CAMEL_YAML));
+ return CodeUtils.getBeans(fs);
+ }
+
+ const getBeans = useMemo(() => getBeanFactoryDefinitions(), [templateName]);
+
+ return (
+ <Modal onClose={_ => setShowWizard(false)}
+ variant={ModalVariant.medium} isOpen={showWizard} onEscapePress={() => setShowWizard(false)}>
+ <ModalHeader title="Bean Wizard"/>
+ <ModalBody>
+ <Wizard className="bean-wizard" height={600} onClose={() => setShowWizard(false)} onSubmit={event => handleFormSubmit()}>
+ <WizardStep name={"Type"} id="type"
+ footer={{isNextDisabled: !templateNames.includes(templateName) && templateName !== EMPTY_BEAN}}
+ >
+ <Flex direction={{default: "column"}} gap={{default: 'gapLg'}}>
+ <Radio key={EMPTY_BEAN} id={EMPTY_BEAN} label={capitalize(EMPTY_BEAN)} name={EMPTY_BEAN}
+ isChecked={EMPTY_BEAN === templateName} onChange={_ => setTemplateName(EMPTY_BEAN)}/>
+ {templateNames.map(n => <Radio key={n} id={n} label={capitalize(n)} name={n}
+ isChecked={n === templateName}
+ onChange={_ => setTemplateName(n)}/>)}
+ </Flex>
+ </WizardStep>
+ <WizardStep name={"Template"} id="template"
+ isHidden={templateName === EMPTY_BEAN}
+ isDisabled={templateName.length === 0}
+ footer={{isNextDisabled: !getBeans.map(b => b.name).includes(templateBeanName)}}
+ >
+ <Flex direction={{default: "column"}} gap={{default: 'gapLg'}}>
+ {getBeans.map(b => <Radio key={b.name} id={b.name} label={b.name} name={b.name}
+ isChecked={b.name === templateBeanName}
+ onChange={_ => setTemplateBeanName(b.name)}/>)}
+ </Flex>
+ </WizardStep>
+ <WizardStep name="Properties" id="properties"
+ isHidden={templateName === EMPTY_BEAN}
+ isDisabled={templateName.length == 0 || templateBeanName.length == 0}
+ >
+ <Form autoComplete="off">
+ <FormGroup key={"beanName"} label={"Name"} fieldId={"beanName"}>
+ <TextInput
+ value={bean?.name}
+ id={"beanName"}
+ aria-describedby={'beanName'}
+ onChange={(_, value) => {
+ const b = new BeanFactoryDefinition({...bean});
+ b.name = value;
+ setBean(b);
+ }}
+ />
+ </FormGroup>
+ <FormGroup label="Properties:" fieldId="properties"/>
+ {getBeans.filter(b => b.name === templateBeanName).map(b => (
+ <div key={b.name}>
+ {Object.getOwnPropertyNames(b.properties).map(prop => (
+ <FormGroup key={prop} label={prop} fieldId={prop}>
+ <TextInput
+ value={bean?.properties[prop] || ''}
+ id={prop}
+ aria-describedby={prop}
+ onChange={(_, value) => {
+ const b = new BeanFactoryDefinition({...bean});
+ b.properties[prop] = value;
+ setBean(b);
+ }}
+ />
+ </FormGroup>
+ ))}
+ </div>
+ ))}
+ </Form>
+ </WizardStep>
+ <WizardStep name={"File"} id={"file"}
+ footer={{nextButtonText: 'Save', onNext: event => handleFormSubmit()}}
+ isDisabled={(templateName.length === 0 || templateBeanName.length === 0) && templateName !== EMPTY_BEAN}
+ >
+ <Form autoComplete="off">
+ <FormGroup label="Filename" fieldId="filename" isRequired>
+ <InputGroup>
+ <InputGroupItem isFill>
+ <TextInput className="text-field" type="text" id="filename"
+ aria-label="filename"
+ value={filename}
+ customIcon={<Content component="p">{KARAVAN_DOT_EXTENSION.CAMEL_YAML}</Content>}
+ onChange={(e, value) => {
+ setFilename(value);
+ }}
+ />
+ </InputGroupItem>
+ {templateName !== EMPTY_BEAN && <InputGroupItem>
+ <BeanFilesDropdown
+ onSelect={(fn, event) => {
+ setFilename(fn);
+ }}
+ />
+ </InputGroupItem>}
+ </InputGroup>
+ {backendError &&
+ <FormAlert>
+ <Alert variant="danger" title={backendError} aria-live="polite" isInline/>
+ </FormAlert>
+ }
+ </FormGroup>
+ </Form>
+ </WizardStep>
+ </Wizard>
+ </ModalBody>
+ </Modal>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/CodeStore.ts b/karavan-app/src/main/webui/src/karavan/features/project/designer/CodeStore.ts
new file mode 100644
index 00000000..78e88133
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/CodeStore.ts
@@ -0,0 +1,14 @@
+import {createWithEqualityFn} from "zustand/traditional";
+import {shallow} from "zustand/shallow";
+
+interface CodeState {
+ code: string;
+ setCode: (code: string) => void;
+}
+
+export const useCodeStore = createWithEqualityFn<CodeState>((set) => ({
+ code: '',
+ setCode: (code: string) => {
+ set({code: code});
+ },
+}), shallow)
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/DesignerStore.ts b/karavan-app/src/main/webui/src/karavan/features/project/designer/DesignerStore.ts
new file mode 100644
index 00000000..335a4bc5
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/DesignerStore.ts
@@ -0,0 +1,386 @@
+/*
+ * 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 {CamelElement, Integration, IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
+import {DslPosition, EventBus} from "./utils/EventBus";
+import {createWithEqualityFn} from "zustand/traditional";
+import {shallow} from "zustand/shallow";
+import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
+import {DslMetaModel} from "@features/project/designer/utils/DslMetaModel";
+
+interface IntegrationState {
+ integration: Integration;
+ json: string;
+ setIntegration: (integration: Integration, propertyOnly: boolean) => void;
+ propertyOnly: boolean;
+ reset: () => void;
+ files: IntegrationFile []
+ setFiles: (files: IntegrationFile []) => void
+ resetFiles: (files: IntegrationFile []) => void
+ variables: string[],
+ setVariables: (variables: string[]) => void;
+ key: string;
+ setKey: (key: string) => void;
+}
+
+export const useIntegrationStore = createWithEqualityFn<IntegrationState>((set, get) => ({
+ integration: Integration.createNew("demo", "plain"),
+ propertyOnly: false,
+ json: '{}',
+ key: '',
+ setIntegration: (integration: Integration, propertyOnly: boolean) => {
+ set((state: IntegrationState) => {
+ const json = JSON.stringify(integration);
+ if (state.json === json) {
+ return {integration: state.integration, propertyOnly: state.propertyOnly, json: state.json};
+ } else {
+ EventBus.sendIntegrationUpdate(integration, propertyOnly);
+ return {integration: integration, propertyOnly: propertyOnly, json: json};
+ }
+ })
+ },
+ reset: () => {
+ set({integration: Integration.createNew("demo", "plain"), json: '{}', propertyOnly: false});
+ },
+ files: [],
+ setFiles: (files: IntegrationFile []) => {
+ set((state: IntegrationState) => {
+ return {files: files};
+ });
+ },
+ resetFiles: (files: IntegrationFile []) => {
+ set((state: IntegrationState) => {
+ return {files: [...files]};
+ });
+ },
+ variables: [],
+ setVariables: (variables: string[]) => {
+ set((state: IntegrationState) => {
+ return {variables: [...variables]};
+ })
+ },
+ setKey: (key: string) => {
+ set({key: key});
+ },
+}), shallow)
+
+
+interface SelectorStateState {
+ showSelector: boolean;
+ setShowSelector: (showSelector: boolean) => void;
+ showProperties: boolean;
+ setShowProperties: (showProperties: boolean) => void;
+ selectedDsl?: DslMetaModel;
+ setSelectedDsl: (selectedDsl?: DslMetaModel) => void;
+ showSteps: boolean;
+ setShowSteps: (showSteps: boolean) => void;
+ parentDsl?: string;
+ setParentDsl: (parentDsl?: string) => void;
+ parentId: string;
+ setParentId: (parentId: string) => void;
+ selectorTabIndex?: string | number
+ setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
+ selectedPosition?: number;
+ setSelectedPosition: (selectedPosition?: number) => void;
+ selectedToggles: string [];
+ addSelectedToggle: (label: string) => void;
+ deleteSelectedToggle: (label: string) => void;
+ routeId?: string;
+ setRouteId: (routeId: string) => void;
+ isRouteTemplate?: boolean;
+ setIsRouteTemplate: (isRouteTemplate: boolean) => void;
+}
+
+export const useSelectorStore = createWithEqualityFn<SelectorStateState>((set) => ({
+ showSelector: false,
+ showProperties: false,
+ deleteMessage: '',
+ parentId: '',
+ showSteps: true,
+ isRouteTemplate: false,
+ selectedToggles: ['eip', 'components', 'kamelets'],
+ addSelectedToggle: (toggle: string) => {
+ set(state => ({
+ selectedToggles: [...state.selectedToggles, toggle]
+ }))
+ },
+ deleteSelectedToggle: (toggle: string) => {
+ set(state => ({
+ selectedToggles: [...state.selectedToggles.filter(x => x !== toggle)]
+ }))
+ },
+ setSelectorTabIndex: (selectorTabIndex?: string | number) => {
+ set({selectorTabIndex: selectorTabIndex})
+ },
+ setParentDsl: (parentDsl?: string) => {
+ set({parentDsl: parentDsl})
+ },
+ setSelectedDsl: (selectedDsl?: DslMetaModel) => {
+ set(state => ({
+ selectedDsl: selectedDsl,
+ showProperties: selectedDsl ? state.showProperties : false
+ }))
+ },
+ setShowSelector: (showSelector: boolean) => {
+ set({showSelector: showSelector})
+ },
+ setShowProperties: (showProperties: boolean) => {
+ set({showProperties: showProperties})
+ },
+ setShowSteps: (showSteps: boolean) => {
+ set({showSteps: showSteps})
+ },
+ setParentId: (parentId: string) => {
+ set({parentId: parentId})
+ },
+ setSelectedPosition: (selectedPosition?: number) => {
+ set({selectedPosition: selectedPosition})
+ },
+ setRouteId: (routeId: string) => {
+ set({routeId: routeId})
+ },
+ setIsRouteTemplate: (isRouteTemplate: boolean) => {
+ set({isRouteTemplate: isRouteTemplate})
+ },
+}), shallow)
+
+
+interface ConnectionsState {
+ steps: Map<string, DslPosition>;
+ addStep: (uuid: string, position: DslPosition) => void;
+ deleteStep: (uuid: string) => void;
+ clearSteps: () => void;
+ setSteps: (steps: Map<string, DslPosition>) => void;
+}
+
+export const useConnectionsStore = createWithEqualityFn<ConnectionsState>((set) => ({
+ steps: new Map<string, DslPosition>(),
+ addStep: (uuid: string, position: DslPosition) => {
+ set(state => ({
+ steps: new Map(state.steps).set(uuid, position),
+ }))
+ },
+ deleteStep: (uuid: string) => {
+ set((state: ConnectionsState) => {
+ // state.steps.clear();
+ Array.from(state.steps.entries())
+ .filter(value => value[1]?.parent?.uuid !== uuid)
+ .filter(value => value[1]?.prevStep?.uuid !== uuid)
+ .filter(value => value[1]?.nextstep?.uuid !== uuid)
+ .forEach(value => state.steps.set(value[0], value[1]));
+ state.steps.delete(uuid)
+ return state;
+ })
+ },
+ clearSteps: () => {
+ set((state: ConnectionsState) => {
+ state.steps.clear();
+ return state;
+ })
+ },
+ setSteps: (steps: Map<string, DslPosition>) => {
+ set({steps: steps})
+ }
+}), shallow)
+
+
+export const DesignerViewSwitchOptions = ["routes", "rest", "beans", "kamelet"] as const;
+export type DesignerViewSwitchOption = typeof DesignerViewSwitchOptions[number];
+
+type DesignerState = {
+ designerSwitch: boolean
+ isDebugging: boolean
+ notificationBadge: boolean
+ notificationMessage: [string, string]
+ shiftKeyPressed: boolean
+ showDeleteConfirmation: boolean
+ showMoveConfirmation: boolean
+ deleteMessage: string
+ selectedStep?: CamelElement
+ selectedUuids: string[]
+ passedNodeIds: string[]
+ passedRouteId?: string
+ failedRouteId?: string
+ suspendedNodeId?: string
+ failed: boolean
+ clipboardSteps: CamelElement[]
+ width: number
+ height: number
+ top: number
+ left: number
+ moveElements: [string | undefined, string | undefined]
+ propertyPlaceholders: [string, string][]
+ parameterPlaceholders: [string, string][], // route template parameters
+ beans: BeanFactoryDefinition[],
+ tab?: DesignerViewSwitchOption,
+ stepDoubleClicked: boolean,
+}
+
+const designerState: DesignerState = {
+ designerSwitch: true,
+ isDebugging: false,
+ notificationBadge: false,
+ notificationMessage: ['', ''],
+ shiftKeyPressed: false,
+ showDeleteConfirmation: false,
+ showMoveConfirmation: false,
+ deleteMessage: '',
+ selectedUuids: [],
+ passedNodeIds: [],
+ passedRouteId: undefined,
+ failedRouteId: undefined,
+ suspendedNodeId: undefined,
+ failed: false,
+ clipboardSteps: [],
+ width: 0,
+ height: 0,
+ top: 0,
+ left: 0,
+ moveElements: [undefined, undefined],
+ propertyPlaceholders: [],
+ parameterPlaceholders: [],
+ beans: [],
+ stepDoubleClicked: false,
+};
+
+type DesignerAction = {
+ setDebugging: (isDebugging: boolean) => void;
+ setShiftKeyPressed: (shiftKeyPressed: boolean) => void;
+ setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => void;
+ setShowMoveConfirmation: (showMoveConfirmation: boolean) => void;
+ setDeleteMessage: (deleteMessage: string) => void;
+ setSelectedStep: (selectedStep?: CamelElement) => void;
+ setSelectedUuids: (selectedUuids: string[]) => void;
+ setPassedNodeIds: (passedNodeIds: string[]) => void;
+ setPassedRouteId: (passedRouteId?: string) => void;
+ setFailedRouteId: (failedRouteId?: string) => void;
+ setSuspendedNodeId: (suspendedNodeId?: string) => void;
+ setFailed: (failed: boolean) => void;
+ setClipboardSteps: (clipboardSteps: CamelElement[]) => void;
+ setPosition: (width: number, height: number, top: number, left: number) => void;
+ reset: () => void;
+ setNotification: (notificationBadge: boolean, notificationMessage: [string, string]) => void;
+ setMoveElements: (moveElements: [string | undefined, string | undefined]) => void;
+ setPropertyPlaceholders: (propertyPlaceholders: [string, string][]) => void;
+ setParameterPlaceholders: (parameterPlaceholders: [string, string][]) => void;
+ setBeans: (beans: BeanFactoryDefinition[]) => void;
+ setTab: (tab?: DesignerViewSwitchOption) => void;
+ setDesignerSwitch: (designerSwitch: boolean) => void;
+ setStepDoubleClicked: (stepDoubleClicked: boolean) => void;
+}
+
+export const useDesignerStore = createWithEqualityFn<DesignerState & DesignerAction>((set) => ({
+ ...designerState,
+ setDebugging: (isDebugging: boolean) => {
+ set({isDebugging: isDebugging})
+ },
+ setFailed: (failed: boolean) => {
+ set({failed: failed})
+ },
+ setShiftKeyPressed: (shiftKeyPressed: boolean) => {
+ set({shiftKeyPressed: shiftKeyPressed})
+ },
+ setSelectedStep: (selectedStep?: CamelElement) => {
+ set({selectedStep: selectedStep})
+ },
+ setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => {
+ set({showDeleteConfirmation: showDeleteConfirmation})
+ },
+ setShowMoveConfirmation: (showMoveConfirmation: boolean) => {
+ set({showMoveConfirmation: showMoveConfirmation})
+ },
+ setDeleteMessage: (deleteMessage: string) => {
+ set({deleteMessage: deleteMessage})
+ },
+ setSelectedUuids: (selectedUuids: string[]) => {
+ set((state: DesignerState) => {
+ state.selectedUuids.length = 0;
+ state.selectedUuids.push(...selectedUuids);
+ return state;
+ })
+ },
+ setPassedNodeIds: (passedNodeIds: string[]) => {
+ set((state: DesignerState) => {
+ state.passedNodeIds.length = 0;
+ state.passedNodeIds.push(...passedNodeIds);
+ return state;
+ })
+ },
+ setPassedRouteId: (passedRouteId?: string) => {
+ set({passedRouteId: passedRouteId})
+ },
+ setFailedRouteId: (failedRouteId?: string) => {
+ set({failedRouteId: failedRouteId})
+ },
+ setSuspendedNodeId: (suspendedNodeId?: string) => {
+ set({suspendedNodeId: suspendedNodeId})
+ },
+ setClipboardSteps: (clipboardSteps: CamelElement[]) => {
+ set((state: DesignerState) => {
+ state.clipboardSteps.length = 0;
+ state.clipboardSteps.push(...clipboardSteps);
+ return state;
+ })
+ },
+ width: 100,
+ height: 100,
+ top: 0,
+ left: 0,
+ setPosition: (width: number, height: number, top: number, left: number) => {
+ set({width: width, height: height, top: top, left: left})
+ },
+ reset: () => {
+ set(state => {
+ designerState.designerSwitch = state.designerSwitch;
+ return designerState;
+ });
+ },
+ setNotification: (notificationBadge: boolean, notificationMessage: [string, string]) => {
+ set({notificationBadge: notificationBadge, notificationMessage: notificationMessage})
+ },
+ setMoveElements: (moveElements: [string | undefined, string | undefined]) => {
+ set({moveElements: moveElements})
+ },
+ setPropertyPlaceholders: (propertyPlaceholders: [string, string][]) => {
+ set((state: DesignerState) => {
+ state.propertyPlaceholders.length = 0;
+ state.propertyPlaceholders.push(...propertyPlaceholders);
+ return state;
+ })
+ },
+ setParameterPlaceholders: (parameterPlaceholders: [string, string][]) => {
+ set((state: DesignerState) => {
+ state.parameterPlaceholders.length = 0;
+ state.parameterPlaceholders.push(...parameterPlaceholders);
+ return state;
+ })
+ },
+ setBeans: (beans: BeanFactoryDefinition[]) => {
+ set((state: DesignerState) => {
+ return {beans: [...beans]};
+ })
+ },
+ setTab: (tab?: DesignerViewSwitchOption) => {
+ set({tab: tab})
+ },
+ setDesignerSwitch: (designerSwitch: boolean) => {
+ set({designerSwitch: designerSwitch})
+ },
+ setStepDoubleClicked: (stepDoubleClicked: boolean) => {
+ set({stepDoubleClicked: stepDoubleClicked})
+ },
+}), shallow)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/ErrorBoundaryWrapper.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/ErrorBoundaryWrapper.tsx
new file mode 100644
index 00000000..36ac98dc
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/ErrorBoundaryWrapper.tsx
@@ -0,0 +1,35 @@
+import React, {ReactNode} from "react";
+
+export interface ErrorBoundaryState {
+ hasError: boolean;
+ error: Error | null;
+}
+
+interface ErrorBoundaryProps {
+ children: ReactNode;
+ onError: (error: Error) => void;
+}
+
+export class ErrorBoundaryWrapper extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
+ constructor(props: ErrorBoundaryProps) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+ // Handle error (logging, etc.)
+ console.error("Error caught in ErrorBoundary:", error, errorInfo);
+ this.props.onError(error);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return <div style={{ color: "red" }}>Something went wrong: {this.state.error?.message}</div>;
+ }
+ return this.props.children;
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.css
new file mode 100644
index 00000000..19898c41
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+.karavan .karavan-designer-page {
+ height: 100vh;
+ width: 100%;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
+.karavan .karavan-designer-view-switcher {
+ position: absolute;
+ width: 125px;
+ right: 1px;
+ top: 1px;
+ z-index: 100;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.tsx
new file mode 100644
index 00000000..eda53963
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesigner.tsx
@@ -0,0 +1,207 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import './KaravanDesigner.css';
+import {RouteDesigner} from "./route/RouteDesigner";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {Integration, IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {CamelUi} from "./utils/CamelUi";
+import {useDesignerStore, useIntegrationStore} from "./DesignerStore";
+import {shallow} from "zustand/shallow";
+import {InfrastructureAPI} from "./utils/InfrastructureAPI";
+import {EventBus, IntegrationUpdate} from "./utils/EventBus";
+import {RestDesigner} from "./rest/RestDesigner";
+import {BeansDesigner} from "./beans/BeansDesigner";
+import {KameletDesigner} from "./kamelet/KameletDesigner";
+import {BeanFactoryDefinition, RouteDefinition, RouteTemplateDefinition} from "@karavan-core/model/CamelDefinition";
+import {ErrorBoundaryState, ErrorBoundaryWrapper} from "./ErrorBoundaryWrapper";
+import {Group, Panel, Separator} from 'react-resizable-panels';
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {KaravanDesignerViewSwitch} from "@features/project/designer/KaravanDesignerViewSwitch";
+import {MainPropertiesPanel} from "@features/project/designer/property/MainPropertiesPanel";
+
+interface Props {
+ onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
+ onSaveCustomCode: (name: string, code: string, active: boolean) => void
+ onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>
+ onSavePropertyPlaceholder: (key: string, value: string) => void
+ onInternalConsumerClick: (uri?: string, name?: string, routeId?: string, fileName?: string) => void
+ onCreateNewRoute: (componentName: string, propertyName: string, propertyValue: string) => void
+ onCreateNewFile: (fileName: string, code: string, open: boolean) => void
+ filename: string
+ yaml: string
+ showCodeTab: boolean
+ tab?: "routes" | "rest" | "beans" | "kamelet"
+ propertyPlaceholders: [string, string][]
+ beans: BeanFactoryDefinition[]
+ files: IntegrationFile[]
+}
+
+export function KaravanDesigner(props: Props) {
+
+ const [setSelectedStep, reset, badge, message, setPropertyPlaceholders, setBeans, tab, setTab, selectedStep, setSelectedUuids, setDesignerSwitch] =
+ useDesignerStore((s) =>
+ [s.setSelectedStep, s.reset, s.notificationBadge, s.notificationMessage, s.setPropertyPlaceholders, s.setBeans, s.tab, s.setTab,
+ s.selectedStep, s.setSelectedUuids, s.setDesignerSwitch], shallow)
+ const [integration, setIntegration, resetFiles] = useIntegrationStore((s) =>
+ [s.integration, s.setIntegration, s.resetFiles], shallow)
+
+ useEffect(() => {
+ const sub = EventBus.onIntegrationUpdate()?.subscribe((update: IntegrationUpdate) =>
+ save(update.integration, update.propertyOnly));
+ try {
+ resetErrorBoundary();
+ InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
+ InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
+ InfrastructureAPI.setOnSave(props.onSave);
+ InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder);
+ InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick);
+ InfrastructureAPI.setOnCreateNewRoute(props.onCreateNewRoute);
+ InfrastructureAPI.setOnCreateNewFile(props.onCreateNewFile);
+
+ 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();
+ setPropertyPlaceholders(props.propertyPlaceholders)
+ setBeans(props.beans)
+ resetFiles(props.files)
+ resolveSelectedStep(i);
+ } catch (e: any) {
+ console.error(e)
+ EventBus.sendAlert(' ' + e?.name, '' + e?.message, 'danger');
+ }
+ return () => {
+ sub?.unsubscribe();
+ setSelectedStep(undefined);
+ reset();
+ resetErrorBoundary();
+ setIntegration(Integration.createNew("demo"), false);
+ };
+ }, []);
+
+ function resolveSelectedStep(i: Integration) {
+ try {
+ if (selectedStep) {
+ const step = CamelDefinitionApiExt.findElementById(i, (selectedStep as any).id)
+ if (step) {
+ setSelectedStep(step);
+ setSelectedUuids([step?.uuid])
+ }
+ } else {
+ const r = CamelDefinitionApiExt.getFlowsOfTypes(integration, ['RouteDefinition', 'RouteTemplateDefinition'])?.at(0);
+ if (r) {
+ const step = r?.dslName === 'RouteDefinition' ? (r as RouteDefinition).from : (r as RouteTemplateDefinition).route?.from;
+ if (step) {
+ setSelectedStep(step);
+ setSelectedUuids([step?.uuid])
+ }
+ }
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ function makeIntegration(yaml: string, filename: string): Integration {
+ try {
+ const type = CamelDefinitionYaml.yamlIsIntegration(yaml);
+ if (yaml && type !== 'none') {
+ const i = CamelDefinitionYaml.yamlToIntegration(props.filename, props.yaml)
+ return i;
+ } else {
+ return Integration.createNew(filename, 'plain');
+ }
+ } catch (e) {
+ console.error(e)
+ EventBus.sendAlert("Error parsing YAML", (e as Error).message, 'danger')
+ return Integration.createNew(filename, 'plain');
+ }
+ }
+
+ function save(integration: Integration, propertyOnly: boolean): void {
+ const code = getCode(integration);
+ props.onSave(props.filename, code, propertyOnly);
+ }
+
+ function getCode(integration: Integration): string {
+ try {
+ const clone = CamelUtil.cloneIntegration(integration);
+ return CamelDefinitionYaml.integrationToYaml(clone);
+ } catch (e) {
+ console.error(e)
+ EventBus.sendAlert('Error parsing Yaml', (e as Error).message, 'danger');
+ return '';
+ }
+ }
+
+ const [state, setState] = useState<ErrorBoundaryState>({hasError: false, error: null});
+
+ const resetErrorBoundary = () => {
+ setState({hasError: false, error: null});
+ };
+
+ // Mimic `getDerivedStateFromError`
+ const handleError = (error: Error) => {
+ setState({hasError: true, error});
+ setDesignerSwitch(false)
+ }
+
+ useEffect(() => {
+ if (state.hasError && state.error) {
+ EventBus.sendAlert(state.error.message, state.error?.stack?.toString()?.substring(0, 300) || '', 'danger');
+ }
+ }, [state]);
+
+ function getMainPart() {
+ return (
+ <div className="karavan-designer-page">
+ <KaravanDesignerViewSwitch/>
+ <ErrorBoundaryWrapper onError={handleError}>
+ {tab === 'kamelet' && <KameletDesigner/>}
+ {tab === 'routes' && <RouteDesigner/>}
+ {tab === 'rest' && <RestDesigner/>}
+ {tab === 'beans' && <BeansDesigner/>}
+ </ErrorBoundaryWrapper>
+ </div>
+ )
+ }
+
+ return (
+ (tab !== 'kamelet')
+ ? <Group orientation="horizontal">
+ <Panel minSize={10} defaultSize={70}>
+ {getMainPart()}
+ </Panel>
+ <Separator className='resize-handler'/>
+ <Panel minSize={10} defaultSize={30}>
+ <MainPropertiesPanel/>
+ </Panel>
+ </Group>
+ : <Group orientation="horizontal">
+ {getMainPart()}
+ </Group>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesignerViewSwitch.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesignerViewSwitch.tsx
new file mode 100644
index 00000000..49a825e2
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/KaravanDesignerViewSwitch.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import {Menu, MenuContent, MenuItem, MenuList} from '@patternfly/react-core';
+import {DesignerViewSwitchOption, DesignerViewSwitchOptions, useDesignerStore, useIntegrationStore} from "@features/project/designer/DesignerStore";
+import {shallow} from "zustand/shallow";
+import {getDesignerIcon} from "@features/project/designer/icons/KaravanIcons";
+
+export function KaravanDesignerViewSwitch() {
+
+ const [setSelectedStep, setTab, tab] = useDesignerStore((s) => [s.setSelectedStep, s.setTab, s.tab], shallow)
+ const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+ const isKamelet = integration.type === 'kamelet';
+
+ const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, itemId: number | string | undefined) => {
+ const item = itemId as string; // eslint-disable-next-line no-console
+ if (DesignerViewSwitchOptions.includes(item as DesignerViewSwitchOption)) {
+ setTab(item as DesignerViewSwitchOption);
+ } else {
+ setTab(undefined);
+ }
+ setSelectedStep(undefined);
+ };
+
+ function getMenuItem(name: string, title: string) {
+ return (
+ <MenuItem isSelected={tab === name} itemId={name} key={name} icon={getDesignerIcon(name)}>
+ {title}
+ </MenuItem>
+ )
+ }
+
+ return (
+ <div className="karavan-designer-view-switcher">
+ <Menu onSelect={onSelect} activeItemId={tab}>
+ <MenuContent>
+ <MenuList>
+ {isKamelet && getMenuItem("kamelet", "Kamelet Definitions")}
+ {getMenuItem("routes", "Routes")}
+ {!isKamelet && getMenuItem("rest", "REST")}
+ {getMenuItem("beans", "Beans")}
+ </MenuList>
+ </MenuContent>
+ </Menu>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeanCard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeanCard.tsx
new file mode 100644
index 00000000..1400b213
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeanCard.tsx
@@ -0,0 +1,61 @@
+/*
+ * 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, Flex, FlexItem
+} from '@patternfly/react-core';
+import './bean.css';
+import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
+import {DeleteElementIcon} from "../utils/ElementIcons";
+import {CamelElement} from "@karavan-core/model/IntegrationDefinition";
+
+interface Props {
+ bean: BeanFactoryDefinition
+ selectedStep?: CamelElement
+ selectElement: (element: BeanFactoryDefinition) => void
+ deleteElement: (element: BeanFactoryDefinition) => void
+}
+
+export function BeanCard (props: Props) {
+
+ function selectElement (evt: React.MouseEvent) {
+ evt.stopPropagation();
+ props.selectElement(props.bean);
+ }
+
+ function onDelete (evt: React.MouseEvent) {
+ evt.stopPropagation();
+ props.deleteElement(props.bean);
+ }
+
+ const bean = props.bean;
+ return (
+ <Flex direction={{default: "row"}}
+ className={props.selectedStep?.uuid === bean.uuid ? "bean-card bean-card-selected" : "bean-card bean-card-unselected"}
+ onClick={e => selectElement(e)}
+ >
+ <FlexItem flex={{default:"flex_1"}} className="title">Bean</FlexItem>
+ <FlexItem flex={{default:"flex_2"}} className="title">{bean.name}</FlexItem>
+ <FlexItem flex={{default:"flex_3"}} align={{default: "alignRight"}} className="description">{bean.type}</FlexItem>
+ <FlexItem>
+ <Button variant="link" className="delete-button" onClick={e => onDelete(e)}>
+ {DeleteElementIcon()}
+ </Button>
+ </FlexItem>
+ </Flex>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeansDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeansDesigner.tsx
new file mode 100644
index 00000000..5cd1a6bf
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/BeansDesigner.tsx
@@ -0,0 +1,115 @@
+/*
+ * 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, {useEffect} from 'react';
+import {Button, Flex, FlexItem, Gallery, GalleryItem, PageSection} from '@patternfly/react-core';
+import './bean.css';
+import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
+import {CamelUi} from "../utils/CamelUi";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {BeanCard} from "./BeanCard";
+import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+
+export function BeansDesigner() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+ const [selectedStep, showDeleteConfirmation, setShowDeleteConfirmation, setSelectedStep, setNotification]
+ = useDesignerStore((s) =>
+ [s.selectedStep, s.showDeleteConfirmation, s.setShowDeleteConfirmation, s.setSelectedStep, s.setNotification], shallow)
+
+ useEffect(() => {
+ return () => {
+ setNotification(false, ['', '']);
+ }
+ }, []);
+
+ function onShowDeleteConfirmation(bean: BeanFactoryDefinition) {
+ setSelectedStep(bean);
+ setShowDeleteConfirmation(true);
+ }
+
+ function deleteBean() {
+ const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep as BeanFactoryDefinition);
+ setIntegration(i, false);
+ setShowDeleteConfirmation(false);
+ setSelectedStep(undefined);
+ }
+
+ function selectBean(bean?: BeanFactoryDefinition) {
+ setSelectedStep(bean);
+ }
+
+ function unselectBean(evt: React.MouseEvent<HTMLDivElement, MouseEvent>) {
+ if ((evt.target as any).dataset.click === 'BEANS') {
+ evt.stopPropagation()
+ setSelectedStep(undefined);
+ }
+ }
+
+ function createBean() {
+ const bean = new BeanFactoryDefinition();
+ const clone = CamelUtil.cloneIntegration(integration);
+ const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
+ setIntegration(i, false);
+ setSelectedStep(bean);
+ }
+
+ const beans = CamelUi.getBeans(integration);
+ return (
+ <PageSection hasBodyWrapper={false} className="bean-designer" isFilled padding={{default: 'noPadding'}}>
+ <Gallery className="gallery"
+ hasGutter
+ maxWidths={{
+ default: '100%',
+ }}
+ >
+ {beans?.map((bean, index) => (
+ <GalleryItem key={bean.uuid + index}>
+ <BeanCard bean={bean}
+ selectedStep={selectedStep}
+ selectElement={selectBean}
+ deleteElement={onShowDeleteConfirmation}
+ />
+ </GalleryItem>
+ ))}
+ <GalleryItem>
+ <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentCenter"}}>
+ <FlexItem>
+ <Button
+ variant={beans?.length === 0 ? "primary" : "secondary"}
+ data-click="ADD_REST"
+ icon={<PlusIcon/>}
+ onClick={e => createBean()}>Create bean
+ </Button>
+ </FlexItem>
+ </Flex>
+ </GalleryItem>
+ </Gallery>
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message='Delete bean from integration?'
+ btnConfirm='Delete'
+ btnConfirmVariant='danger'
+ onConfirm={() => deleteBean()}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ </PageSection>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/bean.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/bean.css
new file mode 100644
index 00000000..c6a4b43b
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/beans/bean.css
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+.karavan .bean-card {
+ /*max-width: 800px;*/
+ border-style: dashed;
+ border-radius: 42px;
+ border-width: 1px;
+ padding: 16px 6px 16px 16px;
+ margin-right: 80px;
+ margin-left: 80px;
+ position: relative;
+}
+
+.karavan .bean-card-unselected {
+ border-color: var(--pf-t--global--color--brand--200);
+ background-color: transparent;
+}
+
+.karavan .bean-card-selected {
+ border-color: var(--pf-t--global--color--brand--100);
+}
+
+.karavan .bean-card .title {
+ margin: auto 0 auto 0;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+.karavan .bean-card .description {
+ margin: auto 0 auto 0;
+ min-width: 200px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.karavan .bean-card .delete-button {
+ position: relative;
+ right: 6px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ background: transparent;
+ color: #909090;
+ visibility: hidden;
+ z-index: 100;
+}
+
+.karavan .bean-card:hover .delete-button {
+ visibility: visible;
+}
+
+/*.karavan .bean-designer {*/
+/* display: block;*/
+/* height: 100vh;*/
+/* width: 100%;*/
+/* overflow-y: auto;*/
+/* padding-bottom: 106px;*/
+/*}*/
+
+.karavan .bean-designer .gallery {
+ padding-top: 16px;
+ padding-bottom: 16px;
+}
+
+.karavan .bean-designer .properties {
+ padding: 10px 10px 10px 10px;
+ background: transparent;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+/*Beans*/
+.karavan .bean-designer .properties .bean-property {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+}
+
+.karavan .bean-designer .properties .bean-property .delete-button {
+ padding: 3px;
+ color: #b1b1b7;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx
new file mode 100644
index 00000000..3be551c9
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx
@@ -0,0 +1,69 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import '@shared/monaco-setup';
+import Editor from "@monaco-editor/react";
+import {shallow} from "zustand/shallow";
+import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+
+export function CodeEditor () {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow);
+ const [setNotification, badge] = useDesignerStore((s) => [s.setNotification, s.notificationBadge], shallow)
+ const [code, setCode] = useState<string>('');
+
+ useEffect(() => {
+ try {
+ const clone = CamelUtil.cloneIntegration(integration);
+ const c = CamelDefinitionYaml.integrationToYaml(clone);
+ setCode(c);
+ } catch (e: any) {
+ const message: string = e?.message ? e.message : e.reason;
+ setNotification(true, ['Error in YAML, Integration can not be saved!', message]);
+ }
+ return () => {
+ setNotification(false, ['', '']);
+ }
+ }, []);
+
+ function onChange(value: string | undefined) {
+ if (value) {
+ try {
+ const i = CamelDefinitionYaml.yamlToIntegration(integration.metadata.name, value);
+ setIntegration(i, false);
+ setNotification(false, ['', '']);
+ } catch (e: any) {
+ const message: string = e?.message ? e.message : e.reason;
+ setNotification(true, ['Error in YAML, Integration can not be saved!' ,message]);
+ }
+ }
+ }
+
+ return (
+ <Editor
+ height="100vh"
+ defaultLanguage={'yaml'}
+ theme={'light'}
+ value={code}
+ className={'code-editor'}
+ defaultValue={code}
+ onChange={(value, ev) => onChange(value)}
+ />
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/ComponentIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/ComponentIcons.tsx
new file mode 100644
index 00000000..284ab55a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/ComponentIcons.tsx
@@ -0,0 +1,1833 @@
+/*
+ * 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';
+
+export function AmqpIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 116 115"
+ width="32px" height="32px"
+ className="icon"
+ >
+ <g>
+ <path
+ fill="#000"
+ d="m.027 110.87.02-19.535c0-2.731 0-5.461.006-8.198 0-.212.033-.43.053-.729h1.405c26.904 0 53.808-.006 80.712 0 .543 0 1.087.1 1.623.153 1.803 1.875 3.565 3.797 5.414 5.626 2.989 2.949 6.044 5.825 9.046 8.747 1.06 1.034 2.041 2.154 3.108 3.187 2.133 2.068 4.307 4.096 6.441 6.157 2.551 2.465 5.082 4.943 7.627 7.421l.47.53.02.285-.02-.046-.046.013-.252.04c-.113.053-.225.113-.331.166l-.504.079c.007-.04.013-.079.02-.112-.272-.603-1.173-.67-1.67-.133-.987.02-1.975.04-2.969.066 [...]
+ />
+ <path
+ fill="#c9cbce"
+ d="M115.488 113.699c-2.538-2.471-5.076-4.956-7.627-7.422-2.14-2.06-4.314-4.088-6.441-6.156-1.067-1.033-2.04-2.153-3.108-3.187-3.008-2.929-6.063-5.805-9.045-8.747-1.849-1.829-3.611-3.744-5.414-5.626V.166c.146-.02.225-.047.245-.027.71.862 1.657.915 2.69.915 9.192-.027 18.383-.014 27.574-.014 1.299 0 1.299 0 1.299 1.279v107.232c0 .497.006.994.013 1.491 0 .384-.013.775-.02 1.16-.053.503-.113 1.007-.166 1.504z"
+ />
+ <path
+ fill="#002485"
+ d="M74.59 73.231c0 .119.006.331-.014.338-.272.039-.55.066-.822.066H1.36c-.219 0-.444.013-.663.02H.18c-.046-.259-.132-.517-.132-.775-.007-10.239-.014-20.477 0-30.715 0-.278.199-.55.305-.828.178.02.364.04.543.053.046 0 .086.013.113.053 0 .848.583.848 1.199.848h38.328c.272 0 .537-.026.908-.04v-.868l.636.04c.219.206.438.411.65.616l13.233 13.075c3.254 3.214 6.514 6.427 9.774 9.635 2.611 2.571 5.229 5.135 7.84 7.7.337.265.669.53 1.007.795z"
+ />
+ <path
+ fill="#a1afd9"
+ d="M73.582 72.435c-2.61-2.564-5.228-5.129-7.84-7.7A6480.73 6480.73 0 0 1 55.97 55.1c-4.414-4.353-8.82-8.714-13.234-13.074-.212-.212-.43-.411-.65-.616 0-5.567.014-11.14.02-16.706V0c.743.331 1.366.616 1.989.895.086.086.159.238.252.245 1.186.112 2.379.278 3.571.291 5.189.034 10.378.027 15.566.02 3.161-.006 6.322-.046 9.483-.099.325 0 .643-.219.96-.338.113.331.22.669.332 1.001.04.669.073 1.338.113 2.001-.007.159-.02.324-.027.483-.702.073-.417.623-.417.968-.014 20.304-.014 40. [...]
+ />
+ <path
+ fill="#000"
+ d="M31.987 31.536c.205.239.417.477.749.862H29.74c-9.356 0-18.707.013-28.063.013H1.43C.491 32.428.02 31.945.02 30.96c.013-9.795.027-19.589.053-29.383 0-.397.066-.795.113-1.312.662.583 1.16 1.014 1.656 1.451.146.219.265.471.45.656 2.512 2.512 5.024 5.03 7.562 7.522 1.213 1.186 2.498 2.299 3.698 3.492 2.266 2.246 4.472 4.546 6.739 6.785 1.955 1.929 3.956 3.804 5.924 5.719 1.928 1.876 3.843 3.764 5.765 5.646z"
+ />
+ <path
+ fill="#c9cbce"
+ d="M31.986 31.536c-1.921-1.882-3.836-3.77-5.765-5.646-1.968-1.915-3.976-3.79-5.924-5.718-2.266-2.24-4.48-4.54-6.74-6.786-1.205-1.193-2.49-2.306-3.697-3.492-2.538-2.492-5.05-5.01-7.56-7.522-.186-.185-.299-.437-.451-.656.642-.835 1.623-.622 2.432-.642 3.498-.08 7.004-.04 10.51-.04h16.3c1.16 0 1.247.086 1.247 1.213 0 9.211 0 18.422-.02 27.632 0 .551-.212 1.101-.318 1.657z"
+ />
+ </g>
+ </svg>
+ )
+}
+
+export function SalesforceIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 273 191"
+ width="32px" height="32px"
+ className="icon"
+ >
+ <defs>
+ <path id="a" d="M.06.5h272v190H.06z" />
+ </defs>
+ <g fillRule="evenodd">
+ <path
+ fill="#00A1E0"
+ d="M113 21.3c8.78-9.14 21-14.8 34.5-14.8 18 0 33.6 10 42 24.9a58 58 0 0 1 23.7-5.05c32.4 0 58.7 26.5 58.7 59.2s-26.3 59.2-58.7 59.2c-3.96 0-7.82-.398-11.6-1.15-7.35 13.1-21.4 22-37.4 22a42.7 42.7 0 0 1-18.8-4.32c-7.45 17.5-24.8 29.8-45 29.8-21.1 0-39-13.3-45.9-32a45.1 45.1 0 0 1-9.34.972c-25.1 0-45.4-20.6-45.4-45.9 0-17 9.14-31.8 22.7-39.8a52.6 52.6 0 0 1-4.35-21c0-29.2 23.7-52.8 52.9-52.8 17.1 0 32.4 8.15 42 20.8"
+ mask="url(#b)"
+ />
+ <path
+ fill="#FFFFFE"
+ d="M39.4 99.3c-.171.446.061.539.116.618.511.37 1.03.638 1.55.939 2.78 1.47 5.4 1.9 8.14 1.9 5.58 0 9.05-2.97 9.05-7.75v-.094c0-4.42-3.92-6.03-7.58-7.18l-.479-.155c-2.77-.898-5.16-1.68-5.16-3.5v-.093c0-1.56 1.4-2.71 3.56-2.71 2.4 0 5.26.799 7.09 1.81 0 0 .542.35.739-.173.107-.283 1.04-2.78 1.14-3.06.106-.293-.08-.514-.271-.628-2.1-1.28-5-2.15-8-2.15l-.557.002c-5.11 0-8.68 3.09-8.68 7.51v.095c0 4.66 3.94 6.18 7.62 7.23l.592.184c2.68.824 5 1.54 5 3.42v.094c0 1.73-1.5 [...]
+ />
+ <path
+ fill="#FFFFFE"
+ d="M162.201 67.548a13.258 13.258 0 0 0-1.559-.37 12.217 12.217 0 0 0-2.144-.166c-2.853 0-5.102.806-6.681 2.398-1.568 1.58-2.635 3.987-3.17 7.154l-.193 1.069h-3.581s-.437-.018-.529.459l-.588 3.28c-.041.314.094.51.514.508h3.486l-3.537 19.743c-.277 1.59-.594 2.898-.945 3.889-.346.978-.684 1.711-1.1 2.243-.403.515-.785.894-1.444 1.115-.544.183-1.17.267-1.856.267-.382 0-.89-.064-1.265-.139-.375-.074-.57-.158-.851-.276 0 0-.409-.156-.57.254-.131.335-1.06 2.89-1.17 3.206 [...]
+ />
+ </g>
+ </svg>
+ )
+}
+export function SlackIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127 127" width={32} height={32} className="icon">
+ <g fill="none">
+ <path
+ fill="#E01E5A"
+ d="M27.2 80c0 7.3-5.9 13.2-13.2 13.2C6.7 93.2.8 87.3.8 80c0-7.3 5.9-13.2 13.2-13.2h13.2V80zm6.6 0c0-7.3 5.9-13.2 13.2-13.2 7.3 0 13.2 5.9 13.2 13.2v33c0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V80z"
+ />
+ <path
+ fill="#36C5F0"
+ d="M47 27c-7.3 0-13.2-5.9-13.2-13.2C33.8 6.5 39.7.6 47 .6c7.3 0 13.2 5.9 13.2 13.2V27H47zm0 6.7c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H13.9C6.6 60.1.7 54.2.7 46.9c0-7.3 5.9-13.2 13.2-13.2H47z"
+ />
+ <path
+ fill="#2EB67D"
+ d="M99.9 46.9c0-7.3 5.9-13.2 13.2-13.2 7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H99.9V46.9zm-6.6 0c0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V13.8C66.9 6.5 72.8.6 80.1.6c7.3 0 13.2 5.9 13.2 13.2v33.1z"
+ />
+ <path
+ fill="#ECB22E"
+ d="M80.1 99.8c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V99.8h13.2zm0-6.6c-7.3 0-13.2-5.9-13.2-13.2 0-7.3 5.9-13.2 13.2-13.2h33.1c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H80.1z"
+ />
+ </g>
+ </svg>
+ )
+}
+
+export function VertXIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ id="svg8"
+ x={0}
+ y={0}
+ viewBox="0 0 114.3 114.3"
+ className="icon" width="32px" height="32px">
+ <style>{".st3{fill:#fff}"}</style>
+ <path
+ id="rect4446"
+ d="M15.9 2.7h82.4c7.3 0 13.3 5.1 13.3 11.3v86.3c0 6.2-5.9 11.3-13.3 11.3H15.9c-7.3 0-13.3-5.1-13.3-11.3V14c.1-6.3 6-11.3 13.3-11.3z"
+ style={{
+ fill: "#782a90",
+ stroke: "#782a90",
+ strokeWidth: 5.383,
+ strokeLinejoin: "round",
+ strokeMiterlimit: 11.3386,
+ }}
+ />
+ <path
+ id="path4436"
+ d="M-6.7 20.8h18.6l18.4 42.4 19.2-41.9h17.8L35.1 92.1H24.9L-6.7 20.8z"
+ style={{
+ fillRule: "evenodd",
+ clipRule: "evenodd",
+ fill: "#fff",
+ }}
+ />
+ <circle
+ id="circle4442"
+ cx={42.5}
+ cy={91.8}
+ r={13.2}
+ style={{
+ fill: "#fff",
+ stroke: "#782a90",
+ strokeWidth: 6.3269,
+ strokeLinejoin: "round",
+ strokeMiterlimit: 11.3386,
+ }}
+ />
+ <path
+ d="M100.2 61.8 89.6 77.9l7.6 13.7h21.9zM96.3 21.3l-12.2 19-10.4-19H52.1L74 56.1 56.8 83.3c1.5 2.4 2.3 5.3 2.4 8.3H72l46-70.3H96.3z"
+ className="st3"
+ />
+ </svg>
+ )
+}
+
+export function SmooksIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 90 79"
+ className="icon" width="32px" height="32px">
+ <path fill="#FDFEFE" d="M0 0h90v79H0V0Z"/>
+ <path
+ fill="#795EAA"
+ d="M28 9c3.944.589 6.824 1.786 10.25 3.813.871.5 1.743 1.002 2.64 1.519C43.279 16.22 43.595 17.062 44 20l1 1.938c1.13 2.332 1.575 4.515 2 7.062l3.875-.125c2.18-.07 2.18-.07 4.125.125 2 2 2 2 2.195 4.82l-.07 3.305-.055 3.32L57 43c-5.573-.76-5.573-.76-8-2.125-2.895-1.267-4.892-.44-8 .125-3.668.096-7.331.059-11 0l.063 2.875C30 47 30 47 29 49c-3.911-.674-6.871-2.543-10.25-4.563l-3.266-1.94L13 41l.95-1.875C15.01 36.979 15.775 35.388 16 33c-1.392-2.133-1.392-2.133-3-4v-2c-.957- [...]
+ />
+ <path
+ fill="#136C2B"
+ d="M47 42v3c6.26 1.163 6.26 1.163 12-1 3.253.105 4.262 1.232 6.75 3.438C68 50 68 50 68 52l-2.082.48c-5.657 1.283-5.657 1.283-9.793 5.02L55 60c-2.188 1.813-2.188 1.813-4 3l1 2.313C53 68 53 68 53 71l-15 2v-7c-5.472-1.243-5.472-1.243-10.5.438L26 68c-3.82-1.556-6.26-3.956-9-7v-2c3.62-1.316 6.096-2 10-2l.25-2.25C28 52 28 52 30.063 50c2.215-1.868 2.215-1.868 2.187-4.75L32 43c5.07-.712 9.882-1.107 15-1Z"
+ />
+ <path
+ fill="#5D76B5"
+ d="M60 10c1.437-.027 2.875-.046 4.313-.063l2.425-.035C69 10 69 10 72 11v3c3.292 1.254 5.64 2.021 9.188 1.813L84 16c2.311 2.85 3 4.314 3 8l-1.758.078c-5.37.39-9.18 1.069-13.242 4.922v6H60c-1-3-1-3 0-6-2.802-1.793-4.083-1.996-7.5-1.813C49 27 49 27 46.562 24.625 45 22 45 22 45 20l3.813-.25c3.465-.378 3.465-.378 6-2.75L56 15l3-1c.733-2.015.733-2.015 1-4Z"
+ />
+ <path
+ fill="#E4EAE9"
+ d="M57 38h1l1 7c-3.67 1.573-5.443 2.144-9.375 1.125L47 45v-3l-13 1v-2c8.909-2.395 14.505-1.369 23 2v-5Z"
+ />
+ <path
+ fill="#D1D4E8"
+ d="m44 17 1 2h8v1h-8c2.88 4.577 2.88 4.577 7 8l-5 1c-1.524-2.983-2.94-5.818-4-9l1-3Z"
+ />
+ <path fill="#F6F6F9" d="M30 41h4v2h-2l1 5-4 3-2-2h2l1-8Z" />
+ </svg>
+ )
+}
+export function DHIS2Icon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ id="Layer_1"
+ viewBox="0 0 195 175"
+ className="icon" width="32px" height="32px"
+ data-name="Layer 1"
+ >
+ <defs id="defs1">
+ <style id="style1">{".cls-1{fill:#0080d4}"}</style>
+ </defs>
+ <path
+ id="path1"
+ d="m189.415 56.477-82.74-53.66a19.75 19.75 0 0 0-20.33 0l-80.35 52.09a12 12 0 0 0-.25 20.63l80.54 54.94a19.39 19.39 0 0 0 20.38.25l82.75-53.65a11.87 11.87 0 0 0 0-20.59zm-91 61.45a4.29 4.29 0 0 1-3.49-.05l-77-52.49 76.71-49.78a4.76 4.76 0 0 1 3.74 0l78.91 51.15z"
+ className="cls-1"
+ />
+ <path
+ id="path2"
+ d="m86.345 44.297-43.56 28.24 13.62 9.33 38.23-24.78a4.76 4.76 0 0 1 3.74 0l39.37 25.52 14-9.06-45.07-29.25a19.78 19.78 0 0 0-20.33 0z"
+ className="cls-1"
+ />
+ <path
+ id="path3"
+ d="m189.415 97.937-8.62-5.59-14 9.06 10.52 6.83-78.91 51.15a4.37 4.37 0 0 1-3.49 0l-77-52.5 10-6.47-13.67-9.37-8.25 5.34a12 12 0 0 0-.25 20.63l80.54 54.92a19.36 19.36 0 0 0 20.38.24l82.74-53.65a11.87 11.87 0 0 0 0-20.59z"
+ className="cls-1"
+ />
+ </svg>
+ );
+}
+
+export function DirectIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px"
+ >
+ <path
+ d="M25 11a5.008 5.008 0 0 0-4.899 4H11.9a5 5 0 1 0 0 2H20.1A5 5 0 1 0 25 11Zm0 8a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function SpringIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <g fill="none" fillRule="evenodd">
+ <path d="M0 0h32v32H0z"></path>
+ <path
+ fill="#70AD51"
+ d="M5.466 27.993a1.364 1.364 0 10-.087-.076l-.266-.234C1.972 24.762 0 20.597 0 15.978 0 7.168 7.168 0 15.98 0c4.48 0 8.53 1.857 11.435 4.836a14.681 14.681 0 001.7-3.015c2.036 6.118 3.233 11.26 2.795 15.31-.592 8.274-7.508 14.83-15.93 14.83a15.903 15.903 0 01-10.276-3.757l-.238-.21zm23.58-4.982c4.01-5.336 1.775-13.965-.085-19.48-1.657 3.453-5.738 6.094-9.262 6.93-3.303.788-6.226.142-9.283 1.318-6.97 2.68-6.86 10.992-3.02 12.86.002 0 .23.124.227.12 0-.002 5.644-1.122 8. [...]
+ ></path>
+ </g>
+ </svg>
+ );
+}
+
+export function QuarkusIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="-0.5 0 257 257"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#4695EB"
+ d="M213.554 0c23.418.08 42.377 19.052 42.443 42.47v171.084c-.066 23.428-19.042 42.404-42.47 42.47h-25.439l-11.661-28.318h37.127c7.774-.1 14.051-6.378 14.152-14.152V42.47c-.1-7.774-6.378-14.051-14.152-14.152H42.47c-7.774.1-14.051 6.378-14.152 14.152v171.084c.1 7.774 6.378 14.051 14.152 14.152h62.607l22.935-48.494 31.625 76.812H42.47C19.042 255.958.066 236.982 0 213.554V42.47C.066 19.042 19.042.066 42.47 0h171.084zm-43.983 139.727v45.51l-39.417-22.748 39.417-22.762zM86.453 [...]
+ ></path>
+ <path
+ fill="#FF004A"
+ d="M86.453 139.727l39.417 22.762-39.417 22.748v-45.51zm83.118-45.509l39.418 22.748-39.418 22.761V94.218zM88.595 44.987l39.417 22.748-39.417 22.761V44.987z"
+ ></path>
+ <path
+ fill="#091313"
+ d="M86.453 94.218l39.417 22.748v45.523l-39.417-22.762V94.218zm83.118 0v45.51l-39.417 22.76v-45.522l39.417-22.748zm-41.559-26.483l39.417 22.761-39.417 22.761-39.417-22.76 39.417-22.762z"
+ ></path>
+ </svg>
+ );
+}
+
+export function DatabaseIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 24 24"
+ className="icon" width="32px" height="32px">
+ <path
+ fillRule="evenodd"
+ d="M12 1.25c-2.487 0-4.774.402-6.466 1.079-.844.337-1.577.758-2.112 1.264C2.886 4.1 2.5 4.744 2.5 5.5v12.987l.026.013H2.5c0 .756.386 1.4.922 1.907.535.506 1.268.927 2.112 1.264 1.692.677 3.979 1.079 6.466 1.079s4.773-.402 6.466-1.079c.844-.337 1.577-.758 2.112-1.264.536-.507.922-1.151.922-1.907h-.026l.026-.013V5.5c0-.756-.386-1.4-.922-1.907-.535-.506-1.268-.927-2.112-1.264C16.773 1.652 14.487 1.25 12 1.25zM4 5.5c0-.21.104-.487.453-.817.35-.332.899-.666 1.638-.962C7.566 3. [...]
+ ></path>
+ </svg>
+ );
+}
+
+export function CloudIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M16 7a7.66 7.66 0 0 1 1.51.15 8 8 0 0 1 6.35 6.34l.26 1.35 1.35.24a5.5 5.5 0 0 1-1 10.92H7.5a5.5 5.5 0 0 1-1-10.92l1.34-.24.26-1.35A8 8 0 0 1 16 7m0-2a10 10 0 0 0-9.83 8.12A7.5 7.5 0 0 0 7.49 28h17a7.5 7.5 0 0 0 1.32-14.88 10 10 0 0 0-7.94-7.94A10.27 10.27 0 0 0 16 5Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function FileIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="m25.7 9.3-7-7c-.2-.2-.4-.3-.7-.3H8c-1.1 0-2 .9-2 2v24c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V10c0-.3-.1-.5-.3-.7zM18 4.4l5.6 5.6H18V4.4zM24 28H8V4h8v6c0 1.1.9 2 2 2h6v16z"/>
+ <path d="M10 22h12v2H10zM10 16h12v2H10z"/>
+ <path
+ d="M0 0h32v32H0z"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function MessagingIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="M28 28H4a2.002 2.002 0 0 1-2-2v-5h2v5h24v-5h2v5a2.002 2.002 0 0 1-2 2Z"/>
+ <path d="M7 21h18v2H7zM7 16h18v2H7zM7 11h18v2H7zM7 6h18v2H7z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function SchedulingIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="M16 30a14 14 0 1 1 14-14 14 14 0 0 1-14 14Zm0-26a12 12 0 1 0 12 12A12 12 0 0 0 16 4Z"/>
+ <path d="M20.59 22 15 16.41V7h2v8.58l5 5.01L20.59 22z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function HttpIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M30 11h-5v10h2v-3h3a2.003 2.003 0 0 0 2-2v-3a2.002 2.002 0 0 0-2-2Zm-3 5v-3h3l.001 3ZM10 13h2v8h2v-8h2v-2h-6v2zM23 11h-6v2h2v8h2v-8h2v-2zM6 11v4H3v-4H1v10h2v-4h3v4h2V11H6z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function GoogleCloudIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 -25 256 256"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#EA4335"
+ d="m170.252 56.819 22.253-22.253 1.483-9.37C153.437-11.677 88.976-7.496 52.42 33.92 42.267 45.423 34.734 59.764 30.717 74.573l7.97-1.123 44.505-7.34 3.436-3.513c19.797-21.742 53.27-24.667 76.128-6.168l7.496.39Z"
+ />
+ <path
+ fill="#4285F4"
+ d="M224.205 73.918a100.249 100.249 0 0 0-30.217-48.722l-31.232 31.232a55.515 55.515 0 0 1 20.379 44.037v5.544c15.35 0 27.797 12.445 27.797 27.796 0 15.352-12.446 27.485-27.797 27.485h-55.671l-5.466 5.934v33.34l5.466 5.231h55.67c39.93.311 72.553-31.494 72.864-71.424a72.303 72.303 0 0 0-31.793-60.453"
+ />
+ <path
+ fill="#34A853"
+ d="M71.87 205.796h55.593V161.29H71.87a27.275 27.275 0 0 1-11.399-2.498l-7.887 2.42-22.409 22.253-1.952 7.574c12.567 9.489 27.9 14.825 43.647 14.757"
+ />
+ <path
+ fill="#FBBC05"
+ d="M71.87 61.425C31.94 61.664-.237 94.228.001 134.159a72.301 72.301 0 0 0 28.222 56.88l32.248-32.246c-13.99-6.322-20.208-22.786-13.887-36.776 6.32-13.99 22.786-20.208 36.775-13.888a27.796 27.796 0 0 1 13.887 13.888l32.248-32.248A72.224 72.224 0 0 0 71.87 61.425"
+ />
+ </svg>
+ );
+}
+
+export function AwsIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 16 16"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#252F3E"
+ d="M4.51 7.687c0 .197.02.357.058.475.042.117.096.245.17.384a.233.233 0 0 1 .037.123c0 .053-.032.107-.1.16l-.336.224a.255.255 0 0 1-.138.048c-.054 0-.107-.026-.16-.074a1.652 1.652 0 0 1-.192-.251 4.137 4.137 0 0 1-.165-.315c-.415.491-.936.737-1.564.737-.447 0-.804-.129-1.064-.385-.261-.256-.394-.598-.394-1.025 0-.454.16-.822.484-1.1.325-.278.756-.416 1.304-.416.18 0 .367.016.564.042.197.027.4.07.612.118v-.39c0-.406-.085-.689-.25-.854-.17-.166-.458-.246-.868-.246-.186 0-.37 [...]
+ />
+ <g fill="#F90" fillRule="evenodd" clipRule="evenodd">
+ <path
+ d="M14.465 11.813c-1.75 1.297-4.294 1.986-6.481 1.986-3.065 0-5.827-1.137-7.913-3.027-.165-.15-.016-.353.18-.235 2.257 1.313 5.04 2.109 7.92 2.109 1.941 0 4.075-.406 6.039-1.239.293-.133.543.192.255.406z"/>
+ <path
+ d="M15.194 10.98c-.223-.287-1.479-.138-2.048-.069-.17.022-.197-.128-.043-.24 1-.705 2.645-.502 2.836-.267.192.24-.053 1.89-.99 2.68-.143.123-.281.06-.218-.1.213-.53.687-1.72.463-2.003z"/>
+ </g>
+ </svg>
+ );
+}
+
+export function MailIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M28 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2Zm-2.2 2L16 14.78 6.2 8ZM4 24V8.91l11.43 7.91a1 1 0 0 0 1.14 0L28 8.91V24Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function IotIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M30 19h-4v-4h-2v9H8V8h9V6h-4V2h-2v4H8a2.002 2.002 0 0 0-2 2v3H2v2h4v6H2v2h4v3a2.002 2.002 0 0 0 2 2h3v4h2v-4h6v4h2v-4h3a2.003 2.003 0 0 0 2-2v-3h4Z"/>
+ <path d="M21 21H11V11h10Zm-8-2h6v-6h-6ZM31 13h-2A10.012 10.012 0 0 0 19 3V1a12.013 12.013 0 0 1 12 12Z"/>
+ <path d="M26 13h-2a5.006 5.006 0 0 0-5-5V6a7.008 7.008 0 0 1 7 7Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function GithubIcon() {
+ return (
+ <svg
+ aria-hidden="true"
+ data-view-component="true"
+ viewBox="0 0 16 16"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45 [...]
+ </svg>
+ );
+}
+
+export function CassandraIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 113.63554 58.899029"
+ className="icon" width="32px" height="32px">
+ <defs>
+ <path id="a" d="M24.216.082v24.141H.053V.082z"/>
+ </defs>
+ <g
+ style={{
+ fill: "none",
+ fillRule: "evenodd",
+ stroke: "none",
+ strokeWidth: 1,
+ }}
+ >
+ <path
+ fill="#bbe6fb"
+ d="M90.565 20.787C91.4 30.202 76.112 39.163 56.422 40.8c-19.69 1.638-36.329-4.669-37.162-14.083C18.426 17.3 33.713 8.34 53.404 6.702c19.69-1.636 36.329 4.669 37.161 14.085"
+ />
+ <path
+ fill="#fff"
+ d="M53.334 6.75c-4.16-.255-11.326 1.915-17.302 4.08a17.762 17.762 0 0 0-1.413 6.948c0 10.096 9.154 18.28 18.837 18.28 9.62 0 18.13-8.197 18.836-18.28.23-3.283-.9-6.377-2.47-9.044-6.196-1.091-12.771-1.758-16.488-1.984"
+ />
+ <image
+ xlinkHref="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUwAAADqCAYAAADJXHwYAAAABGdBTUEAALGOfPtRkwAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABTKADAAQAAAABAAAA6gAAAAAGjBs3AAAWs0lEQVR4Ae2d+dPctAGG+SABQkI5AyFQ7hZaekA7nbbT0v7J/bkz7bRQGGDKGaCcIRAg5CBAIBchJH3fjfxh79q78q4P2X40o3hty7b02N8T2ZLlrasIEGiIwOXLl7e0qxtCvF7Ta0K8Ovc7W1Y2XZbO6y4pXlT8Pkzzv7Nl2bTuuotbW1uXtV8CBCoJ+AInQCCKgIR4rRJaiLvDNP/by3YpDvmamhdyJt9sWiZhL3P8NsTzYXoBAYvEyMKQL+6RnYp+i5O [...]
+ width={43.164}
+ height={31.532}
+ x={31.672}
+ y={6.587}
+ opacity={0.596}
+ />
+ <path
+ fill="#373535"
+ d="M42.663 16.453c.51-1.13 1.282-1.683 2.031-2.63-.083-.224-.265-.958-.265-1.212 0-1.128.928-2.056 2.056-2.056.26 0 .517.05.758.146a14.985 14.985 0 0 1 13.597-2.39c-4.45-.617-9.466.96-12.878 3.713.104.246.393.949.393 1.232 0 1.135-.735 1.411-1.87 1.411-.258 0-.504-.05-.732-.136-.771 1.035-1.715 3.006-2.178 4.239 1.887 1.687 3.592 2.299 5.813 3.13-.006-.106.076-.205.076-.312 0-3.424 3.014-6.206 6.438-6.206a6.195 6.195 0 0 1 6.105 5.158c1.53-.974 3.01-1.72 4.139-3.164-. [...]
+ />
+ <path
+ fill="#373535"
+ d="M68.25 14.909c.303.265.555.58.748.932.502.9-.503 1.724-1.533 1.724a1.846 1.846 0 0 1-.306-.031c-1.161 1.814-3.194 4.14-5 5.311 2.769.454 5.38 1.563 7.46 3.277 1.513-2.711 2.673-6.627 2.673-9.953 0-2.532-1.117-4.387-2.804-5.748-.089 1.356-.813 3.252-1.236 4.488M45.77 32.084c.922-2.549 3.192-4.524 5.34-6.26-.315-.43-.786-1.496-.982-2a15.027 15.027 0 0 1-6.733-4.261l-.044.17a13.62 13.62 0 0 0-.232 4.52 2.709 2.709 0 0 1 2.203 2.654c0 .783-.687 1.92-1.22 2.414.58 1.25. [...]
+ />
+ <path
+ fill="#373535"
+ d="M45.607 34.222c-1.1-1.094-1.862-3.277-2.576-4.648a2.707 2.707 0 0 1-.41.035c-1.494 0-3.058-1.253-2.704-2.702.196-.803.75-1.327 1.652-1.765-.206-1.662-.261-4.051.124-5.78.111-.494.345-.726.5-1.196-1.647-2.41-2.711-5.574-2.711-8.713 0-.115.005-.228.008-.342-2.783 1.396-4.87 3.595-4.87 7.058 0 7.659 4.41 15.171 10.973 18.116l.014-.062m16.138-10.588a6.196 6.196 0 0 1-5.843 4.145 6.167 6.167 0 0 1-3.826-1.327c-2.173 1.692-4.143 4.664-5.145 7.242.45.484.763.882 1.267 1.3 [...]
+ />
+ <path
+ fill="#1287b1"
+ d="M42.493 17.348a14.975 14.975 0 0 1 1.898-3.122 2.057 2.057 0 0 1-.132-.72c0-1.127.929-2.056 2.056-2.056.26 0 .517.05.758.147A14.985 14.985 0 0 1 59.46 8.879c.407.093.811.202 1.21.328-4.45-.617-9.048.747-12.46 3.5.107.253.162.525.162.799a2.066 2.066 0 0 1-2.056 2.056 2.05 2.05 0 0 1-.733-.136 13.841 13.841 0 0 0-1.863 3.412c1.62 1.746 3.61 3.127 5.83 3.957-.005-.106-.016-.21-.016-.319a6.195 6.195 0 0 1 12.303-1.04 16.065 16.065 0 0 0 4.019-3.669 1.843 1.843 0 0 1-.4 [...]
+ />
+ <path
+ fill="#1287b1"
+ d="M68.54 15.214c.394.35.62.852.622 1.38a1.876 1.876 0 0 1-1.866 1.866 1.85 1.85 0 0 1-.307-.032 15.102 15.102 0 0 1-4.506 4.533 15.09 15.09 0 0 1 7.261 3.263 18.739 18.739 0 0 0 2.379-9.16c0-2.532-1.118-4.387-2.805-5.748a15.01 15.01 0 0 1-.778 3.898M46.054 32.696a15.04 15.04 0 0 1 4.674-6.572 6.186 6.186 0 0 1-.77-1.406 15.025 15.025 0 0 1-6.733-4.26c-.013.057-.03.113-.043.17a13.593 13.593 0 0 0-.232 4.52 2.71 2.71 0 0 1 2.203 2.653c0 .754-.316 1.473-.87 1.984a16.22 [...]
+ />
+ <path
+ fill="#1287b1"
+ d="M45.6 34.192a15.07 15.07 0 0 1-2.739-3.722 2.704 2.704 0 0 1-.41.034h-.004c-1.482 0-2.7-1.219-2.7-2.7 0-1.035.594-1.983 1.526-2.432-.273-2.209-.05-4.45.651-6.561a14.95 14.95 0 0 1-2.612-8.463c0-.115.006-.228.008-.341-2.783 1.395-4.87 3.595-4.87 7.057 0 7.659 4.573 14.245 11.136 17.19l.014-.062m15.976-9.661a6.198 6.198 0 0 1-5.843 4.144 6.17 6.17 0 0 1-3.826-1.327c-2.173 1.692-3.813 3.998-4.814 6.577.45.484.929.941 1.433 1.369 1.555.404 3.154.608 4.76.607 6.617 0 12 [...]
+ />
+ <g transform="translate(43.304 10.642)">
+ <mask id="b" fill="#fff">
+ <use xlinkHref="#a"/>
+ </mask>
+ <path
+ fill="#fff"
+ d="M14.783 6.242 14.704.147l-2.251 5.43L10.576.081l.101 6.472L7.433.753l1.755 6.16-5.262-3.827 4.122 5.18-6.533-2.403 5.156 3.815-6.612.203 6.76 1.745L.053 13.09l6.68.484L1.1 17.18l5.8-2.103-4.024 5.097 5.085-4.101-1.832 6.838 3.926-5.565-.55 6.573 2.228-5.958 1.897 6.262.461-6.281 2.815 5.36-1.663-6.131 5.155 3.993-3.328-5.091 5.656 2.203-4.325-4.25 5.8.456-5.712-2.192 5.727-1.366-5.748-.293 4.678-3.575-5.309 1.903 3.608-5-4.983 3.312 1.743-5.852z"
+ mask="url(#b)"
+ />
+ </g>
+ <image
+ xlinkHref="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAx4AAADpCAYAAACqReECAAAABGdBTUEAALGOfPtRkwAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAADHqADAAQAAAABAAAA6QAAAADa02YqAABAAElEQVR4Ae292XcT19ruq6qS5B4bm76zMQYSDAZ34AYSyPedMc4a5+Jc5a/M7R5f9l5NFknArYwNiUnnhU2T0BuDbdlqStrPKyQjy2qqpKpSSXpqDLBUzWx+s1Q13/l2Hg83EiABEiABEiABEqhRAn19fU1ff/21VqPdZ7dJgARIgARIgARIgARIgATsJjA4ONg4MjLSZXc9LJ8ESIAESIAESIAESIAESMABAjdv3vSiGsWBqgxX0dvb67969eoNXKAavog [...]
+ width={111.814}
+ height={32.542}
+ x={1.822}
+ y={1.682}
+ opacity={0.487}
+ />
+ <path
+ fill="#373535"
+ d="M46.372 6.794c1.704-.331 2.026-4.053 2.026-4.053s.238 2.743 1.43 3.1c1.193.357 2.742-4.291 2.742-4.291s-1.43 4.172 0 4.41c1.43.238 4.053-4.053 4.053-4.053s-1.072 3.695-.358 3.933c.715.239 4.291-5.364 4.291-5.364s-2.145 3.695-.119 4.053c2.027.358 4.984-2.521 4.984-2.521s-2.325 2.634-1.289 2.998c4.412 1.55 7.98-4.183 7.98-4.183s-.827 2.514-2.972 5.256C73.788 7.27 77.24.267 77.24.267L73.788 7.27C75.576 8.224 82.728 0 82.728 0s-3.694 6.436-5.84 7.747c1.192.954 5.483-2. [...]
+ />
+ <path
+ fill="#373535"
+ d="M0 34.76c9.388 4.71 17.97-.714 28.788 2.334 8.224 2.318 18.239 5.176 31.828 3.209 13.589-1.967 25.21-7.867 30.755-18.416 1.728-4.709 8.76 1.072 8.76 1.072s-5.125-2.145-5.006-1.132c.12 1.013 7.689 4.53 7.689 4.53s-6.855-2.146-6.437-.536c.417 1.608 8.583 8.045 8.583 8.045s-9.239-7.033-10.013-6.079c-.775.953 3.933 4.828 3.933 4.828s-7.808-4.828-10.55-3.405c-1.972 1.024 8.106 7.637 8.106 7.637S89.88 31.84 88.33 33.15c-1.55 1.312 7.391 12.04 7.391 12.04S85.588 34.223 84 [...]
+ />
+ </g>
+ </svg>
+ );
+}
+
+export function ActivemqIcon(width: number = 32, height: number = 32) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 30.803 44.324"
+ className="icon" width={width} height={width}>
+ <defs>
+ <filter
+ id="a"
+ width={1.068}
+ height={1.046}
+ x={-0.017}
+ y={-0.011}
+ >
+ <feFlood floodColor="#000" floodOpacity={0.498} result="flood"/>
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ />
+ <feGaussianBlur in="composite1" result="blur" stdDeviation={0.2}/>
+ <feOffset dx={1} dy={1} result="offset"/>
+ <feComposite in="SourceGraphic" in2="offset" result="composite2"/>
+ </filter>
+ </defs>
+ <g
+ style={{
+ display: "inline",
+ }}
+ >
+ <g
+ style={{
+ filter: "url(#a)",
+ }}
+ transform="translate(-39.667 -110.707)"
+ >
+ <path
+ d="m64.697 153.552-8.352-.05-4.133-7.257 4.218-7.208 8.352.049 4.134 7.257z"
+ style={{
+ fill: "#fff",
+ strokeWidth: 0.394699,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ }}
+ />
+ <path
+ d="m52.632 146.553-8.352-.049-4.133-7.257 4.218-7.209 8.352.05 4.134 7.257z"
+ style={{
+ display: "inline",
+ fill: "#fff",
+ strokeWidth: 0.394699,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ }}
+ />
+ <path
+ d="m64.771 139.589-8.352-.05-4.133-7.257 4.218-7.208 8.352.05 4.134 7.257z"
+ style={{
+ display: "inline",
+ fill: "#fff",
+ strokeWidth: 0.394699,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ }}
+ />
+ <path
+ d="m64.765 125.702-8.351-.049-4.134-7.257 4.219-7.209 8.352.05 4.133 7.257z"
+ style={{
+ display: "inline",
+ fill: "#fff",
+ strokeWidth: 0.394699,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ }}
+ />
+ <path
+ d="m52.696 132.676-8.352-.049-4.133-7.257 4.218-7.209 8.352.05 4.133 7.257z"
+ style={{
+ display: "inline",
+ fill: "#fff",
+ strokeWidth: 0.394699,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ }}
+ />
+ </g>
+ </g>
+ <g
+ style={{
+ display: "inline",
+ }}
+ transform="translate(-39.667 -110.707)"
+ >
+ <path
+ d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
+ style={{
+ opacity: 1,
+ fill: "#c12766",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 3,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ transform="matrix(.07206 .01553 -.01553 .07206 -59.031 63.796)"
+ />
+ <path
+ d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
+ style={{
+ opacity: 1,
+ fill: "#3e489f",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 15,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ transform="matrix(.07206 .01553 -.01553 .07206 -71.17 70.76)"
+ />
+ <path
+ d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
+ style={{
+ opacity: 1,
+ fill: "#714099",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 3,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ transform="matrix(.07206 .01553 -.01553 .07206 -59.106 77.758)"
+ />
+ <path
+ d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
+ style={{
+ opacity: 1,
+ fill: "#78932c",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 3,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ transform="matrix(.07206 .01553 -.01553 .07206 -71.106 56.883)"
+ />
+ <path
+ d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
+ style={{
+ opacity: 1,
+ fill: "#cf242a",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 3,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ transform="matrix(.07206 .01553 -.01553 .07206 -59.037 49.91)"
+ />
+ <circle
+ cx={60.564}
+ cy={146.294}
+ r={1.6}
+ style={{
+ opacity: 1,
+ fill: "#fff",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 0.320071,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <path
+ d="m61.748 117.71-14.267 8.174M48.514 124.197l.048 16.442M47.525 138.715l14.136 8.397M60.59 117.133l.048 16.442"
+ style={{
+ fill: "none",
+ fillRule: "evenodd",
+ stroke: "#fff",
+ strokeWidth: 0.523753,
+ strokeLinecap: "butt",
+ strokeLinejoin: "miter",
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <path
+ d="m60.657 131.093.048 16.442"
+ style={{
+ fill: "none",
+ fillRule: "evenodd",
+ stroke: "#fff",
+ strokeWidth: 0.5238,
+ strokeLinecap: "butt",
+ strokeLinejoin: "miter",
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <path
+ d="m61.766 131.708-14.267 8.174M47.564 124.84l14.136 8.398"
+ style={{
+ fill: "none",
+ fillRule: "evenodd",
+ stroke: "#fff",
+ strokeWidth: 0.523753,
+ strokeLinecap: "butt",
+ strokeLinejoin: "miter",
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <circle
+ cx={48.334}
+ cy={139.242}
+ r={1.6}
+ style={{
+ opacity: 1,
+ fill: "#fff",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 0.320071,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <circle
+ cx={60.901}
+ cy={132.486}
+ r={1.6}
+ style={{
+ opacity: 1,
+ fill: "#fff",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 0.320071,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <circle
+ cx={48.563}
+ cy={125.419}
+ r={1.6}
+ style={{
+ opacity: 1,
+ fill: "#fff",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 0.320071,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ <circle
+ cx={60.632}
+ cy={118.445}
+ r={1.6}
+ style={{
+ opacity: 1,
+ fill: "#fff",
+ fillOpacity: 1,
+ stroke: "none",
+ strokeWidth: 0.320071,
+ strokeMiterlimit: 4,
+ strokeDasharray: "none",
+ strokeOpacity: 1,
+ }}
+ />
+ </g>
+ </svg>
+ );
+}
+
+export function KafkaIcon(width: number = 32, height: number = 32) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="-78.5 0 413 413"
+ className="icon" width={width} height={width}>
+ <path
+ fill="#1A1919"
+ d="M87.932 36.714c-4.55-4.571-10.896-7.394-17.951-7.394-7.029 0-13.326 2.823-17.822 7.394h-.13c-4.535 4.55-7.358 10.9-7.358 17.93 0 7.055 2.823 13.352 7.359 17.875l.129.102c4.496 4.55 10.793 7.346 17.822 7.346 7.055 0 13.402-2.797 17.951-7.346L88 72.52c4.558-4.523 7.354-10.82 7.354-17.876 0-7.029-2.796-13.38-7.354-17.929h-.067Zm-17.951 346.64a25.504 25.504 0 0 0 17.951-7.368l.067-.134c4.558-4.487 7.354-10.838 7.354-17.817 0-7.056-2.796-13.38-7.354-17.952h-.067c-4.55-4.625 [...]
+ />
+ </svg>
+ );
+}
+
+export function GrapeIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ viewBox="0 0 512 512"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M438.557 512H19.785c-8.216 0-14.876-6.66-14.876-14.876V256.916c0-8.216 6.66-14.876 14.876-14.876s14.876 6.66 14.876 14.876v225.332h389.021v-32.833c0-8.216 6.661-14.876 14.876-14.876s14.876 6.66 14.876 14.876v47.709c-.001 8.216-6.662 14.876-14.877 14.876z"
+ style={{
+ fill: "#2d527c",
+ }}
+ />
+ <path
+ d="M19.785 177.122v-4.79L175.581 14.876v162.246zM196.154 219.435h296.061v163.65H196.154z"
+ style={{
+ fill: "#cee8fa",
+ }}
+ />
+ <path
+ d="M492.215 204.559h-38.782V14.876C453.433 6.66 446.772 0 438.557 0H175.581c-.182 0-.361.021-.543.027a14.949 14.949 0 0 0-2.41.269c-.018.003-.036.01-.054.013-.613.126-1.211.302-1.8.504-.158.054-.315.11-.472.171-.58.22-1.148.466-1.697.756-.024.012-.048.021-.071.034-.567.305-1.105.66-1.63 1.037a10.84 10.84 0 0 0-.403.302c-.521.402-1.026.827-1.495 1.3L9.21 161.868c-.35.353-.678.721-.988 1.104-.207.254-.388.521-.576.784-.092.131-.195.256-.283.388a15.3 15.3 0 0 0-.592.998c-.04 [...]
+ style={{
+ fill: "#2d527c",
+ }}
+ />
+ <path
+ d="M265.4 270.343c-3.927 0-6.153-4.188-6.153-9.031 0-4.189 1.831-8.771 6.153-8.771h22.907c4.451 0 8.902 2.095 8.902 6.285v59.298c0 22.516-14.269 30.894-31.418 30.894-18.718 0-32.857-9.949-32.857-27.36 0-7.854 3.273-9.687 10.342-9.687 5.236 0 9.687 1.309 10.078 6.153.393 5.105 1.047 13.091 11.521 13.091 7.593 0 11.913-4.188 11.913-13.091v-47.78H265.4v-.001zM304.411 339.854c0-.393.131-.916.262-1.44l24.349-79.853c1.44-4.58 7.331-6.806 13.353-6.806s11.913 2.225 13.353 6.806l2 [...]
+ style={{
+ fill: "#2d527c",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function MachineLearningIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M27 24a2.96 2.96 0 0 0-1.285.3l-4.3-4.3H18v2h2.586l3.715 3.715A2.966 2.966 0 0 0 24 27a3 3 0 1 0 3-3Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 13a2.995 2.995 0 0 0-2.816 2H18v2h6.184A2.995 2.995 0 1 0 27 13Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 2a3.003 3.003 0 0 0-3 3 2.966 2.966 0 0 0 .348 1.373L20.596 10H18v2h3.404l4.4-4.252A2.999 2.999 0 1 0 27 2Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1Z"/>
+ <path
+ d="M18 6h2V4h-2a3.976 3.976 0 0 0-3 1.382A3.976 3.976 0 0 0 12 4h-1a9.01 9.01 0 0 0-9 9v6a9.01 9.01 0 0 0 9 9h1a3.976 3.976 0 0 0 3-1.382A3.976 3.976 0 0 0 18 28h2v-2h-2a2.002 2.002 0 0 1-2-2V8a2.002 2.002 0 0 1 2-2Zm-6 20h-1a7.005 7.005 0 0 1-6.92-6H6v-2H4v-4h3a3.003 3.003 0 0 0 3-3V9H8v2a1 1 0 0 1-1 1H4.08A7.005 7.005 0 0 1 11 6h1a2.002 2.002 0 0 1 2 2v4h-2v2h2v4h-2a3.003 3.003 0 0 0-3 3v2h2v-2a1 1 0 0 1 1-1h2v4a2.002 2.002 0 0 1-2 2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function TerminalIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M26 4.01H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-20a2 2 0 0 0-2-2Zm0 2v4H6v-4Zm-20 20v-14h20v14Z"/>
+ <path d="m10.76 16.18 2.82 2.83-2.82 2.83 1.41 1.41 4.24-4.24-4.24-4.24-1.41 1.41z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function SapIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 1024 1024"
+ className="icon" width="32px" height="32px">
+ <circle
+ cx={512}
+ cy={512}
+ r={512}
+ style={{
+ fill: "#007cc5",
+ }}
+ />
+ <path
+ d="M256 359.88v304.24h310.82L871 359.88zm83.62 56.58h.14c22.11 0 49.06 6.29 68.56 16.22l-21 36.64C365.92 459 355.17 458 343 457.36c-18.14-1-27.26 5.51-27.4 12.5-.18 8.52 17.13 16.23 33.45 21.47 24.7 7.85 56.1 18.33 60.9 48.7l45.15-119.36h52.45l52.88 142.91-.2-142.86H621c57.84 0 85 19.58 85 64.53 0 40.36-28 64.42-75.25 64.42h-19.56l-.19 53.69-92-.09-6.38-23.27a101.65 101.65 0 0 1-31.56 4.83 100.52 100.52 0 0 1-32.32-5.12l-9.19 23.54-51.25.16 2.3-11.84c-.73.64-1.43 1.29-2.2 [...]
+ style={{
+ fill: "#fff",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ScriptIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="m18.83 26 2.58-2.58L20 22l-4 4 4 4 1.42-1.41L18.83 26zM27.17 26l-2.58 2.58L26 30l4-4-4-4-1.42 1.41L27.17 26z"/>
+ <path
+ d="M14 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h6Zm4-23.6 5.6 5.6H18Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ValidationIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="m22 27.18-2.59-2.59L18 26l4 4 8-8-1.41-1.41L22 27.18z"/>
+ <path
+ d="M15 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h7Zm3-23.6 5.6 5.6H18Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function OpenstackIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 -2.5 256 256"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#DA1A32"
+ d="M57.82 170.723v9.156c0 7.104 5.756 12.86 12.86 12.86h114.65c7.104 0 12.86-5.756 12.86-12.86v-9.156H256v56.051c0 13.082-10.703 23.785-23.785 23.785H23.785C10.703 250.559 0 239.856 0 226.774v-56.051h57.82Zm-.01-74.353v57.809H0v-57.81h57.81Zm198.19 0v57.809h-57.81v-57.81H256ZM232.215 0C245.297 0 256 10.703 256 23.795v56.041h-57.81V70.68c0-7.104-5.756-12.86-12.86-12.86H70.67c-7.104 0-12.86 5.756-12.86 12.86v9.156H0V23.785C0 10.703 10.703 0 23.785 0Z"
+ />
+ </svg>
+ );
+}
+
+export function OpenshiftIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 -9.5 256 256"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#DA2430"
+ d="m74.84 106.893-40.869 14.87c.525 6.552 1.652 13.024 3.24 19.366l38.818-14.137c-1.244-6.552-1.689-13.32-1.18-20.1M255.444 61.702c-2.85-5.879-6.147-11.561-9.966-16.916l-40.857 14.87c4.755 4.864 8.743 10.33 12.007 16.176L255.445 61.7v.002Z"
+ />
+ <path
+ fill="#DA2430"
+ d="M182.95 61.461c-5.14-4.46-10.946-8.31-17.408-11.324h-.003C127.6 32.449 82.33 48.905 64.642 86.859a73.976 73.976 0 0 0-2.653 6.487c-2.208 6.423-3.498 12.99-3.991 19.546l-.144.054-.011.144-24.596 8.95-15.826 5.849-.007-.088-.434.158c-1.536-19.435 1.74-39.512 10.553-58.411a117.952 117.952 0 0 1 3.687-7.246c29.054-54.116 95.164-76.736 150.918-50.33a115.314 115.314 0 0 1 30.557 21.074 116.597 116.597 0 0 1 15.78 17.94L187.618 65.86a79.69 79.69 0 0 0-.635-.641l-.113.041a78.6 [...]
+ />
+ <path
+ fill="#E82429"
+ d="m19.261 193.896-.064.024A118.404 118.404 0 0 1 .939 154.347l38.825-14.14.002.003.024.125.252-.093.006.015c1.994 10.56 6.145 20.635 12.198 29.494a75.287 75.287 0 0 0 7.722 9.326l-.154.057.294.308-40.488 14.97c-.12-.171-.24-.343-.359-.516Z"
+ />
+ <path
+ fill="#DA2430"
+ d="M173.465 183.447c-21.051 13.017-48.053 15.532-72.113 4.312a75.139 75.139 0 0 1-22.118-15.695l-40.772 14.844.313.437-.02.008c11.21 16.016 26.502 29.404 45.266 38.298 40.47 19.163 86.387 12.501 119.634-13.284 14.888-11.152 27.317-26.016 35.713-44.02 8.819-18.895 12.076-38.964 10.515-58.384l-1.136.414c-.015-.208-.03-.416-.047-.624l-40.49 14.957.002.004a76.457 76.457 0 0 1-6.806 26.46c-6.315 13.753-16.164 24.708-27.94 32.273Z"
+ />
+ <path
+ fill="#E82429"
+ d="m218.552 75.13.607-.222v-.001a117.732 117.732 0 0 1 11.454 42.055l-40.773 14.834.022-.304-.77.285c1.11-15.088-2.275-30.093-9.435-43.123l38.548-14.25.002-.004c.116.243.231.486.345.73Z"
+ />
+ <path
+ fill="#C22035"
+ d="M74.89 106.654 34.31 121.65c.52 6.61 1.64 13.136 3.219 19.532l38.546-14.258c-1.247-6.622-1.695-13.438-1.169-20.274M254.227 61.083c-2.83-5.929-6.106-11.658-9.898-17.059L203.76 59.02c4.72 4.906 8.68 10.418 11.92 16.315l38.542-14.256.006.004Z"
+ />
+ <path
+ fill="#AC223B"
+ d="m34.308 121.653 40.482-14.829-.165 8.133-39.056 14.749-1.266-8.063.005.01ZM203.766 58.897l41.113-14.108 4.273 6.449-39.946 14.121-5.434-6.465-.006.003Z"
+ />
+ <path
+ fill="#B92135"
+ d="m38.764 187.201 40.53-14.749 12.258 11.565-42.503 15.956-10.283-12.776-.002.004ZM249.38 109.862l-41.165 14.844-3.032 16.478 43.892-15.643.311-15.677-.005-.002Z"
+ />
+ </svg>
+ );
+}
+
+export function RefIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M4 20v2h4.586L2 28.586 3.414 30 10 23.414V28h2v-8H4zM30 30h-8v-8h8Zm-6-2h4v-4h-4ZM20 20h-8v-8h8Zm-6-2h4v-4h-4Z"/>
+ <path d="M24 17h-2v-2h2a4 4 0 0 0 0-8H12V5h12a6 6 0 0 1 0 12ZM10 10H2V2h8ZM4 8h4V4H4Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function RedisIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 -18 256 256"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#912626"
+ d="M245.97 168.943c-13.662 7.121-84.434 36.22-99.501 44.075-15.067 7.856-23.437 7.78-35.34 2.09-11.902-5.69-87.216-36.112-100.783-42.597C3.566 169.271 0 166.535 0 163.951v-25.876s98.05-21.345 113.879-27.024c15.828-5.679 21.32-5.884 34.79-.95 13.472 4.936 94.018 19.468 107.331 24.344l-.006 25.51c.002 2.558-3.07 5.364-10.024 8.988"
+ />
+ <path
+ fill="#C6302B"
+ d="M245.965 143.22c-13.661 7.118-84.431 36.218-99.498 44.072-15.066 7.857-23.436 7.78-35.338 2.09-11.903-5.686-87.214-36.113-100.78-42.594-13.566-6.485-13.85-10.948-.524-16.166 13.326-5.22 88.224-34.605 104.055-40.284 15.828-5.677 21.319-5.884 34.789-.948 13.471 4.934 83.819 32.935 97.13 37.81 13.316 4.881 13.827 8.9.166 16.02"
+ />
+ <path
+ fill="#912626"
+ d="M245.97 127.074c-13.662 7.122-84.434 36.22-99.501 44.078-15.067 7.853-23.437 7.777-35.34 2.087-11.903-5.687-87.216-36.112-100.783-42.597C3.566 127.402 0 124.67 0 122.085V96.206s98.05-21.344 113.879-27.023c15.828-5.679 21.32-5.885 34.79-.95C162.142 73.168 242.688 87.697 256 92.574l-.006 25.513c.002 2.557-3.07 5.363-10.024 8.987"
+ />
+ <path
+ fill="#C6302B"
+ d="M245.965 101.351c-13.661 7.12-84.431 36.218-99.498 44.075-15.066 7.854-23.436 7.777-35.338 2.087-11.903-5.686-87.214-36.112-100.78-42.594-13.566-6.483-13.85-10.947-.524-16.167C23.151 83.535 98.05 54.148 113.88 48.47c15.828-5.678 21.319-5.884 34.789-.949 13.471 4.934 83.819 32.933 97.13 37.81 13.316 4.88 13.827 8.9.166 16.02"
+ />
+ <path
+ fill="#912626"
+ d="M245.97 83.653c-13.662 7.12-84.434 36.22-99.501 44.078-15.067 7.854-23.437 7.777-35.34 2.087-11.903-5.687-87.216-36.113-100.783-42.595C3.566 83.98 0 81.247 0 78.665v-25.88s98.05-21.343 113.879-27.021c15.828-5.68 21.32-5.884 34.79-.95C162.142 29.749 242.688 44.278 256 49.155l-.006 25.512c.002 2.555-3.07 5.361-10.024 8.986"
+ />
+ <path
+ fill="#C6302B"
+ d="M245.965 57.93c-13.661 7.12-84.431 36.22-99.498 44.074-15.066 7.854-23.436 7.777-35.338 2.09C99.227 98.404 23.915 67.98 10.35 61.497-3.217 55.015-3.5 50.55 9.825 45.331 23.151 40.113 98.05 10.73 113.88 5.05c15.828-5.679 21.319-5.883 34.789-.948 13.471 4.935 83.819 32.934 97.13 37.811 13.316 4.876 13.827 8.897.166 16.017"
+ />
+ <path
+ fill="#FFF"
+ d="m159.283 32.757-22.01 2.285-4.927 11.856-7.958-13.23-25.415-2.284 18.964-6.839-5.69-10.498 17.755 6.944 16.738-5.48-4.524 10.855 17.067 6.391M131.032 90.275 89.955 73.238l58.86-9.035-17.783 26.072M74.082 39.347c17.375 0 31.46 5.46 31.46 12.194 0 6.736-14.085 12.195-31.46 12.195s-31.46-5.46-31.46-12.195c0-6.734 14.085-12.194 31.46-12.194"
+ />
+ <path
+ fill="#621B1C"
+ d="m185.295 35.998 34.836 13.766-34.806 13.753-.03-27.52"
+ />
+ <path
+ fill="#9A2928"
+ d="m146.755 51.243 38.54-15.245.03 27.519-3.779 1.478-34.791-13.752"
+ />
+ </svg>
+ );
+}
+
+export function SearchIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="m29 27.586-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9 9.01 9.01 0 0 1-9-9Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function BlockchainIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="M6 24H4V8h2ZM28 8h-2v16h2Zm-4-2V4H8v2Zm0 22v-2H8v2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ChatIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M17.74 30 16 29l4-7h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h9v2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4h20a4 4 0 0 1 4 4v12a4 4 0 0 1-4 4h-4.84Z"/>
+ <path d="M8 10h16v2H8zM8 16h10v2H8z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function WorkflowIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ viewBox="0 0 512 512"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M445.66 49.341H340.206L294.008 3.143c-4.192-4.191-10.99-4.191-15.183 0l-49.341 49.342c-4.192 4.192-4.192 10.99 0 15.183l46.198 46.198v38.494h-80.516c-5.929 0-10.736 4.806-10.736 10.735v21.471h-42.942v-21.471c0-5.929-4.806-10.735-10.736-10.735H66.34c-5.929 0-10.735 4.806-10.735 10.735v64.413c0 5.929 4.806 10.735 10.735 10.735h20.755v93.798c0 5.929 4.806 10.736 10.735 10.736h95.437l-10.346 10.346c-4.192 4.192-4.193 10.99 0 15.182a10.7 10.7 0 0 0 7.591 3.144c2.747 0 5.495 [...]
+ </svg>
+ );
+}
+
+export function WebserviceIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M25.829 13.116A10.02 10.02 0 0 0 16 5v2a8.023 8.023 0 0 1 7.865 6.493l.259 1.346 1.349.245A5.502 5.502 0 0 1 24.508 26H16v2h8.508a7.502 7.502 0 0 0 1.32-14.884ZM8 24h6v2H8zM4 24h2v2H4zM6 20h8v2H6zM2 20h2v2H2zM8 16h6v2H8zM4 16h2v2H4zM10 12h4v2h-4zM6 12h2v2H6zM12 8h2v2h-2z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function MobileIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="M23 7h4v4h-4zM23 13h4v4h-4zM17 7h4v4h-4zM17 13h4v4h-4z"/>
+ <circle cx={14.5} cy={24.5} r={1.5}/>
+ <path
+ d="M21 30H8a2.002 2.002 0 0 1-2-2V4a2.002 2.002 0 0 1 2-2h13v2H8v24h13v-8h2v8a2.002 2.002 0 0 1-2 2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ClusterIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M16 7a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM11 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM7 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM21 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM25 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM4 21a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 [...]
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function RpcIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path d="m14 26 1.41-1.41L7.83 17H28v-2H7.83l7.58-7.59L14 6 4 16l10 10z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function InfinispanIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ id="artwork"
+ viewBox="0 0 1024 1024"
+ className="icon" width="32px" height="32px">
+ <defs>
+ <style>{".cls-2{fill:#fff}"}</style>
+ </defs>
+ <path
+ d="M1 1h1022v1022H1z"
+ style={{
+ fill: "#599fc6",
+ }}
+ />
+ <path
+ d="M566.84 512c0-221.39-179.47-400.86-400.86-400.86v109.68c160.56 0 291.18 130.62 291.18 291.18 0 221.39 179.47 400.86 400.86 400.86V803.18c-160.56 0-291.18-130.62-291.18-291.18Z"
+ className="cls-2"
+ />
+ <path
+ d="M436.76 618.86C394.05 726.69 288.82 803.18 166 803.18v109.68c134.26 0 253-66.07 325.76-167.4a432.16 432.16 0 0 1-55-126.6ZM587.24 405.14C630 297.31 735.19 220.82 858 220.82V111.14c-134.26 0-253 66.07-325.77 167.4a431.92 431.92 0 0 1 55.01 126.6Z"
+ className="cls-2"
+ />
+ </svg>
+ );
+}
+
+export function TransformationIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2ZM2 6h6v2H2zM2 2h8v2H2z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function TestingIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M28 17v5H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-5ZM18 28h-4v-4h4Z"/>
+ <path
+ d="M30 10V8h-2.101a4.968 4.968 0 0 0-.732-1.753l1.49-1.49-1.414-1.414-1.49 1.49A4.968 4.968 0 0 0 24 4.101V2h-2v2.101a4.968 4.968 0 0 0-1.753.732l-1.49-1.49-1.414 1.414 1.49 1.49A4.968 4.968 0 0 0 18.101 8H16v2h2.101a4.968 4.968 0 0 0 .732 1.753l-1.49 1.49 1.414 1.414 1.49-1.49a4.968 4.968 0 0 0 1.753.732V16h2v-2.101a4.968 4.968 0 0 0 1.753-.732l1.49 1.49 1.414-1.414-1.49-1.49A4.968 4.968 0 0 0 27.899 10Zm-7 2a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ApiIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M26 22a3.86 3.86 0 0 0-2 .57l-3.09-3.1a6 6 0 0 0 0-6.94L24 9.43a3.86 3.86 0 0 0 2 .57 4 4 0 1 0-4-4 3.86 3.86 0 0 0 .57 2l-3.1 3.09a6 6 0 0 0-6.94 0L9.43 8A3.86 3.86 0 0 0 10 6a4 4 0 1 0-4 4 3.86 3.86 0 0 0 2-.57l3.09 3.1a6 6 0 0 0 0 6.94L8 22.57A3.86 3.86 0 0 0 6 22a4 4 0 1 0 4 4 3.86 3.86 0 0 0-.57-2l3.1-3.09a6 6 0 0 0 6.94 0l3.1 3.09a3.86 3.86 0 0 0-.57 2 4 4 0 1 0 4-4Zm0-18a2 2 0 1 1-2 2 2 2 0 0 1 2-2ZM4 6a2 2 0 1 1 2 2 2 2 0 0 1-2-2Zm2 22a2 2 0 1 1 2-2 2 2 0 0 1-2 [...]
+ <path
+ d="M0 0h32v32H0z"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function KameletIcon() {
+ return (
+ <svg
+ className="icon" id="icon"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ >
+ <path d="M16 18H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2ZM6 6v10h10V6ZM26 12v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM26 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM16 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2Z" />
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ )
+}
+
+export function CouchbaseIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={800}
+ height={800}
+ viewBox="0 0 256 256"
+ className="icon"
+ >
+ <path
+ fill="#ED2226"
+ d="M128 0C57.426 0 0 57.233 0 128c0 70.574 57.233 128 128 128 70.574 0 128-57.233 128-128S198.574 0 128 0Zm86.429 150.429c0 7.734-4.447 14.502-13.148 16.048-15.082 2.707-46.792 4.254-73.281 4.254-26.49 0-58.2-1.547-73.281-4.254-8.7-1.546-13.148-8.314-13.148-16.048v-49.885c0-7.734 5.994-14.888 13.148-16.049 4.447-.773 14.888-1.546 23.01-1.546 3.093 0 5.606 2.32 5.606 5.994v34.997l44.858-.967 44.858.967V88.943c0-3.674 2.514-5.994 5.608-5.994 8.12 0 18.562.773 23.009 1.546 7 [...]
+ />
+ </svg>
+ );
+}
+
+export function TwilioIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={800}
+ height={800}
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 0 256 256"
+ className="icon"
+ >
+ <path
+ fill="#F12E45"
+ d="M128 0c70.656 0 128 57.344 128 128s-57.344 128-128 128S0 198.656 0 128 57.344 0 128 0Zm0 33.792c-52.224 0-94.208 41.984-94.208 94.208S75.776 222.208 128 222.208s94.208-41.984 94.208-94.208S180.224 33.792 128 33.792Zm31.744 99.328c14.704 0 26.624 11.92 26.624 26.624 0 14.704-11.92 26.624-26.624 26.624-14.704 0-26.624-11.92-26.624-26.624 0-14.704 11.92-26.624 26.624-26.624Zm-63.488 0c14.704 0 26.624 11.92 26.624 26.624 0 14.704-11.92 26.624-26.624 26.624-14.704 0-26.624- [...]
+ />
+ </svg>
+ );
+}
+
+export function TwitterIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={800}
+ height={800}
+ viewBox="-0.25 -104.25 1109.5 1109.5"
+ className="icon"
+ >
+ <path
+ fill="#5da8dc"
+ stroke="#5da8dc"
+ strokeWidth={0.5}
+ d="M741 .2V0h52l19 3.8c12.667 2.467 24.167 5.7 34.5 9.7 10.334 4 20.334 8.667 30 14 9.667 5.333 18.434 10.767 26.301 16.3 7.8 5.467 14.8 11.267 21 17.4C929.933 67.4 939.5 69 952.5 66s27-7.167 42-12.5 29.834-11.333 44.5-18c14.667-6.667 23.601-10.9 26.801-12.7 3.133-1.866 4.8-2.866 5-3l.199-.3 1-.5 1-.5 1-.5 1-.5.2-.3.3-.2.301-.2.199-.3 1-.3 1-.2-.199 1.5-.301 1.5-.5 1.5-.5 1.5-.5 1-.5 1-.5 1.5c-.333 1-.666 2.333-1 4-.333 1.667-3.5 8.333-9.5 20S1051 73 1042 85s-17.066 21.06 [...]
+ />
+ <path
+ fill="#fff"
+ stroke="#fff"
+ strokeWidth={0.5}
+ d="M0 399V0h741v.2c0 .2-4.333.966-13 2.3-8.666 1.333-19.333 4.167-32 8.5-12.666 4.333-26.5 10.667-41.5 19s-28.333 17.833-40 28.5c-11.666 10.667-21.166 21-28.5 31-7.333 10-13.266 18.9-17.8 26.7-4.466 7.866-9.033 18.3-13.7 31.3-4.666 13-8.166 25.833-10.5 38.5-2.333 12.667-3.5 26.5-3.5 41.5s.667 26.667 2 35l2 12.5.301 1.5.199 1.5-7-.2c-4.666-.2-13.333-.966-26-2.3-12.666-1.333-31.5-4.333-56.5-9s-42.666-8.5-53-11.5c-10.333-3-28.333-9.333-54-19-25.666-9.667-49.666-20.5-72-32.5- [...]
+ />
+ </svg>
+ );
+}
+
+export function MonitoringIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6ZM18 28h-4v-4h4Z"/>
+ <path
+ d="M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76 3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04-3.082 10.018A1 1 0 0 1 18 18Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function NetworkingIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ viewBox="0 0 511.984 511.984"
+ className="icon" width="32px" height="32px">
+ <path
+ d="M207.29 287.991H48.735C30.687 287.991 16 302.375 16 320.054v111.868c0 17.679 14.688 32.063 32.735 32.063H207.29c18.031 0 32.703-14.384 32.703-32.063V320.054c0-17.679-14.672-32.063-32.703-32.063zm0 143.996-159.291-.064.736-111.932 159.259.064.048 111.645c0 .015-.192.287-.752.287z"/>
+ <path
+ d="M383.988 239.992H127.996c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-31.999h223.993v31.999c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c0-8.832-7.167-16-15.999-16z"/>
+ <path
+ d="M463.25 287.991H304.727c-18.047 0-32.735 14.384-32.735 32.063v111.868c0 17.679 14.688 32.063 32.735 32.063H463.25c18.047 0 32.735-14.384 32.735-32.063V320.054c-.001-17.679-14.688-32.063-32.735-32.063zm0 143.996-159.259-.064.736-111.932 159.259.064.064 111.645c-.016-.001-.208.287-.8.287zM415.987 479.985h-63.998c-8.832 0-16 7.168-16 16s7.168 16 16 16h63.998c8.832 0 16-7.168 16-16s-7.168-16-16-16zM335.253 0H176.73c-18.047 0-32.735 14.384-32.735 32.063v111.869c0 17.679 14. [...]
+ <path
+ d="M255.992 191.994c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c.001-8.832-7.167-16-15.999-16z"/>
+ </svg>
+ );
+}
+
+export function HealthIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ id="Icons"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <style>
+ {
+ ".st0{fill:none;stroke:#000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}"
+ }
+ </style>
+ <path
+ d="M27 7h0c-2.6-2.7-6.9-2.7-9.5 0l-1.3 1.4c-.1.1-.4.1-.5 0L14.4 7C11.8 4.3 7.6 4.3 5 7h0c-2.6 2.7-2.6 7.1 0 9.8l1.6 1.6 9.2 9.5c.1.1.4.1.5 0l9.2-9.5 1.6-1.6c2.6-2.7 2.6-7.1-.1-9.8z"
+ className="st0"
+ />
+ <path d="M9 15h3l2-2 2 4 2-5 2 3h3" className="st0"/>
+ </svg>
+ );
+}
+
+export function KubernetesIcon(className?: string) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 -10.44 722.846 722.846"
+ className={className ? className + " icon" : "icon"}
+ width="32px" height="32px">
+ <path
+ fill="#326ce5"
+ d="M358.986 10.06a46.725 46.342 0 0 0-17.906 4.531L96.736 131.341a46.725 46.342 0 0 0-25.28 31.438l-60.282 262.25a46.725 46.342 0 0 0 6.344 35.531 46.725 46.342 0 0 0 2.656 3.688l169.125 210.28a46.725 46.342 0 0 0 36.531 17.438l271.219-.062a46.725 46.342 0 0 0 36.531-17.406l169.063-210.313a46.725 46.342 0 0 0 9.03-39.219L651.3 162.716a46.725 46.342 0 0 0-25.281-31.437L381.643 14.59a46.725 46.342 0 0 0-22.657-4.53z"
+ />
+ <path
+ fill="#fff"
+ stroke="#fff"
+ strokeWidth={0.25}
+ d="M361.408 99.307c-8.077.001-14.626 7.276-14.625 16.25 0 .138.028.27.03.406-.011 1.22-.07 2.689-.03 3.75.192 5.176 1.32 9.138 2 13.907 1.23 10.206 2.26 18.667 1.625 26.531-.62 2.965-2.803 5.677-4.75 7.562l-.344 6.188a190.337 190.337 0 0 0-26.438 4.062c-37.974 8.623-70.67 28.184-95.562 54.594a245.167 245.167 0 0 1-5.281-3.75c-2.612.353-5.25 1.159-8.688-.844-6.545-4.405-12.506-10.486-19.719-17.812-3.305-3.504-5.698-6.841-9.625-10.219-.891-.767-2.252-1.804-3.25-2.594-3.07-2 [...]
+ color="#000"
+ fontFamily="Sans"
+ fontWeight={400}
+ overflow="visible"
+ style={{
+ textIndent: 0,
+ textAlign: "start",
+ lineHeight: "normal",
+ textTransform: "none",
+ marker: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function DocumentIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <path
+ d="m25.7 9.3-7-7A.908.908 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h16a2.006 2.006 0 0 0 2-2V10a.908.908 0 0 0-.3-.7ZM18 4.4l5.6 5.6H18ZM24 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function GitIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#000"
+ fillRule="evenodd"
+ d="M13.414 3.828a2 2 0 0 0-2.828 0l-.672.672 1.568 1.568a2.002 2.002 0 0 1 2.45 2.45l2.05 2.05a2 2 0 1 1-1.414 1.414L13 10.414v4.854A2 2 0 0 1 12 19a2 2 0 0 1-1-3.732V9.732a2 2 0 0 1-.932-2.25L8.5 5.914l-4.672 4.672a2 2 0 0 0 0 2.828l6.758 6.758a2 2 0 0 0 2.828 0l6.758-6.758a2 2 0 0 0 0-2.828l-6.758-6.758ZM9.172 2.414a4 4 0 0 1 5.656 0l6.758 6.758a4 4 0 0 1 0 5.656l-6.758 6.758a4 4 0 0 1-5.656 0l-6.758-6.758a4 4 0 0 1 0-5.656l6.758-6.758Z"
+ clipRule="evenodd"
+ />
+ </svg>
+ );
+}
+
+export function SocialIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 1024 1024"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#FFB89A"
+ d="M570.2 842c-50.6 0-278.7-180-278.7-401.9 0-58.8-2.9-133.1-1-183.9-50.8 3.2-91.4 45.7-91.4 97.3v272.1c37.4 194.7 137.5 334 255.2 334 69.5 0 132.9-48.6 180.9-128.5-20.8 7.1-42.6 10.9-65 10.9z"
+ />
+ <path
+ fill="#4E5155"
+ d="M926.1 191.8C900.5 74.1 817.9 62.1 704.9 62.1c-29.1 0-60.3.8-93 .8-36 0-70.5-1.1-102.5-1.1-109.7 0-189.8 12.5-201.3 123.7-20.4 198.3 30 617.1 306.1 617.1S939 414.3 926.1 191.8zm-76.9 268.5c-9.5 47.9-22.3 90.8-38.1 127.7-16.8 39.2-37 71.4-60 95.8-37.3 39.5-82.1 58.7-137 58.7-53.4 0-97.6-20.1-134.9-61.6-45.5-50.5-79.8-131.5-99-234.2-15.6-83.5-20.3-178.9-12.4-255.2 1.8-17.3 5.7-30.7 11.6-39.8 4.4-6.8 10.1-11.7 18.7-15.8 25.8-12.5 70.8-14.2 111.4-14.2 15 0 30.7.2 47.3.5 17 [...]
+ />
+ <path
+ fill="#4E5155"
+ d="M532 841.7c-32.5 22.3-70.6 33.7-113.2 33.7-29.7 0-57.3-6-82.1-17.7-23.2-11-44.7-27.4-63.9-48.7-46-50.9-80.3-131.3-99.2-232.4-15.1-80.6-19.6-172.9-12-246.8 3-29.5 12-50.2 27.5-63.2 14.2-12 35.1-19.2 65.8-22.9 16.5-2 28.2-16.9 26.3-33.3-2-16.5-16.9-28.2-33.3-26.3-42.9 5.1-73.8 16.7-97.4 36.5-27.9 23.5-43.8 57.2-48.5 103-8.2 79.3-3.4 178.1 12.7 264 9.7 51.9 23.4 99.4 40.6 141.2 19.8 48.1 44.4 88.6 73 120.4 51.6 57.2 115.7 86.2 190.6 86.2 55 0 104.5-14.9 147.2-44.2 13.7-9. [...]
+ />
+ <path
+ fill="#3C9"
+ d="M519.7 248.5c-16.6 0-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3c0-16.6-13.5-30-30-30zm-220.2 137c0-16.6-13.4-30-30-30s-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3zm455.1-137c-16.6 0-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3c0-16.6-13.4-30-30-30zm-37.9 306c0-16.6-13.4-30-30-30H551v30c0 58.5 38.1 123.7 92.8 123.7 22.9 0 45-11.9 62.2-33.6 10.3-13 8.1-31.9-4.9-42.1-13-10.3-31.9-8.1-42.1 4.9-5.3 6.7-11.1 10.9-15.1 10.9-4.3 [...]
+ />
+ </svg>
+ );
+}
+
+export function DebeziumIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ viewBox="0 0 130.93 130.93"
+ className="icon" width="32px" height="32px">
+ <defs>
+ <linearGradient
+ id="linear-gradient"
+ x1={19.74}
+ x2={114.03}
+ y1={19.73}
+ y2={114.02}
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop offset={0} stopColor="#91d443"/>
+ <stop offset={1} stopColor="#48bfe0"/>
+ </linearGradient>
+ <linearGradient
+ xlinkHref="#linear-gradient"
+ id="linear-gradient-2"
+ x1={43.19}
+ x2={137.48}
+ y1={-3.72}
+ y2={90.57}
+ />
+ <linearGradient
+ xlinkHref="#linear-gradient"
+ id="linear-gradient-3"
+ x1={66.56}
+ x2={160.85}
+ y1={-27.09}
+ y2={67.2}
+ />
+ <linearGradient
+ xlinkHref="#linear-gradient"
+ id="linear-gradient-4"
+ x1={-3.72}
+ x2={90.57}
+ y1={43.18}
+ y2={137.47}
+ />
+ <linearGradient
+ xlinkHref="#linear-gradient"
+ id="linear-gradient-5"
+ x1={-27.09}
+ x2={67.2}
+ y1={66.55}
+ y2={160.84}
+ />
+ <style>{".cls-1{fill:#fff}"}</style>
+ </defs>
+ <g id="Layer_1" data-name="Layer 1">
+ <path
+ d="M93.79 114.29a16.65 16.65 0 0 0 16.63 16.63h20.53v-20.53a16.65 16.65 0 0 0-16.63-16.63h-3.91A26.39 26.39 0 0 1 84 67.4v-3.89a16.65 16.65 0 0 0-16.59-16.62h-3.9a26.39 26.39 0 0 1-26.35-26.37v-3.9A16.65 16.65 0 0 0 20.53 0H0v20.52a16.65 16.65 0 0 0 16.63 16.63h3.91A26.39 26.39 0 0 1 46.9 63.51v3.89A16.65 16.65 0 0 0 63.53 84h3.9a26.39 26.39 0 0 1 26.36 26.36Z"
+ style={{
+ fill: "url(#linear-gradient)",
+ }}
+ />
+ <path
+ d="M130.94 63.51a16.65 16.65 0 0 0-16.63-16.63h-3.91A26.39 26.39 0 0 1 84 20.52v-3.9A16.65 16.65 0 0 0 67.41 0H46.9v20.75a16.64 16.64 0 0 0 16.62 16.4h3.91a26.39 26.39 0 0 1 26.36 26.36v3.89A16.65 16.65 0 0 0 110.36 84h20.58Z"
+ style={{
+ fill: "url(#linear-gradient-2)",
+ }}
+ />
+ <path
+ d="M130.94 16.49A16.63 16.63 0 0 0 115 0H93.47v20.7a16.64 16.64 0 0 0 16.62 16.44h20.85Z"
+ style={{
+ fill: "url(#linear-gradient-3)",
+ }}
+ />
+ <path
+ d="M0 67.44a16.65 16.65 0 0 0 16.64 16.62h3.91a26.39 26.39 0 0 1 26.36 26.36v3.89a16.65 16.65 0 0 0 16.63 16.63H84v-20.75A16.64 16.64 0 0 0 67.43 93.8h-3.9a26.39 26.39 0 0 1-26.37-26.36v-3.9a16.65 16.65 0 0 0-16.57-16.63H0Z"
+ style={{
+ fill: "url(#linear-gradient-4)",
+ }}
+ />
+ <path
+ d="M0 114.45a16.63 16.63 0 0 0 16 16.5h21.48v-20.71A16.64 16.64 0 0 0 20.86 93.8H0Z"
+ style={{
+ fill: "url(#linear-gradient-5)",
+ }}
+ />
+ </g>
+ </svg>
+ );
+}
+
+export function IgniteIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 48 48"
+ className="icon" width="32px" height="32px">
+ <path
+ fill="#ED1C24"
+ d="M7.686 8.136S-8.95 18.28 6.73 28.355c3.016 1.962 13.956 7.418 13.644 12.466 0 0 6.631-9.81-3.064-15.983C7.351 18.52 4.862 11.772 7.686 8.135Z"
+ />
+ <path
+ fill="#ED1C24"
+ d="M1.893 27.517s-5.936 8.997 5.745 10.84c1.15.144 9.6 1.029 11.802 3.804 0 0-.192-4.785-7.086-7.609-6.87-2.823-9.695-3.517-10.46-7.035Zm22.981-9.451C17.74 10.6 15.754 5.982 18.818 0c0 0-21.281 8.183-.264 22.708 7.517 5.192 6.272 10.504 6.272 10.696 1.173-1.22 7.181-7.873.048-15.338Z"
+ />
+ </svg>
+ );
+}
+
+export function HazelcastIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 133.3 133.3" className="icon" width="32px" height="32px">
+ <defs>
+ <style>{".a{fill:#00e1e1}"}</style>
+ </defs>
+ <path
+ d="M133.3 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.93v.38c0 6.07-6.42 12.49-12.49 12.49h-.38v.93h.36c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM26.66 12.86h-.38C20.21 12.86 13.8 6.45 13.8.38V0h-.94v.38c0 6.07-6.41 12.48-12.48 12.48H0v.94h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.94Z"
+ className="a"
+ />
+ <path
+ d="M26.66 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.53v-.38h-.94V27c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
+ className="a"
+ />
+ <path
+ d="M53.32 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94V27c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM26.66 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
+ className="a"
+ />
+ <path
+ d="M53.32 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
+ className="a"
+ />
+ <path
+ d="M80 66.19h-.4c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.4v-.93ZM26.66 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.94v.38c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
+ className="a"
+ />
+ <path
+ d="M53.32 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM106.64 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93V27c0 6.07-6.42 12.49-12.49 12.49H80v.93h.38c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM106.64 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93v.38c0 6.07-6.42 12.49-12.49 12.49H80v.93h. [...]
+ className="a"
+ />
+ <path
+ d="M106.64 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.93v.38c0 6.07-6.42 12.49-12.49 12.49H80v.93h.38c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM133.3 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93V27c0 6.07-6.42 12.49-12.49 12.49h-.38v.93h.36c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM133.3 12.86h-.38c-6.07 0-12.48-6.41-12.48-12.48V0h-.93v.38c0 6.07-6.42 12.48-12.49 12.48h-.38v.94h.3 [...]
+ className="a"
+ />
+ </svg>
+ );
+}
+
+export function AzureIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 96 96"
+ className="icon" width="32px" height="32px">
+ <defs>
+ <linearGradient
+ id="a"
+ x1={-1032.172}
+ x2={-1059.213}
+ y1={145.312}
+ y2={65.426}
+ gradientTransform="matrix(1 0 0 -1 1075 158)"
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop offset={0} stopColor="#114a8b"/>
+ <stop offset={1} stopColor="#0669bc"/>
+ </linearGradient>
+ <linearGradient
+ id="b"
+ x1={-1023.725}
+ x2={-1029.98}
+ y1={108.083}
+ y2={105.968}
+ gradientTransform="matrix(1 0 0 -1 1075 158)"
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop offset={0} stopOpacity={0.3}/>
+ <stop offset={0.071} stopOpacity={0.2}/>
+ <stop offset={0.321} stopOpacity={0.1}/>
+ <stop offset={0.623} stopOpacity={0.05}/>
+ <stop offset={1} stopOpacity={0}/>
+ </linearGradient>
+ <linearGradient
+ id="c"
+ x1={-1027.165}
+ x2={-997.482}
+ y1={147.642}
+ y2={68.561}
+ gradientTransform="matrix(1 0 0 -1 1075 158)"
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop offset={0} stopColor="#3ccbf4"/>
+ <stop offset={1} stopColor="#2892df"/>
+ </linearGradient>
+ </defs>
+ <path
+ fill="url(#a)"
+ d="M33.338 6.544h26.038l-27.03 80.087a4.152 4.152 0 0 1-3.933 2.824H8.149a4.145 4.145 0 0 1-3.928-5.47L29.404 9.368a4.152 4.152 0 0 1 3.934-2.825z"
+ />
+ <path
+ fill="#0078d4"
+ d="M71.175 60.261h-41.29a1.911 1.911 0 0 0-1.305 3.309l26.532 24.764a4.171 4.171 0 0 0 2.846 1.121h23.38z"
+ />
+ <path
+ fill="url(#b)"
+ d="M33.338 6.544a4.118 4.118 0 0 0-3.943 2.879L4.252 83.917a4.14 4.14 0 0 0 3.908 5.538h20.787a4.443 4.443 0 0 0 3.41-2.9l5.014-14.777 17.91 16.705a4.237 4.237 0 0 0 2.666.972H81.24L71.024 60.261l-29.781.007L59.47 6.544z"
+ />
+ <path
+ fill="url(#c)"
+ d="M66.595 9.364a4.145 4.145 0 0 0-3.928-2.82H33.648a4.146 4.146 0 0 1 3.928 2.82l25.184 74.62a4.146 4.146 0 0 1-3.928 5.472h29.02a4.146 4.146 0 0 0 3.927-5.472z"
+ />
+ </svg>
+ );
+}
+
+
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/EipIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/EipIcons.tsx
new file mode 100644
index 00000000..4bdac684
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/EipIcons.tsx
@@ -0,0 +1,293 @@
+/*
+ * 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';
+
+export function LoadBalanceIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="32px" height="32px">
+ <path
+ d="M4 26h4v4H4zM14 26h4v4h-4zM24 26h4v4h-4zM25 16h-8v-2h-2v2H7a2.002 2.002 0 0 0-2 2v6h2v-6h8v6h2v-6h8v6h2v-6a2.002 2.002 0 0 0-2-2ZM9 2v10h14V2Zm2 2h2v6h-2Zm10 6h-6V4h6Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function AggregateIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M496.2 417.71l-130.22 101.1c-.19.14-.39.29-.59.42a28.39 28.39 0 01-30.77 0c-.21-.13-.4-.28-.59-.42L203.8 417.71h292.4z"></path>
+ <path
+ d="M516.1 426.23v202.1c0 4.12-3.34 7.46-7.45 7.46H191.36c-4.11 0-7.46-3.34-7.46-7.46V426.22l138.52 107.53c.68.53 1.31.98 1.94 1.38 7.79 5.04 16.72 7.55 25.66 7.55s17.86-2.52 25.66-7.55c.62-.4 1.25-.85 1.94-1.38l138.5-107.52zM247.14 358.45l-12.91 30.22-.03.06v.03c-.11.21-.21.43-.32.64s-.23.42-.36.61c-.08.14-.17.27-.27.4-.08.11-.16.21-.24.31-.1.13-.21.25-.31.36-.08.09-.16.18-.24.25-.05.06-.1.11-.16.15l-.27.25c-.17.15-.33.29-.51.42-.15.13-.3.23-.47.33-.19.13-.39.25-.59.36s-. [...]
+ <path
+ d="M277.46 154.15V264.2c0 5.52-4.48 10-10 10H82.69c-5.52 0-10-4.48-10-10V154.14l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
+ <g>
+ <path d="M610.57 145.6l-76.07 57.24c-5.52 4.16-13.24 4.16-18.76 0l-76.08-57.24h170.91z"></path>
+ <path
+ d="M627.5 154.15V264.2c0 5.52-4.48 10-10 10H432.73c-5.52 0-10-4.48-10-10V154.14l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
+ </g>
+ </svg>
+ );
+}
+
+export function ToIcon(classname: string = '') {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={800}
+ height={800}
+ viewBox="0 0 32 32"
+ className={classname ? "icon " + classname : "icon"}
+ >
+ <path d="m12.103 11.923 2.58 2.59H2.513v2h12.17l-2.58 2.59 1.41 1.41 5-5-5-5z"/>
+ <path
+ d="M9.513 23.013v-.5h2v.5a4.504 4.504 0 0 0 9 .36v-.86l.82-.1a7 7 0 0 0 0-13.88l-.82-.02v-.86a4.504 4.504 0 0 0-9 .36v.5h-2v-.5a6.5 6.5 0 0 1 12.86-1.3 9 9 0 0 1 0 17.6 6.5 6.5 0 0 1-12.86-1.3z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function PollIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={800}
+ height={800}
+ viewBox="0 0 32 32"
+ className="icon"
+ >
+ <title>{"cloud--download"}</title>
+ <path
+ d="M10.013 23.513v-.5h2v.5a4.504 4.504 0 0 0 9 .36v-.86l.82-.1a7 7 0 0 0 0-13.88l-.82-.02v-.86a4.504 4.504 0 0 0-9 .36v.5h-2v-.5a6.5 6.5 0 0 1 12.86-1.3 9 9 0 0 1 0 17.6 6.5 6.5 0 0 1-12.86-1.3z"/>
+ <path d="M18.013 17.013v-2H5.843l2.58-2.59-1.41-1.41-5 5 5 5 1.41-1.41-2.58-2.59z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function ChoiceIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M407.33 113.97V609.2c0 2.75-1.9 5-4.22 5H291.55c-2.33 0-4.22-2.25-4.22-5V113.97c0-2.76 1.89-5 4.22-5h111.56c2.32 0 4.22 2.24 4.22 5zM27.1 437.55l60.87-57.64c.95-.9 2.32-1.41 3.76-1.41H258.2c2.76 0 5 1.87 5 4.17v111.65c0 2.3-2.24 4.17-5 4.17H91.54c-1.38 0-2.7-.48-3.65-1.32L27.2 443.15c-1.77-1.58-1.81-3.99-.1-5.61zM667.57 285.62l-60.87 57.64c-.95.9-2.32 1.41-3.76 1.41H436.47c-2.76 0-5-1.87-5-4.17V228.85c0-2.3 2.24-4.17 5-4.17h166.66c1.38 0 2.7.48 3.65 1.32l60.69 54.02c1. [...]
+ </svg>
+ );
+}
+
+
+export function SplitIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M496.2 83.65l-130.22 101.1c-.19.14-.39.29-.59.42a28.39 28.39 0 01-30.77 0c-.21-.13-.4-.28-.59-.42L203.8 83.65h292.4z"></path>
+ <path
+ d="M516.1 92.17v202.1c0 4.12-3.34 7.46-7.45 7.46H191.36c-4.11 0-7.46-3.34-7.46-7.46V92.16l138.52 107.53c.68.53 1.31.98 1.94 1.38 7.79 5.04 16.72 7.55 25.66 7.55s17.86-2.52 25.66-7.55c.62-.4 1.25-.85 1.94-1.38l138.5-107.52zM524.34 397.22l-12.91 30.22-.03.06v.03c-.11.21-.21.43-.32.64s-.23.42-.36.61c-.08.14-.17.27-.27.4-.08.11-.16.21-.24.31-.1.13-.21.25-.31.36-.08.09-.16.18-.24.25-.05.06-.1.11-.16.15l-.27.25c-.17.15-.33.29-.51.42-.15.13-.3.23-.47.33-.19.13-.39.25-.59.36s-.42 [...]
+ <path
+ d="M277.36 476.26v110.05c0 5.52-4.48 10-10 10H82.59c-5.52 0-10-4.48-10-10V476.25l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
+ <g>
+ <path d="M610.48 467.71l-76.07 57.24c-5.52 4.16-13.24 4.16-18.76 0l-76.08-57.24h170.91z"></path>
+ <path
+ d="M627.41 476.26v110.05c0 5.52-4.48 10-10 10H432.64c-5.52 0-10-4.48-10-10V476.25l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
+ </g>
+ </svg>
+ );
+}
+
+export function SagaIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M626.41 255.77c-.56-4.77-2.95-9.03-6.71-11.99l-46.46-36.64-1.06-1.09-.8-.28c-.81-.52-1.67-.98-2.56-1.36-.43-.19-.85-.36-1.25-.5-.47-.16-.96-.31-1.51-.45-.47-.11-.96-.22-1.45-.3-.49-.08-.97-.14-1.43-.18-.96-.08-1.95-.08-2.91-.01-.41.03-.83.08-1.23.14-.41.06-.82.14-1.25.23l-.58.14c-.1.03-.2.05-.31.08-.11.03-.21.06-.3.09-.29.08-.57.18-.86.28-.49.17-.99.37-1.53.61l-.16.08c-.32.15-.65.31-.97.49-.49.26-.93.53-1.34.81-.39.26-.76.52-1.12.8l-46.96 37.05a17.823 17.823 0 00-6.72 [...]
+ </svg>
+ );
+}
+
+export function TransformIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M441.77 277.51l-82.73 64.23c-.07.05-.13.09-.19.13-5.37 3.48-12.33 3.48-17.69.01-.07-.05-.13-.09-.18-.13l-82.76-64.24h183.54z"></path>
+ <path
+ d="M462.2 287.02V420.7c0 .98-.79 1.77-1.77 1.77H239.57c-.98 0-1.77-.79-1.77-1.77V287.02l90.91 70.56c.54.44 1.06.8 1.57 1.12 5.99 3.88 12.86 5.81 19.72 5.81s13.73-1.94 19.73-5.81c.49-.32 1.01-.68 1.58-1.13l90.89-70.55zM622.28 330.68l-35.89 31.78a1.48 1.48 0 01-1.98 0l-35.89-31.78c-.3-.26-.48-.63-.51-1.03-.02-.4.11-.79.38-1.09l11.28-12.73c.55-.61 1.49-.67 2.11-.12l12.44 11.02c-5.24-51.26-28.18-99.47-64.84-136.12-35.82-35.82-81.13-58.05-131.04-64.27-.1 0-.19-.03-.28-.06v.09s [...]
+ </svg>
+ );
+}
+
+export function FilterIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" id="a" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <path
+ d="M565.62 156.56L413.36 350.33a10.032 10.032 0 00-2.14 6.18v190.52c0 19.05-25.01 34.49-55.86 34.49s-55.86-15.44-55.86-34.49V356.51c0-2.24-.75-4.42-2.14-6.18L145.1 156.56c-5.15-6.56-.48-16.18 7.87-16.18h404.79c8.34 0 13.02 9.62 7.86 16.18z"></path>
+ </svg>
+ );
+}
+
+export function SetExchangePatternIcon() {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ className="icon" width="32px" height="32px">
+ <title>{"data-share"}</title>
+ <path
+ d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM4.226 1.135h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2zm4 6v-4H4.225l.001 4zM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ );
+}
+
+export function SortIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
+ <defs>
+ <style>{".b{stroke-linejoin: round;}.b,.c {stroke-linecap: round;}.b,.c,.d {fill: none;stroke: #000;stroke-width: 35px;}.c,.d {stroke-miterlimit: 10;}"}</style>
+ </defs>
+ <path d="M160.63 168.63L160.63 531.37" className="d"></path>
+ <path d="M576.31 170.27L269.3 170.27" className="c"></path>
+ <path d="M517.53 290.64L269.3 290.64" className="c"></path>
+ <path d="M458.75 411L269.3 411" className="c"></path>
+ <path d="M399.97 531.37L269.3 531.37" className="c"></path>
+ <path d="M197.7 197.95L160.63 168.71 123.55 197.95" className="b"></path>
+ <path d="M123.55 502.12L160.62 531.37 197.7 502.12" className="b"></path>
+ </svg>
+ );
+}
+
+export function OnCompletion() {
+ return (
+ <svg
+ className="icon" width="32px" height="32px"
+ xmlns="http://www.w3.org/2000/svg"
+ id="icon"
+ fill="#000"
+ viewBox="0 0 32 32"
+ >
+ <defs>
+ <style>{".cls-1 { fill: none; }"}</style>
+ </defs>
+ <path d="M22 26.59L19.41 24 18 25.41 22 29.41 30 21.41 28.59 20 22 26.59z"></path>
+ <circle cx="16" cy="16" r="2"></circle>
+ <path d="M16 22a6 6 0 116-6 6.007 6.007 0 01-6 6zm0-10a4 4 0 104 4 4.005 4.005 0 00-4-4z"></path>
+ <path d="M28 16a12 12 0 10-12 12v-2a10 10 0 1110-10z"></path>
+ <path
+ id="_Transparent_Rectangle_"
+ d="M0 0H32V32H0z"
+ className="cls-1"
+ data-name="<Transparent Rectangle>"
+ ></path>
+ </svg>
+ );
+}
+
+export function Intercept() {
+ return (
+ <svg
+ className="icon" width="32px" height="32px"
+ xmlns="http://www.w3.org/2000/svg"
+ id="icon"
+ fill="#000"
+ viewBox="0 0 32 32"
+ >
+ <defs>
+ <style>{".cls-1 { fill: none; }"}</style>
+ </defs>
+ <path d="M15 4H17V28H15z"></path>
+ <path
+ d="M10 7v18H4V7h6m0-2H4a2 2 0 00-2 2v18a2 2 0 002 2h6a2 2 0 002-2V7a2 2 0 00-2-2zM28 7v18h-6V7h6m0-2h-6a2 2 0 00-2 2v18a2 2 0 002 2h6a2 2 0 002-2V7a2 2 0 00-2-2z"></path>
+ <path
+ id="_Transparent_Rectangle_"
+ d="M0 0H32V32H0z"
+ className="cls-1"
+ data-name="<Transparent Rectangle>"
+ ></path>
+ </svg>
+ );
+}
+
+export function InterceptFrom() {
+ return (
+ <svg
+ className="icon" width="32px" height="32px"
+ xmlns="http://www.w3.org/2000/svg"
+ id="icon"
+ fill="#000"
+ viewBox="0 0 32 32"
+ >
+ <defs>
+ <style>{".cls-1 { fill: none; }"}</style>
+ </defs>
+ <path d="M26 30H14a2 2 0 01-2-2v-3h2v3h12V4H14v3h-2V4a2 2 0 012-2h12a2 2 0 012 2v24a2 2 0 01-2 2z"></path>
+ <path d="M14.59 20.59L18.17 17 4 17 4 15 18.17 15 14.59 11.41 16 10 22 16 16 22 14.59 20.59z"></path>
+ <path
+ id="_Transparent_Rectangle_"
+ d="M0 0H32V32H0z"
+ className="cls-1"
+ data-name="<Transparent Rectangle>"
+ ></path>
+ </svg>
+ );
+}
+
+export function InterceptSendToEndpoint() {
+ return (
+ <svg
+ className="icon" width="32px" height="32px"
+ xmlns="http://www.w3.org/2000/svg"
+ id="icon"
+ fill="#000"
+ viewBox="0 0 32 32"
+ >
+ <defs>
+ <style>{".cls-1 { fill: none; }"}</style>
+ </defs>
+ <path
+ d="M6 30h12a2.002 2.002 0 002-2v-3h-2v3H6V4h12v3h2V4a2.002 2.002 0 00-2-2H6a2.002 2.002 0 00-2 2v24a2.002 2.002 0 002 2z"></path>
+ <path
+ d="M20.586 20.586L24.172 17 10 17 10 15 24.172 15 20.586 11.414 22 10 28 16 22 22 20.586 20.586z"></path>
+ <path
+ id="_Transparent_Rectangle_"
+ d="M0 0H32V32H0z"
+ className="cls-1"
+ data-name="<Transparent Rectangle>"
+ ></path>
+ </svg>
+ );
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/KaravanIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/KaravanIcons.tsx
new file mode 100644
index 00000000..71f4a62b
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/KaravanIcons.tsx
@@ -0,0 +1,721 @@
+/*
+ * 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, {ReactElement} from 'react';
+
+export function KaravanIcon(className?: string) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ id="svg50"
+ width={32}
+ height={32}
+ preserveAspectRatio="xMidYMid"
+ version="1.1"
+ viewBox="0 0 256 256"
+ className={className ? className : "logo"}
+ >
+ <defs id="defs31">
+ <linearGradient id="linearGradient1351">
+ <stop
+ id="stop1347"
+ offset="0"
+ stopColor="#dcffff"
+ stopOpacity="1"
+ ></stop>
+ <stop
+ id="stop1349"
+ offset="1"
+ stopColor="#96d2e6"
+ stopOpacity="1"
+ ></stop>
+ </linearGradient>
+ <circle id="path-1" cx="128" cy="128" r="128"></circle>
+ <linearGradient
+ id="linearGradient-3"
+ x1="-26.051"
+ x2="254.316"
+ y1="271.331"
+ y2="0.048"
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop
+ id="stop10"
+ offset="0%"
+ stopColor="#4790bb"
+ stopOpacity="1"
+ ></stop>
+ <stop
+ id="stop12"
+ offset="10.996%"
+ stopColor="#64b7db"
+ stopOpacity="1"
+ ></stop>
+ <stop
+ id="stop14"
+ offset="94.502%"
+ stopColor="#326ea0"
+ stopOpacity="1"
+ ></stop>
+ </linearGradient>
+ <linearGradient
+ id="linearGradient-4"
+ x1="-32.163"
+ x2="259.338"
+ y1="277.029"
+ y2="-5.028"
+ gradientUnits="userSpaceOnUse"
+ >
+ <stop id="stop17" offset="0%" stopColor="#F69923"></stop>
+ <stop id="stop19" offset="8.048%" stopColor="#F79A23"></stop>
+ <stop id="stop21" offset="41.874%" stopColor="#E97826"></stop>
+ </linearGradient>
+ <linearGradient
+ id="linearGradient-5"
+ x1="217.945"
+ x2="99.459"
+ y1="67.505"
+ y2="247.005"
+ gradientTransform="scale(.96442 1.0369)"
+ gradientUnits="userSpaceOnUse"
+ xlinkHref="#linearGradient-4"
+ >
+ <stop
+ id="stop24"
+ offset="0%"
+ stopColor="#92d6d5"
+ stopOpacity="1"
+ ></stop>
+ <stop
+ id="stop26"
+ offset="41.191%"
+ stopColor="#79b7cc"
+ stopOpacity="1"
+ ></stop>
+ <stop
+ id="stop28"
+ offset="73.271%"
+ stopColor="#5891c5"
+ stopOpacity="1"
+ ></stop>
+ </linearGradient>
+ <mask id="mask-2" fill="#fff">
+ <use id="use33" xlinkHref="#path-1"></use>
+ </mask>
+ <mask id="mask-2-7" fill="#fff">
+ <use id="use137" xlinkHref="#path-1"></use>
+ </mask>
+ <linearGradient
+ id="linearGradient1345"
+ x1="233.122"
+ x2="2.24"
+ y1="56.015"
+ y2="242.78"
+ gradientUnits="userSpaceOnUse"
+ xlinkHref="#linearGradient1351"
+ ></linearGradient>
+ </defs>
+ <circle
+ id="circle38"
+ cx="127.994"
+ cy="127.994"
+ r="123.111"
+ fill="url(#linearGradient-3)"
+ fillRule="nonzero"
+ mask="url(#mask-2)"
+ ></circle>
+ <g id="g2266">
+ <path
+ id="path42"
+ fill="url(#linearGradient-5)"
+ fillOpacity="1"
+ fillRule="nonzero"
+ d="M98.044 75.517c-1.751-.002-3.524.01-5.292.061-2.056.06-4.817.713-8 1.785 53.775 40.834 73.108 114.497 39.875 178.514 1.129.03 2.249.123 3.385.123 60.736 0 111.492-42.323 124.609-99.071-38.542-45.178-90.813-81.314-154.578-81.412z"
+ mask="url(#mask-2)"
+ opacity="0.75"
+ ></path>
+ </g>
+ <path
+ id="path44"
+ fill="#1e4b7b"
+ fillOpacity="1"
+ fillRule="nonzero"
+ d="M84.752 77.368C66.895 83.378 32.83 104.546.079 132.81c2.487 67.334 57.028 121.313 124.548 123.07 33.233-64.016 13.901-137.68-39.875-178.513z"
+ mask="url(#mask-2)"
+ opacity="0.75"
+ ></path>
+ <path
+ id="path150"
+ fill="url(#linearGradient1345)"
+ fillOpacity="1"
+ fillRule="nonzero"
+ d="M128.747 54.005c-10.985 5.495 0 27.466 0 27.466C95.774 108.954 102.78 155.9 64.312 155.9c-20.97 0-42.242-24.077-64.233-38.828-.283 3.479-.785 6.972-.785 10.524 0 48.095 26.263 89.924 65.42 111.897 10.952-1.38 22.838-4.114 31.05-9.592 43.146-28.765 53.857-83.491 71.487-109.925 10.979-16.492 62.434-15.061 65.906-22.01 5.502-10.991-10.99-27.467-16.491-27.467h-43.958c-3.071 0-7.897-5.456-10.974-5.456h-16.492s-7.307-11.085-13.794-11.526c-.93-.066-1.83.053-2.7.488z"
+ mask="url(#mask-2-7)"
+ transform="translate(-.769 -.133)"
+ ></path>
+ <path
+ id="path40"
+ fill="#2d4150"
+ fillOpacity="1"
+ fillRule="nonzero"
+ d="M128 256C57.308 256 0 198.692 0 128 0 57.308 57.308 0 128 0c70.692 0 128 57.308 128 128 0 70.692-57.308 128-128 128zm0-9.768c65.298 0 118.232-52.934 118.232-118.232S193.298 9.768 128 9.768 9.768 62.702 9.768 128 62.702 246.232 128 246.232z"
+ mask="url(#mask-2)"
+ transform="translate(-.59) scale(1.00078)"
+ ></path>
+ </svg>
+ );
+}
+
+export function CamelIcon(props?: (React.SVGProps<SVGSVGElement>) | undefined) {
+ return (<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlnsXlink="http://www.w3.org/1999/xlink"
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 0 256 256"
+ {...props}
+ className="icon" width="32px" height="32px">
+ <defs>
+ <linearGradient
+ id="b"
+ x1="-12.564%"
+ x2="101.304%"
+ y1="108.214%"
+ y2="-1.964%"
+ >
+ <stop offset="0%" stopColor="#F69923"/>
+ <stop offset="10.996%" stopColor="#F79A23"/>
+ <stop offset="94.502%" stopColor="#E97826"/>
+ </linearGradient>
+ <linearGradient
+ id="d"
+ x1="-12.564%"
+ x2="101.304%"
+ y1="108.214%"
+ y2="-1.964%"
+ >
+ <stop offset="0%" stopColor="#F69923"/>
+ <stop offset="8.048%" stopColor="#F79A23"/>
+ <stop offset="41.874%" stopColor="#E97826"/>
+ </linearGradient>
+ <linearGradient
+ id="e"
+ x1="74.724%"
+ x2="6.653%"
+ y1="-3.059%"
+ y2="100.066%"
+ >
+ <stop offset="0%" stopColor="#F6E423"/>
+ <stop offset="41.191%" stopColor="#F79A23"/>
+ <stop offset="73.271%" stopColor="#E97826"/>
+ </linearGradient>
+ <circle id="a" cx={128} cy={128} r={128}/>
+ </defs>
+ <mask id="c" fill="#fff">
+ <use xlinkHref="#a"/>
+ </mask>
+ <circle
+ cx={127.994}
+ cy={127.994}
+ r={123.111}
+ fill="url(#b)"
+ mask="url(#c)"
+ />
+ <path
+ fill="url(#d)"
+ d="M128 256C57.308 256 0 198.692 0 128 0 57.308 57.308 0 128 0c70.692 0 128 57.308 128 128 0 70.692-57.308 128-128 128Zm0-9.768c65.298 0 118.232-52.934 118.232-118.232S193.298 9.768 128 9.768 9.768 62.702 9.768 128 62.702 246.232 128 246.232Z"
+ mask="url(#c)"
+ />
+ <path
+ fill="url(#e)"
+ d="M98.044 75.517c-1.751-.002-3.524.01-5.292.061-2.056.06-4.817.713-8 1.785 53.775 40.834 73.108 114.497 39.875 178.514 1.129.03 2.249.123 3.385.123 60.736 0 111.492-42.323 124.609-99.071-38.542-45.178-90.813-81.314-154.578-81.412Z"
+ mask="url(#c)"
+ opacity={0.75}
+ />
+ <path
+ fill="#28170B"
+ d="M84.752 77.368C66.895 83.378 32.83 104.546.079 132.81c2.487 67.334 57.028 121.313 124.548 123.07 33.233-64.016 13.901-137.68-39.875-178.513Z"
+ mask="url(#c)"
+ opacity={0.75}
+ />
+ <path
+ fill="#FFF"
+ d="M128.747 54.005c-10.985 5.495 0 27.466 0 27.466C95.774 108.954 102.78 155.9 64.312 155.9c-20.97 0-42.242-24.077-64.233-38.828-.283 3.479-.785 6.972-.785 10.524 0 48.095 26.263 89.924 65.42 111.897 10.952-1.38 22.838-4.114 31.05-9.592 43.146-28.765 53.857-83.491 71.487-109.925 10.979-16.492 62.434-15.061 65.906-22.01 5.502-10.991-10.99-27.467-16.491-27.467h-43.958c-3.071 0-7.897-5.456-10.974-5.456h-16.492s-7.307-11.085-13.794-11.526c-.93-.066-1.83.053-2.7.488Z"
+ mask="url(#c)"
+ />
+ </svg>
+ );
+}
+
+export function getDesignerIcon(icon: string, className?: string): ReactElement {
+ if (icon === 'kamelet') return (
+ <svg
+ className={`top-icon ${className}`} id="icon"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 32 32"
+ width="32px" height="32px"
+ >
+ <title>{"application"}</title>
+ <path
+ d="M16 18H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2ZM6 6v10h10V6ZM26 12v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM26 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM16 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ )
+ if (icon === 'code') return (
+ <svg
+ className={`top-icon ${className}`}
+ xmlns="http://www.w3.org/2000/svg"
+ width="24"
+ height="24"
+ fill="none"
+ viewBox="0 0 24 24"
+ >
+ <path
+ fill="#000000"
+ d="M8.502 5.387a.75.75 0 00-1.004-1.115L5.761 5.836c-.737.663-1.347 1.212-1.767 1.71-.44.525-.754 1.088-.754 1.784 0 .695.313 1.258.754 1.782.42.499 1.03 1.049 1.767 1.711l1.737 1.564a.75.75 0 101.004-1.115l-1.697-1.527c-.788-.709-1.319-1.19-1.663-1.598-.33-.393-.402-.622-.402-.817 0-.196.072-.425.402-.818.344-.409.875-.889 1.663-1.598l1.697-1.527zM14.18 4.275a.75.75 0 01.532.918l-3.987 15a.75.75 0 11-1.45-.386l3.987-15a.75.75 0 01.918-.532zM15.443 10.498a.75.75 0 011.059 [...]
+ ></path>
+ </svg>
+ )
+ if (icon === 'routes') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <path
+ d="M29,10H24v2h5v6H22v2h3v2.142a4,4,0,1,0,2,0V20h2a2.0027,2.0027,0,0,0,2-2V12A2.0023,2.0023,0,0,0,29,10ZM28,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,28,26Z"/>
+ <path
+ d="M19,6H14V8h5v6H12v2h3v6.142a4,4,0,1,0,2,0V16h2a2.0023,2.0023,0,0,0,2-2V8A2.0023,2.0023,0,0,0,19,6ZM18,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,18,26Z"/>
+ <path
+ d="M9,2H3A2.002,2.002,0,0,0,1,4v6a2.002,2.002,0,0,0,2,2H5V22.142a4,4,0,1,0,2,0V12H9a2.002,2.002,0,0,0,2-2V4A2.002,2.002,0,0,0,9,2ZM8,26a2,2,0,1,1-2-2A2.0023,2.0023,0,0,1,8,26ZM3,10V4H9l.0015,6Z"/>
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
+ height="32"/>
+ </svg>)
+ if (icon === 'route') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>{"category"}</title>
+ <path
+ d="M27 22.141V18a2 2 0 0 0-2-2h-8v-4h2a2.002 2.002 0 0 0 2-2V4a2.002 2.002 0 0 0-2-2h-6a2.002 2.002 0 0 0-2 2v6a2.002 2.002 0 0 0 2 2h2v4H7a2 2 0 0 0-2 2v4.142a4 4 0 1 0 2 0V18h8v4.142a4 4 0 1 0 2 0V18h8v4.141a4 4 0 1 0 2 0ZM13 4h6l.001 6H13ZM8 26a2 2 0 1 1-2-2 2.002 2.002 0 0 1 2 2Zm10 0a2 2 0 1 1-2-2 2.003 2.003 0 0 1 2 2Zm8 2a2 2 0 1 1 2-2 2.002 2.002 0 0 1-2 2Z"/>
+ <path
+ d="M0 0h32v32H0z"
+ data-name="<Transparent Rectangle>"
+ style={{
+ fill: "none",
+ }}
+ />
+ </svg>
+ )
+ if (icon === 'rest') return (
+ <svg className={`top-icon ${className}`} viewBox="0 0 32 32" width="32px" height="32px">
+ <g className="layer">
+ <title>Layer 1</title>
+ <path
+ d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0 0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0 -13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0 0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0 0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
+ id="svg_1"/>
+ <path
+ d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0 0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0 -1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0 -1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0 -0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0 0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0 1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0 1.7529,-0.7319l1.49,1.49l1.414,-1.414 [...]
+ id="svg_2" transform="rotate(25 15.9724 21.2664)" xmlns="http://www.w3.org/2000/svg"/>
+ </g>
+ </svg>
+ )
+ if (icon === 'beans') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>data--1</title>
+ <rect x="15" y="6" width="13" height="2"/>
+ <rect x="15" y="24" width="13" height="2"/>
+ <rect x="4" y="15" width="13" height="2"/>
+ <path d="M7,11a4,4,0,1,1,4-4A4,4,0,0,1,7,11ZM7,5A2,2,0,1,0,9,7,2,2,0,0,0,7,5Z" transform="translate(0 0)"/>
+ <path d="M7,29a4,4,0,1,1,4-4A4,4,0,0,1,7,29Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,7,23Z" transform="translate(0 0)"/>
+ <path d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
+ transform="translate(0 0)"/>
+ <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
+ <rect fill='none' width="32" height="32"/>
+ </g>
+ </svg>
+ )
+ if (icon === 'dependencies') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>application</title>
+ <path d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
+ transform="translate(0 0)"/>
+ <path d="M26,12v4H22V12h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V12a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <path d="M26,22v4H22V22h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <path d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
+ <rect fill='none' width="32" height="32"/>
+ </g>
+ </svg>
+ )
+ if (icon === 'error') return (
+ <svg className={`top-icon ${className}`} width="36px" height="36px" viewBox="0 0 36 36" version="1.1"
+ preserveAspectRatio="xMidYMid meet">
+ <circle className="clr-i-outline clr-i-outline-path-1" cx="18" cy="26.06" r="1.33"/>
+ <path className="clr-i-outline clr-i-outline-path-2"
+ d="M18,22.61a1,1,0,0,1-1-1v-12a1,1,0,1,1,2,0v12A1,1,0,0,1,18,22.61Z"/>
+ <path className="clr-i-outline clr-i-outline-path-3"
+ d="M18,34A16,16,0,1,1,34,18,16,16,0,0,1,18,34ZM18,4A14,14,0,1,0,32,18,14,14,0,0,0,18,4Z"/>
+ <rect x="0" y="0" width="36" height="36" fillOpacity="0"/>
+ </svg>)
+ if (icon === 'exception') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>misuse--alt</title>
+ <polygon
+ points="21.41 23 16 17.591 10.59 23 9 21.41 14.409 16 9 10.591 10.591 9 16 14.409 21.409 9 23 10.591 17.591 16 23 21.41 21.41 23"/>
+ <path d="M16,4A12,12,0,1,1,4,16,12.0136,12.0136,0,0,1,16,4m0-2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Z"
+ transform="translate(0)"/>
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
+ height="32"/>
+ </svg>)
+ if (icon === 'routeConfiguration') return (
+ <svg className={`top-icon ${className}`} width="32" height="32" viewBox="0 0 32 32">
+ <path
+ d="M28.83 21.17L25 17.37l.67-.67a1 1 0 000-1.41l-6-6a1 1 0 00-1.41 0l-.79.79-6.76-6.79a1 1 0 00-1.41 0l-4 4-.12.15-4 6a1 1 0 00.12 1.26l3 3a1 1 0 001.42 0L10 13.41l2.09 2.09-4.8 4.79a1 1 0 000 1.41l2 2a1 1 0 00.71.3 1 1 0 00.52-.15l4.33-2.6 2.44 2.45a1 1 0 001.41 0l.67-.7 3.79 3.83a4 4 0 005.66-5.66zM10 10.58l-5 5-1.71-1.71 3.49-5.24L10 5.41l6.09 6.09-2.59 2.58zm8 11l-2.84-2.84-5 3-.74-.74L19 11.41 23.59 16zm9.42 3.83a2 2 0 01-2.83 0l-3.8-3.79 2.83-2.83 3.8 3.79a2 2 0 010 [...]
+ <path
+ d="M0 0H32V32H0z"
+ fill='none'
+ data-name="<Transparent Rectangle>"
+ ></path>
+ </svg>)
+ if (icon === 'yaml') return (
+ <svg className={`top-icon ${className}`} x="0px" y="0px" width="32px" height="32px"
+ viewBox="0 0 32 32">
+ <style type="text/css">{".st0{fill:none;}"}</style>
+ <title>document</title>
+ <path
+ d="M25.7,9.3l-7-7C18.5,2.1,18.3,2,18,2H8C6.9,2,6,2.9,6,4v24c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V10C26,9.7,25.9,9.5,25.7,9.3 z M18,4.4l5.6,5.6H18V4.4z M24,28H8V4h8v6c0,1.1,0.9,2,2,2h6V28z"/>
+ <rect x="10" y="22" width="12" height="2"/>
+ <rect x="10" y="16" width="12" height="2"/>
+ <rect className="st0" width="32" height="32"/>
+ </svg>)
+ if (icon === 'code') return (
+ <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>code</title>
+ <polygon points="31 16 24 23 22.59 21.59 28.17 16 22.59 10.41 24 9 31 16"/>
+ <polygon points="1 16 8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 16"/>
+ <rect x="5.91" y="15" width="20.17" height="2" transform="translate(-3.6 27.31) rotate(-75)"/>
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
+ height="32" transform="translate(0 32) rotate(-90)"/>
+ </svg>)
+ return <></>;
+}
+
+
+export class BeanIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>data--1</title>
+ <rect x="15" y="6" width="13" height="2"/>
+ <rect x="15" y="24" width="13" height="2"/>
+ <rect x="4" y="15" width="13" height="2"/>
+ <path d="M7,11a4,4,0,1,1,4-4A4,4,0,0,1,7,11ZM7,5A2,2,0,1,0,9,7,2,2,0,0,0,7,5Z"
+ transform="translate(0 0)"/>
+ <path d="M7,29a4,4,0,1,1,4-4A4,4,0,0,1,7,29Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,7,23Z"
+ transform="translate(0 0)"/>
+ <path d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
+ transform="translate(0 0)"/>
+ <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
+ <rect fill='none' width="32" height="32"/>
+ </g>
+ </svg>
+ )
+ }
+}
+
+export class DependencyIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32" id="icon">
+ <title>application</title>
+ <path d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
+ transform="translate(0 0)"/>
+ <path d="M26,12v4H22V12h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V12a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <path d="M26,22v4H22V22h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <path d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
+ transform="translate(0 0)"/>
+ <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
+ <rect fill='none' width="32" height="32"/>
+ </g>
+ </svg>
+ )
+ }
+}
+
+export class RestIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32">
+ <g className="layer">
+ <title>Layer 1</title>
+ <path
+ d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0 0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0 -13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0 0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0 0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
+ id="svg_1"/>
+ <path
+ d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0 0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0 -1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0 -1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0 -0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0 0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0 1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0 1.7529,-0.7319l1.49,1.49l1.414,-1 [...]
+ id="svg_2" transform="rotate(25 15.9724 21.2664)" xmlns="http://www.w3.org/2000/svg"/>
+ </g>
+ </svg>
+ )
+ }
+}
+
+export class ConceptIcon extends React.Component<any> {
+
+ render() {
+ return (
+ <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32">
+ <title>concept</title>
+ <path
+ d="M20.8851,19.4711a5.9609,5.9609,0,0,0,0-6.9422L23,10.4141l1.293,1.2929a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414l-4-4a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414L21.5859,9l-2.1148,2.1149a5.9609,5.9609,0,0,0-6.9422,0L10,8.5859V2H2v8H8.5859l2.529,2.5289a5.9609,5.9609,0,0,0,0,6.9422L9,21.5859,7.707,20.293a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414l4,4a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414L10.4141,23l2.1148-2.1149a5.960 [...]
+ <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none'
+ width="32" height="32"/>
+ </svg>
+ )
+ }
+}
+
+export function JKubeIcon(className?: string) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 59.799997 68.099998"
+ className={className ? className + " icon" : "icon"}
+ >
+ <style id="style1" type="text/css">
+ {".jkube-icon-outer{fill-rule:evenodd;clip-rule:evenodd;fill:#0a4e9b}"}
+ </style>
+ <g id="g8" transform="translate(-9.2 -8.3)">
+ <path
+ id="path6"
+ d="M9.3 59.8c.9.8 2.5 1.5 3.5 2.1l21.6 12.5c1 .6 2.5 1.6 3.6 2v-6.3L14.8 56.6V29.8c-1.6-.4-4.2-2.7-5.6-2.9Z"
+ className="jkube-icon-outer"
+ />
+ <path
+ id="path7"
+ d="m69 59.8-.1-33c-1.5.5-3.9 2.6-5.5 3v26.9c-.8.8-4.9 2.9-6.1 3.6l-12.3 7c-5.1 3-4.8 2-4.8 4.9l.1 4.2z"
+ className="jkube-icon-outer"
+ />
+ <path
+ id="path8"
+ d="M15.9 28c1.9-.7 4.3-2.4 6-3.4l5.7-3.3c2.1-1.2 3.7-2.2 5.8-3.4 1.7-.9 4.1-2.6 5.7-3.2l14.3 8.2c2.4 1.4 4.7 2.7 7.2 4.1 2.1 1.2 1.6 1 3.7-.1 1-.6 2.7-1.4 3.4-2.1-.7-.7-28.3-16.5-28.5-16.5-.2 0-27.8 15.7-28.7 16.6Z"
+ className="jkube-icon-outer"
+ />
+ </g>
+ <path
+ id="path9"
+ d="M30 9.5 8.6 21.8v24.7L30 58.8l21.4-12.3V21.8Zm7.4 29c0 1.8-.5 3.6-1.4 5.1-.9 1.6-2.2 2.8-3.8 3.7-1.6.9-3.3 1.4-5.2 1.4-1.9 0-3.6-.5-5.2-1.4-1.6-.9-2.9-2.2-3.8-3.7-.9-1.6-1.4-3.3-1.4-5.1h6.8c0 .9.3 1.7 1 2.4s1.5 1 2.5 1 1.8-.3 2.5-1 1-1.5 1-2.4V28.2H24v-6.8h13.3v17.1z"
+ style={{
+ fill: "#0a4e9b",
+ }}
+ />
+ </svg>
+ )
+}
+
+export function AsyncApiIcon({className = ''}) {
+ return (
+ <svg className={"h-10 mt-0.5 w-auto " + className} width="165" height="36" viewBox="0 0 165 36" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="gradient1" x1="33.0317" y1="3.3661" x2="4.57364" y2="32.1761" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#2DCCFD"></stop>
+ <stop offset="100%" stop-color="#AD20E2"></stop>
+ </linearGradient>
+ <linearGradient id="gradient2" x1="33.0317" y1="32.6313" x2="4.571" y2="3.82126" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#A829E2"></stop>
+ <stop offset="5%" stop-color="#A829E2" stop-opacity="84%"></stop>
+ <stop offset="11%" stop-color="#A829E2" stop-opacity="67%"></stop>
+ <stop offset="18%" stop-color="#A829E2" stop-opacity="51%"></stop>
+ <stop offset="25%" stop-color="#A829E2" stop-opacity="38%"></stop>
+ <stop offset="33%" stop-color="#A829E2" stop-opacity="28%"></stop>
+ <stop offset="43%" stop-color="#A829E2" stop-opacity="20%"></stop>
+ <stop offset="54%" stop-color="#A829E2" stop-opacity="14%"></stop>
+ <stop offset="68%" stop-color="#A829E2" stop-opacity="11%"></stop>
+ <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
+ </linearGradient>
+ <linearGradient id="gradient3" x1="3.41005" y1="32.6313" x2="31.8682" y2="3.82129" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#E50E99"></stop>
+ <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
+ </linearGradient>
+ <linearGradient id="gradient4" x1="33.0317" y1="3.36871" x2="4.57097" y2="32.1761" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#21D4FD"></stop>
+ <stop offset="3%" stop-color="#27CDFC" stop-opacity="96%"></stop>
+ <stop offset="23%" stop-color="#4E9CF4" stop-opacity="70%"></stop>
+ <stop offset="43%" stop-color="#6E73EE" stop-opacity="49%"></stop>
+ <stop offset="61%" stop-color="#8753E9" stop-opacity="32%"></stop>
+ <stop offset="77%" stop-color="#993CE5" stop-opacity="20%"></stop>
+ <stop offset="90%" stop-color="#A42EE3" stop-opacity="13%"></stop>
+ <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
+ </linearGradient>
+ </defs>
+ <path
+ d="M63.9815 27.6971H61.4524L59.3704 22.3187H50.4894L48.4074 27.6971H45.9074L53.5529 8.30026H56.3783L63.9815 27.6971ZM51.3386 20.1182H58.5079L54.9074 10.5635L51.3386 20.1182Z"
+ fill="#0C0928"></path>
+ <path
+ d="M71.7037 27.9925C70.3161 28.0052 68.9453 27.6926 67.7037 27.0804C66.5264 26.5139 65.5472 25.6129 64.8915 24.4931L66.9154 23.0531C67.3281 23.9309 67.9957 24.6678 68.8333 25.17C69.7573 25.7002 70.8129 25.9645 71.881 25.9331C72.9392 25.9331 73.7566 25.7345 74.3519 25.332C74.5772 25.1976 74.771 25.0172 74.9202 24.8029C75.0695 24.5887 75.1707 24.3455 75.2173 24.0895C75.2639 23.8335 75.2547 23.5707 75.1903 23.3185C75.1259 23.0663 75.0078 22.8306 74.8439 22.6271C74.5741 22.27 [...]
+ fill="#0C0928"></path>
+ <path
+ d="M90.3703 13.0018H92.9285L85.9391 30.1668C85.642 30.9811 85.2258 31.748 84.7037 32.4431C84.3138 32.9574 83.8037 33.3707 83.2169 33.6479C82.6214 33.9034 81.9771 34.0291 81.328 34.0164C80.6995 34.0219 80.0743 33.9275 79.4762 33.7367C78.939 33.565 78.4321 33.312 77.9735 32.9867L78.6269 30.9299C78.9951 31.2671 79.424 31.5331 79.8915 31.7139C80.3125 31.8803 80.7609 31.9689 81.2143 31.9753C81.7379 31.9722 82.2474 31.8077 82.6719 31.5049C83.127 31.1913 83.5432 30.5545 83.9206 [...]
+ fill="#0C0928"></path>
+ <path
+ d="M94.9735 27.6971V13.0018H97.0502L97.2566 16.2947L96.8703 15.9707C97.1438 15.2501 97.5819 14.6017 98.1507 14.0759C98.6824 13.5968 99.3148 13.2398 100.003 13.0306C100.711 12.8158 101.449 12.7075 102.19 12.7091C103.193 12.6965 104.187 12.9017 105.101 13.3102C105.966 13.7045 106.695 14.3405 107.198 15.1396C107.727 15.9637 107.992 17.0091 107.992 18.2757V27.6841H105.611V19.1146C105.611 17.4891 105.258 16.3566 104.553 15.7172C103.842 15.079 102.91 14.7371 101.95 14.7633C101. [...]
+ fill="#0C0928"></path>
+ <path
+ d="M117.251 12.7091C118.181 12.6912 119.105 12.851 119.974 13.1795C120.741 13.4831 121.436 13.9436 122.011 14.5307C122.599 15.1392 123.072 15.8474 123.407 16.6214L121.148 17.6668C120.895 16.8219 120.393 16.0705 119.706 15.5081C118.978 14.983 118.091 14.7185 117.19 14.758C116.291 14.7331 115.404 14.9625 114.632 15.4192C113.903 15.8776 113.332 16.5437 112.995 17.3297C112.243 19.2646 112.243 21.4057 112.995 23.3405C113.329 24.1319 113.9 24.8032 114.632 25.264C115.404 25.7207 [...]
+ fill="#0C0928"></path>
+ <path
+ d="M143.659 27.6971H140.296L138.423 22.614H130.183L128.307 27.6971H125.034L132.442 8.30026H136.251L143.659 27.6971ZM131.074 20.0555H137.526L134.312 11.0052L131.074 20.0555Z"
+ fill="#0C0928"></path>
+ <path
+ d="M152.992 8.30024C154.248 8.26933 155.494 8.52043 156.638 9.03462C157.616 9.49485 158.441 10.2199 159.019 11.1254C159.584 12.1193 159.881 13.2402 159.881 14.3804C159.881 15.5205 159.584 16.6415 159.019 17.6354C158.443 18.5428 157.617 19.2684 156.638 19.7262C155.495 20.2425 154.248 20.4945 152.992 20.4631H148.619V27.6919H145.444V8.30024H152.992ZM152.487 17.7635C153.898 17.7635 154.934 17.4743 155.595 16.8958C156.257 16.3174 156.589 15.4802 156.593 14.3843C156.593 13.2692 [...]
+ fill="#0C0928"></path>
+ <path d="M165 8.30026V27.6971H161.825V8.30026H165Z" fill="#0C0928"></path>
+ <path
+ d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
+ fill="url(#gradient1)"></path>
+ <path
+ d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
+ fill="url(#gradient2)"></path>
+ <path
+ d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
+ fill="url(#gradient3)"></path>
+ <path
+ d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
+ fill="url(#gradient4)"></path>
+ <path d="M11.7645 14.1988L10.6799 15.6754L19.1508 21.749L19.209 21.7908L20.2936 20.3142L11.8227 14.2406L11.7645 14.1988Z" fill="white"></path>
+ <path d="M17.2989 14.2406L17.2407 14.1988L16.1561 15.6754L24.627 21.749L24.6852 21.7908L25.7698 20.3142L17.2989 14.2406Z" fill="white"></path>
+ <path
+ d="M18.2275 6.64075C13.6349 6.64075 9.89948 9.46064 9.89948 12.9261V12.9966H11.7513V12.9261C11.7513 10.4668 14.6614 8.46492 18.2328 8.46492C21.8042 8.46492 24.7143 10.4668 24.7143 12.9261V12.9966H26.5661V12.9261C26.5556 9.46064 22.8201 6.64075 18.2275 6.64075Z"
+ fill="white"></path>
+ <path
+ d="M24.6958 23.0714C24.6958 25.5306 21.7857 27.5325 18.2116 27.5325C14.6376 27.5325 11.7301 25.5306 11.7301 23.0714V23.0008H9.8783V23.0714C9.8783 26.5368 13.6137 29.3567 18.2063 29.3567C22.7989 29.3567 26.5344 26.5368 26.5344 23.0714V23.0008H24.6825L24.6958 23.0714Z"
+ fill="white"></path>
+ </svg>
+ );
+}
+
+type OpenApiIconProps = React.SVGProps<SVGSVGElement> & {
+ className?: string, height?: number | string | undefined, width?: number | string | undefined, fill?: string
+};
+
+export function OpenApiIcon(props: OpenApiIconProps) {
+ const { className, height, width, fill } = props;
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlSpace="preserve"
+ viewBox="0 0 112 112"
+ height={height}
+ width={width}
+ className={className}
+ >
+ <path
+ fill={fill ?? "#93d500"}
+ d="M74.909 189.069H45.352c.005.144.009.289.017.433.012.278.032.555.049.833.008.119.013.238.022.356.023.322.051.642.08.962l.02.215a46.218 46.218 0 0 0 .126 1.168 43.62 43.62 0 0 0 .154 1.158c.339 2.356.848 4.69 1.527 6.984.003.01.007.019.009.029a43.315 43.315 0 0 0 .373 1.203c.105.323.215.645.325.968.029.081.056.163.086.244.099.279.2.558.304.837l.143.378.27.691c.069.173.141.346.213.519.074.18.15.359.226.54.094.22.192.439.289.658l.175.391c.12.263.244.526.368.787.041.084.08. [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#4d5a31"}
+ d="m82.173 202.638-.071.071-20.819 20.82c.107.1.213.201.323.298.194.176.392.351.589.523.102.091.202.181.304.269.236.204.474.403.711.602l.192.16a47.32 47.32 0 0 0 .917.737 62.01 62.01 0 0 0 .928.711 50.044 50.044 0 0 0 3.895 2.633l.139.085c.255.153.51.304.767.453l.471.268c.148.086.296.168.446.251a63.783 63.783 0 0 0 .927.499c.757.396 1.527.764 2.303 1.118l.739-1.794 10.471-25.429.039-.094a20.195 20.195 0 0 1-3.271-2.181z"
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#6ba43a"}
+ d="M80.005 200.564a20.653 20.653 0 0 1-1.767-2.28 21.467 21.467 0 0 1-.54-.843l-25.275 15.226c.388.645.793 1.273 1.206 1.894l.041.065.015.023c.014.02.026.042.04.063l.004.006.101.148.006.009.003.004c.439.649.89 1.288 1.355 1.91l.031.04.03.039a45.939 45.939 0 0 0 1.351 1.715l.158.191c.2.239.4.477.604.713.087.101.178.202.266.302.174.198.346.395.524.59.097.107.198.215.297.322l.135.146c.13.14.259.28.39.419.052.055.107.109.16.164.23.24.462.48.699.716l20.85-20.85a17.977 17.977 0 [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#4d5a31"}
+ d="M107.642 202.627c-.229.185-.461.366-.697.54l.052.087 15.202 25.235c.704-.46 1.4-.934 2.08-1.432a50.463 50.463 0 0 0 4.267-3.527l-20.821-20.821z"
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#93d500"}
+ d="m74.961 105.035-.006.003.015-.008a.024.024 0 0 1-.009.005zM75.004 105.012c.066-.039.133-.072.198-.112-.065.04-.132.075-.198.112z"
+ />
+ <path
+ fill={fill ?? "#93d500"}
+ d="m119.99 228.696-.516-.856-14.19-23.555c-.287.173-.581.329-.874.487a20.15 20.15 0 0 1-9.528 2.404c-1.936 0-3.871-.28-5.742-.838-.319-.095-.63-.22-.945-.332-.315-.111-.634-.207-.944-.335l-10.464 25.412-.41.996-.351.853-.002.004.082.031.086.033h.001l.002.001.02.008c.247.101.496.188.744.285.311.121.622.244.934.358.159.058.317.126.476.182h.001a49.947 49.947 0 0 0 10.119 2.422c.135.016.269.035.404.054l.424.046c.266.03.531.061.798.087l.198.017c.327.031.654.059.979.082.111.008 [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#4d5a31"}
+ d="M59.838 151.994c-.237.237-.461.482-.692.722-.231.24-.466.479-.692.723a49.743 49.743 0 0 0-4.212 5.22c-.061.085-.122.174-.182.261a49.018 49.018 0 0 0-1.008 1.522 49.48 49.48 0 0 0-7.7 24.627c-.013.333-.02.667-.027 1-.007.333-.017.667-.017 1h29.488c0-.334.031-.666.048-1 .017-.334.022-.668.055-1a20.013 20.013 0 0 1 4.447-10.739c.21-.256.447-.496.672-.743.224-.247.432-.504.671-.742zM120.681 144.675l-.122-.073c-.259-.159-.521-.312-.783-.465-.152-.088-.304-.173-.457-.26-.154 [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#6ba43a"}
+ d="M93.914 137.485c-.333.007-.667.008-1 .021a49.856 49.856 0 0 0-6.233.643l-.136.023c-.29.05-.577.103-.865.157-.163.031-.327.061-.49.094-.17.034-.339.069-.508.106-.28.058-.56.119-.84.184l-.153.034a49.891 49.891 0 0 0-11.898 4.438h-.001c-.245.13-.484.277-.728.411-.292.16-.582.325-.872.491-.215.124-.434.238-.648.366l-.007.004h-.001l-.045.026c-.056.034-.114.062-.17.096l.003.005.516.857 14.705 24.412c.287-.173.581-.33.874-.487.295-.159.594-.308.895-.451a20.051 20.051 0 0 1 7. [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#4d5a31"}
+ d="M144.458 184.631a53.77 53.77 0 0 0-.048-.795c-.008-.132-.015-.263-.026-.397a41.966 41.966 0 0 0-.077-.934c-.006-.081-.014-.161-.021-.242a60.396 60.396 0 0 0-.111-1.043l-.01-.084-.005-.04c-.046-.375-.096-.75-.149-1.124-.001-.011-.002-.025-.005-.035a49.558 49.558 0 0 0-1.524-6.972l-.014-.044c-.107-.356-.216-.71-.328-1.063-.015-.046-.031-.093-.045-.14a66.772 66.772 0 0 0-.412-1.212 50.701 50.701 0 0 0-.714-1.892c-.072-.18-.144-.357-.218-.534-.072-.176-.146-.35-.22-.526a80 [...]
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#6ba43a"}
+ d="M115.03 187.069c0 .334-.031.666-.048 1-.016.334-.022.668-.055 1a20.022 20.022 0 0 1-4.446 10.74c-.21.256-.447.496-.672.743-.224.247-.432.504-.671.742l20.851 20.85c.237-.237.46-.482.691-.723.231-.241.466-.479.691-.723a49.783 49.783 0 0 0 4.224-5.236l.148-.214c.155-.223.306-.448.458-.673.133-.201.266-.402.395-.605.064-.097.128-.198.19-.295a49.46 49.46 0 0 0 7.685-24.607c.013-.333.02-.667.027-1 .007-.333.017-.666.017-1H115.03Z"
+ style={{
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ <path
+ fill={fill ?? "#424143"}
+ d="M153.276 128.706c-5.395-5.395-14.142-5.395-19.536 0-4.304 4.303-5.164 10.736-2.601 15.902L101.048 174.7c-5.166-2.562-11.599-1.703-15.903 2.6-5.395 5.395-5.394 14.142 0 19.537 5.396 5.395 14.143 5.393 19.538-.001 4.303-4.303 5.162-10.736 2.599-15.903l30.091-30.091c5.167 2.562 11.599 1.703 15.902-2.601 5.395-5.392 5.395-14.14.001-19.535z"
+ style={{
+ fill: fill ?? "#424143",
+ fillOpacity: 1,
+ }}
+ transform="translate(-45.308 -124.66)"
+ />
+ </svg>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/OtherIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/OtherIcons.tsx
new file mode 100644
index 00000000..1e10e7ae
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/icons/OtherIcons.tsx
@@ -0,0 +1,36 @@
+/*
+ * 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';
+
+export function AutoStartupFalseIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="24px" height="24px">
+ <circle cx="16" cy="16" r="13" fill="var(--pf-t--global--background--color--primary--default)" stroke="var(--pf-t--global--text--color--regular)" strokeWidth="1px"/>
+ <rect x="12" y="10" width="2" height="12" fill="black"/>
+ <rect x="18" y="10" width="2" height="12" fill="black"/>
+ </svg>
+ );
+}
+
+export function ErrorHandlerIcon() {
+ return (
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="24px" height="24px">
+ <circle cx="16" cy="16" r="13" fill="var(--pf-t--global--background--color--primary--default)" stroke="var(--pf-t--global--text--color--regular)" strokeWidth="1px"/>
+ <path d="m19.264 14.98-3.998 7-1.736-1 2.287-4h-3.889l3.993-7 1.737 1-2.284 4z"/>
+ </svg>
+ );
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletAnnotationsPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletAnnotationsPanel.tsx
new file mode 100644
index 00000000..f0d4a062
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletAnnotationsPanel.tsx
@@ -0,0 +1,84 @@
+/*
+ * 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 {
+ Card,
+ CardBody,
+ CardTitle,
+ Form, Grid,
+} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import { KameletInput } from './KameletInput';
+
+const PREFIX = 'camel.apache.org/';
+
+export function KameletAnnotationsPanel() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ function setValue(key: string, value: string) {
+ if (key && value && value.length > 0) {
+ (integration.metadata.annotations as any)[PREFIX + key] = value;
+ setIntegration(integration, true);
+ }
+ }
+
+ function getValue(key: string): string {
+ const annotations = integration.metadata.annotations;
+ if (annotations) {
+ return (annotations as any)[PREFIX + key];
+ } else {
+ return '';
+ }
+ }
+
+ function getElement(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='text' isRequired={true}/>);
+ }
+
+ function getElementToggleGroup(key: string, label: string, values: string[], span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='toggle' options={values} isRequired={true}/>);
+
+ }
+
+ function getElementIcon(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+
+ return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='icon' isRequired={true}/>);
+ }
+
+ return (
+ <Card isCompact ouiaId="AnnotationsCard">
+ <CardTitle>Annotations</CardTitle>
+ <CardBody>
+ <Form>
+ <Grid hasGutter md={6}>
+ {getElementToggleGroup('kamelet.support.level', 'Support Level', ['Preview', 'Stable'], 2)}
+ {getElementIcon('kamelet.icon', 'Icon', 10)}
+ {getElement('catalog.version', 'Version', 3)}
+ {getElement('provider', 'Provider', 3)}
+ {getElement('kamelet.group', 'Group', 3)}
+ {getElement('kamelet.namespace', 'Namespace', 3)}
+ </Grid>
+ </Form>
+ </CardBody>
+ </Card>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionPropertyCard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionPropertyCard.tsx
new file mode 100644
index 00000000..148b98c3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionPropertyCard.tsx
@@ -0,0 +1,299 @@
+/*
+ * 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, {useState} from 'react';
+import {Button, Card, CardBody, CardTitle, Flex, FlexItem, FormGroup, FormSelect, FormSelectOption, Grid, GridItem, Label, LabelGroup, Switch} from '@patternfly/react-core';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {DefinitionProperty} from "@karavan-core/model/IntegrationDefinition";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {PlusCircleIcon} from '@patternfly/react-icons';
+import {KameletInput} from './KameletInput';
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+
+interface Props {
+ index: number
+ propKey: string
+ property: DefinitionProperty
+}
+
+export function KameletDefinitionPropertyCard(props: Props) {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+
+ const key = props.propKey;
+ const required = integration.spec.definition?.required || [];
+
+ function setPropertyValue(field: string, value: any) {
+ if (integration.spec.definition?.properties) {
+ (integration.spec.definition?.properties as any)[key][field] = value;
+ setIntegration(integration, true);
+ }
+ }
+
+ function getPropertyValue(field: string) {
+ const properties: any = integration.spec.definition?.properties;
+ if (properties) {
+ return properties[key][field];
+ }
+ return undefined;
+ }
+
+
+ function getPropertyField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (<KameletInput elementKey={key + field} label={label} span={span} value={getPropertyValue(field)} setValue={(value: string) => setPropertyValue(field, value)}
+ type='text' isRequired={isRequired}/>);
+ }
+
+ function getPropertyTypeField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (
+ <GridItem span={span}>
+ <FormGroup label={label} fieldId={key + field} isRequired={isRequired}>
+ <FormSelect
+ value={getPropertyValue(field)}
+ onChange={(_, value) => setPropertyValue(field, value)}
+ aria-label="FormSelect Input"
+ ouiaId="BasicFormSelect"
+ >
+ {['string', 'number', 'integer', 'boolean'].map((option, index) => (
+ <FormSelectOption key={option} isDisabled={false} id={key + field} name={key + field}
+ value={option} label={option}/>
+ ))}
+ </FormSelect>
+ </FormGroup>
+ </GridItem>
+ )
+ }
+
+ function sortEnum(source: string, dest: string) {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties[key]) {
+ const enums: string [] = i.spec.definition.properties[key].enum;
+ if (enums && Array.isArray(enums)) {
+ const from = enums.findIndex(e => source);
+ const to = enums.findIndex(e => dest);
+ if (from > -1 && to > -1) {
+ [enums[from], enums[to]] = [enums[to], enums[from]];
+ i.spec.definition.properties[key].enum = enums;
+ setIntegration(i, true);
+ }
+ }
+ }
+ }
+
+ function addEnum() {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties[key]) {
+ let enums: string [] = i.spec.definition.properties[key].enum;
+ if (enums && Array.isArray(enums)) {
+ enums.push("enum")
+ } else {
+ enums = ['enum'];
+ }
+ i.spec.definition.properties[key].enum = enums;
+ setIntegration(i, true);
+ }
+ }
+
+ function deleteEnum(val: string) {
+ const enumVal = getPropertyValue('enum');
+ const i = CamelUtil.cloneIntegration(integration);
+ if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
+ const enums: string[] = [...enumVal];
+ setPropertyValue('enum', enums.filter(e => e !== val));
+ }
+ }
+
+ function renameEnum(index: number, newVal: string) {
+ const enumVal = getPropertyValue('enum');
+ const i = CamelUtil.cloneIntegration(integration);
+ if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
+ const enums: string[] = [...enumVal];
+ enums[index] = newVal;
+ setPropertyValue('enum', enums);
+ }
+ }
+
+ function getPropertyEnumField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ const enumVal = getPropertyValue(field);
+ return (
+ <GridItem span={span}>
+ <FormGroup fieldId={key + field} isRequired={isRequired}>
+ <LabelGroup
+ categoryName={label}
+ numLabels={enumVal?.length || 0}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addEnum()}>
+ Add
+ </Button>
+ }
+ >
+ {enumVal && enumVal.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteEnum(val)}
+ onEditCancel={(_event, prevText) => {
+ }}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameEnum(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameEnum(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameEnum(index, newText)
+ } else {
+ renameEnum(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </GridItem>
+ )
+ }
+
+ function renameProperty(newKey: string) {
+ const oldKey = key;
+ newKey = newKey.replace(/[\W_]+/g, '');
+ if (oldKey !== newKey) {
+ if (integration.spec.definition?.properties) {
+ const o = (integration.spec.definition?.properties as any)
+ const newObject: any = {};
+ Object.keys(o).forEach(k => {
+ if (k !== oldKey) {
+ newObject[k] = o[k];
+ } else {
+ newObject[newKey] = o[k];
+ }
+ })
+ integration.spec.definition.properties = newObject;
+
+ if (required.includes(oldKey)) {
+ const newRequired = [...required];
+ const index = newRequired.findIndex(r => r === oldKey);
+ newRequired.splice(index, 1);
+ newRequired.push(newKey)
+ integration.spec.definition.required = newRequired;
+ }
+ setIntegration(integration, true);
+ }
+ }
+ }
+
+ function deleteProperty() {
+ if (integration.spec.definition?.properties) {
+ integration.spec.definition.required = integration.spec.definition.required.filter(r => r !== key);
+ delete integration.spec.definition.properties[key];
+ setIntegration(integration, true);
+ }
+ }
+
+ function setRequired(checked: boolean) {
+ const newRequired = [...required];
+ if (checked && !newRequired.includes(key)) {
+ newRequired.push(key);
+ } else if (!checked && newRequired.includes(key)) {
+ const index = newRequired.findIndex(r => r === key);
+ newRequired.splice(index, 1);
+ }
+ if (integration.spec.definition !== undefined) {
+ integration.spec.definition.required = newRequired;
+ }
+ setIntegration(integration, true);
+ }
+
+ function getTitle() {
+ return (
+ <Flex>
+ <FlexItem>
+ <Label
+ color="blue"
+ onClose={() => {
+ setShowDeleteConfirmation(true);
+ }}
+ closeBtnAriaLabel="Delete Property"
+ onEditCancel={(_, previousText) => {
+ }}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameProperty(newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameProperty(newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameProperty(newText)
+ } else {
+ renameProperty(key)
+ }
+ }}
+ isEditable
+ editableProps={{
+ 'aria-label': `Editable property with text ${key}`,
+ id: 'editable-property'
+ }}
+ >
+ {key}
+ </Label>
+ </FlexItem>
+ <FlexItem align={{default: "alignRight"}}>
+ <Switch
+ label={"Required"}
+ isChecked={required.includes(key)}
+ onChange={(_, checked) => setRequired(checked)}
+ isReversed
+ />
+ </FlexItem>
+ </Flex>
+ )
+ }
+
+
+ return (
+ <Card isClickable isCompact ouiaId="PropertyCard" className="property-card">
+ <CardTitle>
+ {getTitle()}
+ </CardTitle>
+ <CardBody>
+ <Grid hasGutter>
+ {getPropertyField("title", "Title", true, 3)}
+ {getPropertyField("description", "Description", true, 6)}
+ {getPropertyTypeField("type", "Type", true, 3)}
+ {getPropertyField("format", "Format", false, 3)}
+ {getPropertyField("example", "Example", false, 6)}
+ {getPropertyField("default", "Default", false, 3)}
+ {getPropertyValue('type') === 'string' && getPropertyEnumField("enum", "Enum", true, 12)}
+ {/*{getPropertyField("x-descriptors", "Descriptors", false, 12)}*/}
+ </Grid>
+ </CardBody>
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message={`Delete ${key} property?`}
+ btnConfirm='Delete'
+ btnConfirmVariant='danger'
+ onConfirm={() => deleteProperty()}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ </Card>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionsPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionsPanel.tsx
new file mode 100644
index 00000000..f7e0affa
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDefinitionsPanel.tsx
@@ -0,0 +1,126 @@
+/*
+ * 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, CardBody, CardTitle, Flex, FlexItem, Form, Grid,} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {PlusCircleIcon} from '@patternfly/react-icons';
+import {KameletDefinitionPropertyCard} from "./KameletDefinitionPropertyCard";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {DefinitionProperty} from "@karavan-core/model/IntegrationDefinition";
+import {KameletDependenciesCard} from "./KameletDependenciesCard";
+import {KameletInput} from './KameletInput';
+
+export function KameletDefinitionsPanel() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ function setValue(key: string, value: string) {
+ if (key && value && value.length > 0) {
+ (integration.spec.definition as any)[key] = value;
+ setIntegration(integration, true);
+ }
+ }
+
+ function getValue(key: string): string {
+ const annotations = integration.spec.definition;
+ if (annotations) {
+ return (annotations as any)[key];
+ } else {
+ return '';
+ }
+ }
+
+ function getElementTextInput(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='text' isRequired={true}/>);
+
+ }
+
+ function getElementTextArea(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='textArea' isRequired={true}/>);
+
+ }
+
+ const properties = integration.spec.definition?.properties ? Object.keys(integration.spec.definition?.properties) : [];
+
+ function addNewProperty() {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties) {
+ const propertyName = generatePropertyName();
+ i.spec.definition.properties = Object.assign({[propertyName]: new DefinitionProperty()}, integration.spec.definition.properties);
+ setIntegration(i, true);
+ }
+ }
+
+ function generatePropertyName(count: number = 0): string {
+ const prefix = 'property';
+ const propName = 'property' + count;
+ if (integration.spec.definition?.properties) {
+ const keys = Object.keys(integration.spec.definition?.properties);
+ if (keys.includes(propName)) {
+ return generatePropertyName(count + 1);
+ } else {
+ return propName;
+ }
+ }
+ return prefix;
+ }
+
+ return (
+ <>
+ <Card isCompact ouiaId="DefinitionsCard">
+ <CardTitle>Definitions</CardTitle>
+ <CardBody>
+ <Form>
+ <Grid hasGutter>
+ {getElementTextInput('title', 'Title', 3)}
+ {getElementTextArea('description', 'Description', 9)}
+ {/*{getElementTextInput('type', 'Type', 2)}*/}
+ </Grid>
+ </Form>
+ </CardBody>
+ </Card>
+ <Card isCompact ouiaId="PropertiesCard">
+ <CardTitle>
+ <Flex>
+ <FlexItem>Properties</FlexItem>
+ <FlexItem align={{default: "alignRight"}}>
+ <Button variant={"link"} icon={<PlusCircleIcon/>} onClick={event => addNewProperty()}>
+ Add property
+ </Button>
+ </FlexItem>
+ </Flex>
+ </CardTitle>
+ <CardBody>
+ <Form>
+ {properties.map((key: string, index: number) => {
+ const property = (integration.spec.definition?.properties as any)[key];
+ return <KameletDefinitionPropertyCard key={key}
+ index={index}
+ propKey={key}
+ property={property}/>
+ })}
+ </Form>
+ </CardBody>
+ </Card>
+ <KameletDependenciesCard/>
+ </>
+
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDependenciesCard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDependenciesCard.tsx
new file mode 100644
index 00000000..2c218858
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDependenciesCard.tsx
@@ -0,0 +1,105 @@
+/*
+ * 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, CardBody, CardTitle, FormGroup, FormHelperText, HelperText, HelperTextItem, Label, LabelGroup,} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {PlusCircleIcon} from '@patternfly/react-icons';
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+
+export function KameletDependenciesCard() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ const dependencies: string[] = [...(integration.spec.dependencies || [])];
+
+
+ function setDependencies(deps: string[]) {
+ const i = CamelUtil.cloneIntegration(integration);
+ i.spec.dependencies = deps;
+ setIntegration(i, true);
+ }
+
+ function addDepencency() {
+ dependencies.push("dependency")
+ setDependencies(dependencies);
+ }
+
+ function deleteDependency(val: string) {
+ setDependencies(dependencies.filter(e => e !== val));
+ }
+
+ function renameDependency(index: number, newVal: string) {
+ dependencies[index] = newVal;
+ setDependencies(dependencies);
+ }
+
+ return (
+ <Card isCompact ouiaId="PropertyCard">
+ <CardTitle>
+ Dependencies
+ </CardTitle>
+ <CardBody>
+ <FormHelperText>
+ <HelperText>
+ <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
+ </HelperText>
+ </FormHelperText>
+ </CardBody>
+ <CardBody>
+ <FormGroup fieldId={'dependencies'}>
+ <LabelGroup
+ // categoryName={"Dependencies"}
+ numLabels={dependencies.length}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addDepencency()}>
+ Add
+ </Button>
+ }
+ >
+ {dependencies.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteDependency(val)}
+ onEditCancel={(_event, prevText) => {}}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameDependency(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameDependency(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameDependency(index, newText)
+ } else {
+ renameDependency(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </CardBody>
+ </Card>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx
new file mode 100644
index 00000000..728d4689
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx
@@ -0,0 +1,36 @@
+/*
+ * 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 {
+ PageSection,
+} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+import {KameletAnnotationsPanel} from "./KameletAnnotationsPanel";
+import {KameletDefinitionsPanel} from "./KameletDefinitionsPanel";
+
+export function KameletDesigner() {
+
+ return (
+ <div className="kamelet-designer">
+ <div className="main">
+ <KameletAnnotationsPanel/>
+ <KameletDefinitionsPanel/>
+ </div>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletInput.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletInput.tsx
new file mode 100644
index 00000000..6dd58f38
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletInput.tsx
@@ -0,0 +1,139 @@
+/*
+ * 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, {useEffect, useState} from "react";
+import {
+ GridItem,
+ FormGroup,
+ InputGroup,
+ InputGroupItem,
+ TextInput,
+ InputGroupText,
+ ToggleGroup,
+ ToggleGroupItem,
+ capitalize,
+ TextArea
+} from "@patternfly/react-core";
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+
+interface Props {
+ label: string;
+ type: string;
+ span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
+ elementKey: string;
+ value: any;
+ isRequired: boolean;
+ options?: string[];
+ setValue: (value: string) => void;
+}
+
+export function KameletInput(props: Props) {
+
+ const [inputValue, setInputValue] = useState(props.value);
+ const [checkChanges, setCheckChanges] = useState<boolean>(false);
+
+ useEffect(()=> {
+ if (checkChanges) {
+ const interval = setInterval(() => {
+ if (props.value !== inputValue) {
+ saveValue(inputValue);
+ }
+ }, 1000);
+ return () => {
+ clearInterval(interval)
+ }
+ }
+ }, [checkChanges, inputValue])
+
+ function saveValue(value?: string) {
+ setCheckChanges(false)
+ props.setValue(value ? value : inputValue);
+ }
+
+ function getTextField() {
+ return (
+ <InputGroup>
+ <InputGroupItem isFill>
+ <TextInput className="text-field" type="text" id={props.elementKey} name={props.elementKey}
+ onChange={(_, value) => {
+ setInputValue(value);
+ setCheckChanges(true);
+ }}
+ onBlur={() => saveValue()}
+ value={inputValue}/>
+ </InputGroupItem>
+ </InputGroup>
+ )
+ }
+
+ function getTextArea() {
+ return (<InputGroup>
+ <InputGroupItem isFill> <TextArea type="text" id={props.elementKey} name={props.elementKey} autoResize
+ onChange={(_, value) => {
+ setInputValue(value);
+ setCheckChanges(true);
+ }}
+ onBlur={() => saveValue()}
+ value={inputValue}/></InputGroupItem></InputGroup>)
+ }
+
+ function getIcon() {
+ return (<InputGroup>
+ <InputGroupText id="username">
+ <svg className="icon">
+ <image href={props.value} className="icon"/>
+ </svg>
+ </InputGroupText>
+ <InputGroupItem isFill>
+ <TextInput className="text-field" type="text" id={props.elementKey} name={props.elementKey}
+ onChange={(_, value) => setInputValue(value)}
+ onBlur={() => saveValue()}
+ value={inputValue}/>
+ </InputGroupItem>
+ </InputGroup>);
+ }
+
+ function getToggleGroup() {
+ return (<ToggleGroup aria-label={props.elementKey} id={props.elementKey} name={props.elementKey}>
+ {props.options?.map((option: string) =>
+ <ToggleGroupItem
+ key={option}
+ text={capitalize(option)}
+ buttonId="toggle-group-single-1"
+ isSelected={inputValue === option}
+ onChange={(_, selected) => {
+ setInputValue(option);
+ saveValue(option);
+ setCheckChanges(false);
+ }}
+ />
+ )}
+ </ToggleGroup>)
+ }
+
+ return (
+ <GridItem span={props.span}>
+ <FormGroup label={props.label} fieldId={props.elementKey} isRequired={props.isRequired}>
+ {props.type === 'text' && getTextField()}
+ {props.type === 'icon' && getIcon()}
+ {props.type === 'toggle' && getToggleGroup()}
+ {props.type === 'textArea' && getTextArea()}
+ </FormGroup>
+ </GridItem>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletTypesOutCard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletTypesOutCard.tsx
new file mode 100644
index 00000000..bb2fde3a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletTypesOutCard.tsx
@@ -0,0 +1,105 @@
+/*
+ * 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, CardBody, CardTitle, FormGroup, FormHelperText, HelperText, HelperTextItem, Label, LabelGroup,} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {PlusCircleIcon} from '@patternfly/react-icons';
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+
+export function KameletTypesOutCard() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ const dependencies: string[] = [...(integration.spec.dependencies || [])];
+
+
+ function setDependencies(deps: string[]) {
+ const i = CamelUtil.cloneIntegration(integration);
+ i.spec.dependencies = deps;
+ setIntegration(i, true);
+ }
+
+ function addDepencency() {
+ dependencies.push("dependency")
+ setDependencies(dependencies);
+ }
+
+ function deleteDependency(val: string) {
+ setDependencies(dependencies.filter(e => e !== val));
+ }
+
+ function renameDependency(index: number, newVal: string) {
+ dependencies[index] = newVal;
+ setDependencies(dependencies);
+ }
+
+ return (
+ <Card isClickable isCompact ouiaId="PropertyCard" className="property-card">
+ <CardTitle>
+ Dependencies
+ </CardTitle>
+ <CardBody>
+ <FormHelperText>
+ <HelperText>
+ <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
+ </HelperText>
+ </FormHelperText>
+ </CardBody>
+ <CardBody>
+ <FormGroup fieldId={'dependencies'}>
+ <LabelGroup
+ // categoryName={"Dependencies"}
+ numLabels={dependencies.length}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addDepencency()}>
+ Add
+ </Button>
+ }
+ >
+ {dependencies.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteDependency(val)}
+ onEditCancel={(_event, prevText) => {}}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameDependency(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameDependency(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameDependency(index, newText)
+ } else {
+ renameDependency(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </CardBody>
+ </Card>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/kamelet.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/kamelet.css
new file mode 100644
index 00000000..f909f7ee
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/kamelet.css
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+.karavan .kamelet-designer {
+ display: block;
+ height: 100vh;
+ width: 100%;
+ overflow-y: auto;
+ padding: 16px 16px 106px 16px;
+}
+
+.karavan .kamelet-designer .main {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+.karavan .kamelet-designer .icon {
+ height: 20px;
+ width: 20px;
+ border: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+/*.karavan .kamelet-designer .properties {*/
+/* padding: 10px 10px 10px 10px;*/
+/* background: transparent;*/
+/* width: 100%;*/
+/* height: 100%;*/
+/* overflow: auto;*/
+/* display: flex;*/
+/* flex-direction: column;*/
+/* justify-content: space-between;*/
+/*}*/
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/karavan.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/karavan.css
new file mode 100644
index 00000000..9729ffe9
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/karavan.css
@@ -0,0 +1,456 @@
+/*
+ * 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.
+ */
+/*:root {*/
+ /*--pf-v6-global--FontSize--md: 14px;*/
+ /*--pf-v6-c-page__main-section--PaddingTop: 1em;*/
+ /*--pf-v6-c-page__main-section--PaddingBottom: 1em;*/
+ /*--pf-v6-c-page__main-section--PaddingLeft: 1em;*/
+ /*--pf-v6-c-page__main-section--PaddingRight: 1em;*/
+/*}*/
+
+.karavan .tools-section {
+ padding: 0 0 0 16px;
+}
+
+.karavan .tools-section-wrapper {
+ padding: 0 0 0 16px;
+ border-bottom: 1px solid #eee;
+ background-color: white;
+}
+.karavan .tools-section-tabs {
+ padding: 0;
+ border-bottom: 1px solid #eee;
+ background-color: white;
+}
+
+.karavan .tools-section .dsl-title {
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .tools-section .dsl-title .title {
+ margin-right: 16px;
+}
+
+.karavan .tools-section .tools .header {
+ display: flex;
+ flex-direction: row;
+}
+
+.karavan .tools-section .tools .header .labels {
+ height: fit-content;
+ margin-left: 3px;
+}
+
+.karavan .brand {
+ height: 36px;
+}
+
+.karavan .pf-v6-c-switch__input:focus ~ .pf-v6-c-switch__toggle,
+.pf-v6-c-modal-box .pf-v6-c-switch__input:focus ~ .pf-v6-c-switch__toggle {
+ outline: transparent;
+ outline-offset: 0;
+}
+
+.karavan .header-button {
+ /*margin-left: var(--pf-v6-c-page__header-tools--MarginRight);*/
+}
+
+.karavan .page-header {
+ display: flex;
+ justify-content: space-between;
+}
+
+.karavan .page-header .top-toolbar .pf-v6-c-page__header-tools {
+ margin-right: 0;
+}
+
+.karavan .page-header .top-toolbar {
+ width: 100%;
+}
+
+.karavan .page-header .pf-v6-c-page__header-brand {
+ padding-right: 16px;
+}
+
+.filler {
+ width: 100%;
+}
+
+.modal-footer {
+ width: 100%;
+}
+
+.modal-footer .deploy-buttons .pf-v6-c-form__actions {
+ justify-content: flex-end;
+ margin-top: 16px;
+}
+
+.modal-footer .deploy-buttons .pf-v6-c-button {
+ margin-left: 16px;
+}
+
+.action-buttons .pf-v6-c-form__actions {
+ justify-content: flex-end;
+ margin-top: 16px;
+}
+
+.action-buttons .pf-v6-c-button {
+ margin-left: 16px;
+}
+
+.pf-v6-c-modal-box__footer .hidden {
+ display: none;
+}
+
+.upload-buttons .pf-v6-c-form__actions {
+ margin-top: 20px;
+ justify-content: flex-end;
+}
+
+/*integration page*/
+.integration-page .integration-card {
+ cursor: pointer;
+ height: 160px;
+}
+
+.integration-page .integration-card .pf-v6-c-card__header {
+ padding-right: 6px;
+}
+
+.integration-page .integration-card .icon {
+ height: 24px;
+}
+
+.integration-page .integration-card .delete-button {
+ font-size: 17px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ background: transparent;
+ color: #b1b1b7;
+ visibility: hidden;
+}
+
+.integration-page .integration-card:hover .delete-button {
+ visibility: visible;
+}
+
+/*kamelets*/
+.kamelets-page .kamelet-card {
+ cursor: pointer;
+ height: 160px;
+}
+
+.kamelets-page .kamelet-card .pf-v6-c-card__header .custom {
+ margin-left: auto;
+}
+
+.kamelets-page .kamelet-card .pf-v6-c-card__header .pf-v6-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+}
+
+.kamelets-page .kamelet-card .pf-v6-c-card__title {
+ font-size: 15px;
+ font-weight: 400;
+}
+
+.kamelets-page .kamelet-card .pf-v6-c-card__body {
+ overflow: hidden;
+ position: relative;
+ line-height: 1.6em;
+}
+
+.kamelets-page .kamelet-card .icon {
+ height: 24px;
+ max-width: 24px;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-right: 5px;
+ border: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.kamelets-page .kamelet-card .header-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+}
+
+.kamelets-page .kamelet-card .header-labels .pf-v6-c-card__header-main {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.kamelets-page .kamelet-card .footer-labels {
+ padding: 5px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.kamelets-page .kamelet-card .version,
+.kamelets-page .kamelet-card .support-type,
+.kamelets-page .kamelet-card .support-level {
+ white-space: nowrap;
+}
+
+.kamelets-page .kamelet-card .labels {
+ opacity: 0.5;
+ font-weight: 200;
+}
+
+.kamelets-page .kamelet-card:hover .labels {
+ opacity: 1;
+}
+
+/*kamelet modal*/
+.kamelet-modal-card .pf-v6-c-card__header {
+ padding-right: 6px;
+ display: flex;
+ justify-content: space-between;
+}
+
+.kamelet-modal-card .pf-v6-c-card__title {
+ font-weight: 600;
+}
+
+.kamelet-modal-card .description {
+ overflow: hidden;
+ position: relative;
+ max-width: 600px;
+}
+
+.kamelet-modal-card .icon {
+ height: 36px;
+ width: 36px;
+ margin-top: auto;
+ margin-bottom: auto;
+ border: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.karavan .page {
+ height: 100vh;
+ width: 100%;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.karavan main {
+ overflow: hidden;
+}
+
+
+
+.element-builder .add-button {
+ top: 0;
+ right: 5px;
+ font-size: 15px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: 3px auto 0 auto;
+ background: transparent;
+ visibility: hidden;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ width: 16px;
+}
+
+.element-builder .add-button svg {
+ margin: 0 auto 3px auto;
+}
+
+.element-builder:hover .add-button,
+.dsl-gallery {
+ margin-top: 16px;
+}
+
+.move-modal {
+ width: 270px !important;
+}
+
+.move-modal .pf-v6-c-modal-box__body {
+ margin-right: 0 !important;
+}
+
+.move-modal .pf-v6-m-plain {
+ display: none;
+}
+
+.yaml-code {
+ overflow: auto;
+ height: 100%;
+ width: 100%;
+ padding-bottom: 100px;
+}
+
+.pf-v6-c-popover__footer {
+ overflow-wrap: anywhere;
+}
+
+/*YAML*/
+.karavan .yaml-page {
+ height: 100px;
+}
+
+
+/* Help */
+.dont-show {
+ margin-right: auto;
+}
+
+/* Project Tools */
+.karavan .project-builder {
+ height: 100%;
+}
+
+.karavan .project-builder .tools-section {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.karavan .project-builder .pf-v6-c-toolbar__content {
+ padding: 0;
+}
+
+.karavan .project-builder .card-header svg {
+ margin-right: 6px;
+}
+
+.karavan .project-builder .card-disabled {
+ opacity: 0.4;
+}
+
+.karavan .project-builder .pf-v6-c-form {
+ --pf-v6-c-form--GridGap: 1em;
+}
+
+.karavan .project-builder .pf-v6-c-card__body {
+ --pf-v6-c-card--child--PaddingRight: 0.5em;
+ --pf-v6-c-card--child--PaddingBottom: 1em;
+ --pf-v6-c-card--child--PaddingLeft: 1em;
+}
+
+.karavan .project-builder .pf-v6-c-card__header {
+ --pf-v6-c-card--first-child--PaddingTop: 0.5em;
+}
+
+.karavan .project-builder .center {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ gap: 10px;
+ padding: 10px;
+}
+
+.karavan .project-builder .center-column {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.karavan .project-builder .footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ padding: 10px;
+}
+
+.karavan .project-builder .footer .progress {
+ flex-grow: 4;
+}
+
+.karavan .project-builder .footer .buttons {
+ height: 60px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+}
+
+.karavan .project-builder .project-properties td {
+ padding: 0;
+ margin: 0;
+}
+
+.karavan .project-builder .project-properties td,
+.karavan .project-builder .project-properties tr {
+ border: none;
+}
+
+.karavan .project-builder .project-properties .delete-button {
+ padding: 0 0 0 6px;
+ margin: 0;
+}
+
+.karavan .project-builder .add-button {
+ width: fit-content;
+ margin-top: 6px;
+}
+
+.root .tooltip-required-field .pf-v6-c-tooltip__content {
+ text-align: start;
+}
+
+.karavan .kamelet-section {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .kamelets-page {
+ overflow: auto;
+ flex-shrink: unset;
+ flex-grow: 1;
+ margin-bottom: 100px;
+}
+
+.karavan .scrolled-page {
+ overflow: auto;
+ flex-shrink: unset;
+ flex-grow: 1;
+}
+
+.karavan .knowledbase-eip-section .pf-v6-c-toggle-group {
+ margin: 16px;
+}
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ appearance: none;
+ margin: 0;
+}
+
+.resize-handler {
+ background-color: var(--pf-t--global--border--color--default);
+ width: 1px;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.css
new file mode 100644
index 00000000..cd8b3f6a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.css
@@ -0,0 +1,406 @@
+/*
+ * 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.
+ */
+
+/*Properties*/
+
+.karavan .main-properties {
+ width: 100%;
+ height: 100%;
+ padding-bottom: 64px;
+ border-left-color: var(--pf-t--global--border--color--default);
+ border-left-style: solid;
+ border-left-width: var(--pf-t--global--border--width--box--default);
+}
+
+.karavan .main-properties .main-tabs-wrapper .main-tabs .top-menu-item {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ width: 100%;
+}
+
+.karavan .main-properties .main-tabs-wrapper .main-tabs .top-menu-item .count {
+ background: var(--pf-t--global--color--brand--default);
+ color: white;
+ height: fit-content;
+ margin-top: auto;
+ margin-bottom: auto;
+ min-width: 0;
+}
+
+.karavan .main-properties .main-tabs-wrapper .main-tabs .pf-v6-c-tabs__link .pf-v6-c-tabs__item-icon {
+ /*height: 24px;*/
+ /*margin-right: 0;*/
+}
+
+.karavan .main-properties .main-tabs-wrapper .main-tabs .pf-v6-c-tabs__item-text {
+ /*font-weight: bold;*/
+ /*margin-top: auto;*/
+ /*margin-bottom: auto;*/
+ /*margin-right: 6px;*/
+}
+
+.karavan .main-properties .main-tabs-wrapper .hide-log {
+ white-space: nowrap;
+ margin-right: 16px;
+}
+
+.karavan .properties {
+ padding: 8px 8px 8px 8px;
+ /*background-color: white;*/
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ /*display: flex;*/
+ /*flex-direction: column;*/
+ /*justify-content: space-between;*/
+}
+
+.karavan .properties .headers {
+ grid-row-gap: 8px;
+ row-gap: 8px;
+ display: contents;
+}
+
+.karavan .properties .headers .top {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ /*justify-content: space-between;*/
+ align-items: center;
+ gap: 8px;
+}
+
+.karavan .properties .headers .top h1 {
+ /*width: 100%;*/
+ margin-top: auto;
+ margin-bottom: auto;
+ text-wrap: nowrap;
+}
+
+.karavan .properties .headers .top .pf-v6-c-switch {
+ column-gap: 6px;
+}
+
+.karavan .properties .headers .top .description-help-icon {
+ /*color: var(--pf-v6-c-form__group-label-help--Color);*/
+ cursor: pointer;
+}
+.karavan .properties .headers .top:hover .description-help-icon {
+ color: unset;
+}
+
+.karavan .properties .headers .step-type-switch {
+ column-gap: 6px;
+}
+
+
+.karavan .properties .footer {
+ height: 100%;
+ display: contents;
+}
+
+.karavan .properties .pf-v6-c-form {
+ row-gap: 10px;
+ .pf-v6-c-form__group {
+ gap: 0.1em;
+ }
+}
+
+.karavan .properties .pf-v6-c-form__group-label {
+ display: flex;
+ justify-content: space-between;
+ .pf-v6-c-form__group-label-help .pf-v6-c-button {
+ padding: 0;
+ visibility: hidden;
+ }
+}
+
+.karavan .properties .component-headers .pf-v6-c-button {
+ padding: 0;
+}
+
+.karavan .properties .pf-v6-c-form__group:hover {
+ .pf-v6-c-form__group-label-help .pf-v6-c-button {
+ visibility: visible;
+ }
+}
+
+.karavan .properties .dsl-property-form-group .pf-v6-c-form__label {
+ display: flex;
+}
+
+/*ok till there*/
+
+.karavan .properties .pf-v6-c-expandable-section {
+ .pf-v6-c-expandable-section__toggle .pf-v6-c-button {
+ padding: 1px 0 1px 0;
+ }
+}
+.karavan .properties .pf-m-expanded {}
+
+.karavan .properties .pf-v6-c-form-control:focus-within {
+ --pf-v6-c-form-control--after--BorderBottomColor: var(--pf-v6-c-form-control--after--BorderBottomColor);
+ --pf-v6-c-form-control--after--BorderBottomWidth: var(--pf-v6-c-form-control--after--BorderBottomWidth);
+}
+
+.karavan .properties .pf-v6-c-select {
+ --pf-v6-c-select__toggle--FontSize: 14px;
+ --pf-v6-c-select__menu-item--FontSize: 14px;
+}
+
+.karavan .properties .input-group .pf-v6-c-text-input-group__text {
+ width: 100%;
+}
+
+.karavan .properties .input-group .pf-v6-c-chip-group,
+.karavan .properties .input-group .pf-v6-c-text-input-group__main,
+.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__list,
+.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__list .pf-v6-c-chip-group__list-item,
+.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__main {
+ display: block;
+}
+
+.karavan .properties .input-group .pf-v6-c-chip-group {
+ margin-left: 0;
+}
+
+.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip .pf-v6-c-chip__text {
+ max-width: inherit;
+}
+
+.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip {
+ width: 100%;
+}
+
+.karavan .properties .input-group .pf-v6-c-text-input-group__utilities {
+ align-items: flex-end;
+ margin: auto;
+}
+
+.karavan .properties .chip .pf-v6-c-button {
+ padding: 4px;
+}
+
+.karavan .properties .expression-title {
+ font-size: 17px;
+ font-weight: bold;
+}
+
+.karavan .properties .text-area {
+ font-size: 13px;
+}
+
+.karavan .properties .pf-v6-c-select__menu-search {
+ padding: 0 6px 6px 6px;
+}
+
+.karavan .properties .pf-v6-c-select__toggle-typeahead {
+ height: auto;
+}
+
+.karavan .properties .pf-v6-c-select__menu-item {
+ /*width: 280px;*/
+}
+
+.karavan .properties .pf-v6-c-select__menu-item-description {
+ overflow-wrap: anywhere;
+}
+
+.karavan .properties .number {
+ display: flex;
+ justify-content: space-between;
+}
+
+.karavan .properties .number .number-property {
+ width: 100%;
+}
+
+.karavan .properties .number .clear-button {
+ color: #b1b1b7;
+ --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-control--BorderRadius);
+ --pf-v6-c-button--disabled--BackgroundColor: var(--pf-v6-c-button--m-control--BackgroundColor);
+ --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-control--BorderWidth);
+ --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-control--BorderColor);
+ background-color: var(--pf-v6-c-button--m-control--BackgroundColor);
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.karavan .properties .help-button {
+ font-size: 12px;
+}
+
+.karavan .properties .component-selector {
+ border-width: var(--pf-t--global--border--width--box--default);
+ border-top-color: var(--pf-t--global--border--color--default);
+ border-right-color: var(--pf-t--global--border--color--default);
+ border-bottom-color: var(--pf-t--global--border--color--default);
+ border-left-color: var(--pf-t--global--border--color--default);
+ border-style: solid;
+}
+
+.karavan .properties .object-value {
+ display: flex;
+ flex-direction: row;
+ /*justify-content: stretch;*/
+ /*align-items: center;*/
+ padding: 6px 8px 0 0;
+ border-width: var(--pf-t--global--border--width--box--default);
+ border-color: var(--pf-t--global--border--color--default);
+ border-style: solid;
+ border-radius: var(--pf-t--global--border--radius--medium);
+ position: relative;
+}
+
+.karavan .properties .object-key-value .object {
+ padding-top: 0;
+}
+
+.karavan .properties .object-value .delete-button {
+ margin: 0;
+ padding: 6px;
+ /*height: 16px;*/
+ color: var(--pf-t--global--icon--color--status--danger--default);
+ position: absolute;
+ bottom: 0;
+ right: 0;
+}
+.karavan .properties .object-value .delete-button svg {
+ fill:var(--pf-t--global--icon--color--status--danger--default);
+}
+
+.karavan .properties .object-key-value,
+.karavan .properties .object-key-value .object-field {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+}
+
+.karavan .properties .object-key-value .delete-button {
+ margin: auto 0 22px 0;
+ padding: 0 0 0 3px;
+ height: 16px;
+ color: #909090;
+}
+
+.karavan .properties .expression,
+.karavan .properties .object,
+.karavan .properties .dataformat,
+.karavan .properties .parameters {
+ padding-top: 0;
+ padding-left: 8px;
+ row-gap: 6px;
+ display: grid;
+ width: 100%;
+}
+
+.karavan .properties .expression .pf-v6-c-form__group-label,
+.karavan .properties .object .pf-v6-c-form__group-label,
+.karavan .properties .dataformat .pf-v6-c-form__group-label,
+.karavan .properties .parameters .pf-v6-c-form__group-label {
+ font-weight: 100;
+}
+
+.karavan .properties .expression .pf-v6-c-form__group,
+.karavan .properties .object .pf-v6-c-form__group,
+.karavan .properties .dataformat .pf-v6-c-form__group,
+.karavan .properties .parameters .pf-v6-c-form__group {
+ margin-bottom: 8px;
+}
+
+.karavan .properties .expression .pf-v6-c-select__menu-wrapper,
+.karavan .properties .object .pf-v6-c-select__menu-wrapper,
+.karavan .properties .dataformat .pf-v6-c-select__menu-wrapper,
+.karavan .properties .parameters .pf-v6-c-select__menu-wrapper {
+ width: 350px;
+}
+
+.karavan .properties .change-button {
+ font-size: 15px;
+ height: 15px;
+ line-height: 1;
+ border: 0;
+ padding: 0;
+ margin: auto auto auto 6px;
+ background: transparent;
+}
+
+.karavan .properties .change-button svg {
+ margin-right: 6px;
+}
+
+.karavan .properties .add-button {
+ color: var(--pf-t--global--color--brand--default);
+}
+
+.karavan .properties .delete-button {
+ color: var(--pf-t--global--icon--color--status--danger--default);
+}
+
+.karavan .properties .pf-v6-c-expandable-section__toggle {
+ margin: 0;
+ padding: 0;
+}
+
+.karavan .properties .pf-v6-c-expandable-section__content {
+ margin: 0;
+}
+
+.karavan .properties .pf-v6-c-expandable-section__content p {
+ min-height: 6px;
+}
+
+.karavan .properties .header-menu-toggle {
+ padding-left: 6px;
+ padding-right: 0;
+}
+
+.karavan .properties .component-headers {
+ margin-left: 24px;
+}
+
+.karavan .properties .component-headers .pf-v6-c-clipboard-copy.pf-m-inline {
+ background-color: transparent;
+}
+
+.karavan .properties .value-changed {
+ /*box-shadow: gold 0px 0px 0px 2px;*/
+ /*border-radius: 3px;*/
+}
+
+.karavan .properties .value-changed-label {
+ background-color: var(--pf-t--global--color--nonstatus--yellow--default);
+ color: var(--pf-t--color--gray--95);
+ padding: 0 2px 0 2px;
+ transition: background-color 0.5s ease;
+}
+
+.karavan .properties .value-sensitive-invalid {
+ background-color: var(--pf-t--global--icon--color--status--danger--default);
+}
+.karavan .properties .property-selector-group .property-selector .pf-v6-c-toggle-group__button:before {
+ border-start-end-radius: 0;
+ border-end-end-radius: 0;
+}
+
+.karavan .properties .property-selector .pf-v6-c-toggle-group__button {
+ padding-left: 6px;
+ padding-right: 6px;
+}
+
+
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.tsx
new file mode 100644
index 00000000..edc0e5e9
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/DslProperties.tsx
@@ -0,0 +1,268 @@
+/*
+ * 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, {ReactElement, useEffect, useState} from 'react';
+import {
+ Button,
+ Content,
+ ContentVariants,
+ ExpandableSection,
+ Form,
+ TextInputGroup,
+ TextInputGroupMain,
+ TextInputGroupUtilities,
+ Title,
+ ToggleGroup,
+ ToggleGroupItem,
+ Tooltip,
+} from '@patternfly/react-core';
+import './DslProperties.css';
+import {DataFormatField} from "./property/DataFormatField";
+import {DslPropertyField} from "./property/DslPropertyField";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {CamelUi} from "../utils/CamelUi";
+import {CamelMetadataApi, DataFormats, PropertyMeta} from "@karavan-core/model/CamelMetadata";
+import {IntegrationHeader} from "../utils/IntegrationHeader";
+import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
+import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {usePropertiesHook} from "./usePropertiesHook";
+import {CamelDisplayUtil} from "@karavan-core/api/CamelDisplayUtil";
+import {PropertiesHeader} from "./PropertiesHeader";
+import {PropertyUtil} from "./property/PropertyUtil";
+import {usePropertiesStore} from "./PropertyStore";
+import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
+import {RouteTemplateDefinition} from "@karavan-core/model/CamelDefinition";
+
+interface Props {
+ expressionEditor: React.ComponentType<any>;
+}
+
+export function DslProperties(props: Props) {
+
+ const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+
+ const {
+ cloneElement,
+ onDataFormatChange,
+ onPropertyChange,
+ onParametersChange,
+ onExpressionChange
+ } =
+ usePropertiesHook();
+
+ const [selectedStep, setParameterPlaceholders, tab]
+ = useDesignerStore((s) => [s.selectedStep, s.setParameterPlaceholders, s.tab], shallow)
+
+ const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, sensitiveOnly, setSensitiveOnly, setPropertyFilter, setRequiredOnly]
+ = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, s.requiredOnly, s.setChangedOnly, s.sensitiveOnly, s.setSensitiveOnly, s.setPropertyFilter, s.setRequiredOnly], shallow)
+
+ const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
+
+ useEffect(() => {
+ // setRequiredOnly(false);
+ // setChangedOnly(false);
+ // setSensitiveOnly(false);
+ setPropertyFilter('');
+ getRouteTemplateParameters()
+ }, [selectedStep?.uuid])
+
+ function getRouteTemplateParameters() {
+ if (selectedStep) {
+ const root = CamelDefinitionApiExt.findTopRouteElement(integration, selectedStep.uuid);
+ if ('RouteTemplateDefinition' === root?.dslName) {
+ const paramPlaceholders: [string, string][] = (root as RouteTemplateDefinition).parameters?.map(p => [p.name, p.description || '']) || [];
+ setParameterPlaceholders(paramPlaceholders);
+ }
+ }
+ }
+
+ function getClonableElementHeader(): ReactElement {
+ const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep);
+ const description = selectedStep?.dslName ? CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description : title;
+ const descriptionLines: string [] = description ? description?.split("\n") : [""];
+ return (
+ <div className="headers">
+ <div className="top">
+ <Title headingLevel="h1" size="md">{title}</Title>
+ <Tooltip content="Clone element" position="bottom">
+ <Button variant="link" onClick={() => cloneElement()} icon={<CloneIcon/>}/>
+ </Tooltip>
+ </div>
+ {descriptionLines.map((desc, index, array) => <Content key={index}
+ component={ContentVariants.p}>{desc}</Content>)}
+ </div>
+ )
+ }
+
+ function getPropertiesHeader(): ReactElement {
+ if (tab === 'routes') return <PropertiesHeader/>
+ else return getClonableElementHeader();
+ }
+
+ function getProperties(): PropertyMeta[] {
+ const dslName = selectedStep?.dslName;
+ return CamelDefinitionApiExt.getElementProperties(dslName)
+ .filter((p: PropertyMeta) => dslName === 'InterceptSendToEndpointDefinition' || p.name !== 'uri') // do not show uri except InterceptSendToEndpointDefinition
+ .filter((p: PropertyMeta) => p.name !== 'id') // do not show id
+ // .filer((p: PropertyMeta) => (showAdvanced && p.label.includes('advanced')) || (!showAdvanced && !p.label.includes('advanced')))
+ .filter((p: PropertyMeta) => !p.isObject || (p.isObject && !CamelUi.dslHasSteps(p.type)) || (p.name === 'onWhen'))
+ .filter((p: PropertyMeta) => !(dslName === 'RestDefinition' && ['get', 'post', 'put', 'patch', 'delete', 'head'].includes(p.name)))
+ .filter((p: PropertyMeta) => !(dslName === 'RouteTemplateDefinition' && ['route', 'beans'].includes(p.name)));
+ // .filter((p: PropertyMeta) => dslName && !(['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(dslName) && ['param', 'responseMessage'].includes(p.name))) // TODO: configure this properties
+ }
+
+ function sortProperties(p1: PropertyMeta, p2: PropertyMeta): number {
+ const isConvert = selectedStep?.dslName.startsWith('Convert');
+
+ if (isConvert) {
+ if (p1.name === 'description' && p2.name !== 'description') return 1;
+ if (p1.name !== 'description' && p2.name === 'description') return -1;
+
+ if (p1.name === 'name' && p2.name !== 'name') return -1;
+ if (p1.name !== 'name' && p2.name === 'name') return 1;
+ }
+
+ if (selectedStep?.dslName.startsWith('Set')) {
+ if (p1.name === 'name' && p2.name !== 'name') return -1;
+ if (p1.name !== 'name' && p2.name === 'name') return 1;
+ }
+
+ return 0;
+ }
+
+ function getPropertyFields(properties: PropertyMeta[]) {
+ return (<>
+ {properties.sort(sortProperties).map((property: PropertyMeta) =>
+ <DslPropertyField key={property.name}
+ property={property}
+ element={selectedStep}
+ value={getPropertyValue(property)}
+ onExpressionChange={onExpressionChange}
+ onParameterChange={onParametersChange}
+ onDataFormatChange={onDataFormatChange}
+ onPropertyChange={onPropertyChange}
+ expressionEditor={props.expressionEditor}
+ />
+ )}
+ </>)
+ }
+
+ function getPropertyValue(property: PropertyMeta) {
+ return selectedStep ? (selectedStep as any)[property.name] : undefined;
+ }
+
+ function getFilteredProperties(): PropertyMeta[] {
+ let propertyMetas = !dataFormatElement ? getProperties() : getProperties().filter(p => !dataFormats.includes(p.name));
+ const filter = propertyFilter.toLocaleLowerCase()
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.name.toLocaleLowerCase().includes(filter) || p.label.toLocaleLowerCase().includes(filter) || p.displayName.toLocaleLowerCase().includes(filter));
+ if (requiredOnly) {
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.required);
+ }
+ if (changedOnly) {
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+ }
+ if (sensitiveOnly) {
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.secret);
+ }
+ return propertyMetas
+ }
+
+ const dataFormats = DataFormats.map(value => value[0]);
+ const dataFormatElement = selectedStep !== undefined && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName);
+ const properties = getFilteredProperties();
+ const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
+ const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
+
+ function getPropertySelector() {
+ return (
+ <TextInputGroup className='property-selector-group'>
+ <TextInputGroupUtilities>
+ <ToggleGroup className='property-selector' aria-label="properties selctor">
+ <ToggleGroupItem
+ text="Required"
+ buttonId="requiredOnly"
+ isSelected={requiredOnly}
+ onChange={(_, selected) => setRequiredOnly(selected)}
+ />
+ <ToggleGroupItem
+ text="Changed"
+ buttonId="changedOnly"
+ isSelected={changedOnly}
+ onChange={(_, selected) => setChangedOnly(selected)}
+ />
+ <ToggleGroupItem
+ text="Sensitive"
+ buttonId="sensitiveOnly"
+ isSelected={sensitiveOnly}
+ onChange={(_, selected) => setSensitiveOnly(selected)}
+ />
+ </ToggleGroup>
+ </TextInputGroupUtilities>
+ <TextInputGroupMain
+ value={propertyFilter}
+ placeholder="filter by name"
+ type="text"
+ autoComplete={"off"}
+ autoFocus={true}
+ onChange={(_event, value) => setPropertyFilter(value)}
+ aria-label="filter by name"
+ />
+ <TextInputGroupUtilities>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" onClick={_ => setPropertyFilter('')}/>
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ )
+ }
+
+ function getPropertySelectorChanged(): boolean {
+ return requiredOnly || changedOnly || sensitiveOnly || propertyFilter?.trim().length > 0;
+ }
+
+ function getShowExpanded(): boolean {
+ return showAdvanced || getPropertySelectorChanged();
+ }
+
+ return (
+ <div key={selectedStep ? selectedStep.uuid : 'integration'}
+ className='properties'>
+ <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
+ {selectedStep === undefined && <IntegrationHeader/>}
+ {selectedStep && getPropertiesHeader()}
+ {selectedStep !== undefined && getPropertySelector()}
+ {getPropertyFields(propertiesMain)}
+ {selectedStep && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName) &&
+ <DataFormatField
+ integration={integration}
+ dslName={selectedStep.dslName}
+ value={selectedStep}
+ onDataFormatChange={onDataFormatChange}
+ expressionEditor={props.expressionEditor}
+ />
+ }
+ {selectedStep && propertiesAdvanced.length > 0 &&
+ <ExpandableSection
+ toggleText={'Processors advanced properties'}
+ onToggle={(_event, isExpanded) => setShowAdvanced(!showAdvanced)}
+ isExpanded={getShowExpanded()}>
+ <div className="parameters">
+ {getPropertyFields(propertiesAdvanced)}
+ </div>
+ </ExpandableSection>}
+ </Form>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/MainPropertiesPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/MainPropertiesPanel.tsx
new file mode 100644
index 00000000..41fdeec5
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/MainPropertiesPanel.tsx
@@ -0,0 +1,60 @@
+/*
+ * 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 {Tab, Tabs, TabTitleText,} from '@patternfly/react-core';
+import '@features/project/designer/property/DslProperties.css';
+
+export function MainPropertiesPanel() {
+
+ const [activeTabKey, setActiveTabKey] = React.useState<string | number>();
+ const handleTabClick = (event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent, tabIndex: string | number) => {
+ setActiveTabKey(tabIndex);
+ };
+
+
+ function getTab(title: string, icon: string, error: boolean = false) {
+ const color = error ? "red" : "initial";
+ return (
+ <div className="top-menu-item" style={{color: color}}>
+ <TabTitleText>{title}</TabTitleText>
+ </div>
+ )
+ }
+
+ function getPropertiesPanelTabs() {
+ return (
+ <div>
+ <Tabs activeKey={activeTabKey}
+ onSelect={handleTabClick}
+ isFilled
+ aria-label="PropertyTypes"
+ role="proeprty-type"
+ >
+ <Tab eventKey={'properties'} title={getTab('Properties', 'properties')} aria-label="Properties"/>
+ </Tabs>
+ </div>
+ )
+ }
+
+
+ return (
+ <div className='main-properties'>
+ {getPropertiesPanelTabs()}
+ </div>
+ )
+
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertiesHeader.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertiesHeader.tsx
new file mode 100644
index 00000000..d5b5ed35
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertiesHeader.tsx
@@ -0,0 +1,358 @@
+/*
+ * 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, {ReactElement, useEffect, useRef, useState} from 'react';
+import {
+ Badge,
+ Button,
+ ClipboardCopy,
+ Content,
+ ContentVariants,
+ Dropdown,
+ DropdownItem,
+ DropdownList,
+ ExpandableSection,
+ Flex,
+ FlexItem,
+ FormGroupLabelHelp,
+ Label,
+ MenuToggle,
+ MenuToggleElement,
+ Popover,
+ Switch,
+ Title,
+ Tooltip,
+} from '@patternfly/react-core';
+import './DslProperties.css';
+import {CamelUi} from "../utils/CamelUi";
+import {useDesignerStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {usePropertiesHook} from "./usePropertiesHook";
+import {CamelDisplayUtil} from "@karavan-core/api/CamelDisplayUtil";
+import {EllipsisVIcon} from '@patternfly/react-icons';
+import {ComponentApi} from "@karavan-core/api/ComponentApi";
+import {CamelMetadataApi} from "@karavan-core/model/CamelMetadata";
+import {useRouteDesignerHook} from "../route/useRouteDesignerHook";
+
+export function PropertiesHeader() {
+
+ const {saveAsRoute, convertStep, onPropertyChange} = usePropertiesHook();
+ const {openSelectorToReplaceFrom} = useRouteDesignerHook();
+
+ const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow)
+
+ const [isDescriptionExpanded, setIsDescriptionExpanded] = useState<boolean>(false);
+ const [isHeadersExpanded, setIsHeadersExpanded] = useState<boolean>(false);
+ const [isExchangePropertiesExpanded, setIsExchangePropertiesExpanded] = useState<boolean>(false);
+ const [isMenuOpen, setMenuOpen] = useState<boolean>(false);
+ const [stepIsPoll, setStepIsPoll] = React.useState(false);
+ const [stepDynamic, setStepDynamic] = React.useState(false);
+ const [stepWireTap, setStepWireTap] = React.useState(false);
+ const labelHelpRef = useRef(null);
+
+ useEffect(() => {
+ setStepDynamic(selectedStep?.dslName === 'ToDynamicDefinition')
+ setStepIsPoll(selectedStep?.dslName === 'PollDefinition')
+ setStepWireTap(selectedStep?.dslName === 'WireTapDefinition')
+ }, [])
+
+ useEffect(() => {
+ setMenuOpen(false)
+ }, [selectedStep])
+
+ function getHeaderMenu(): ReactElement {
+ const hasSteps = selectedStep?.hasSteps();
+ const targetDsl = CamelUi.getConvertTargetDsl(selectedStep?.dslName);
+ const targetDslTitle = targetDsl?.replace("Definition", "");
+ const showMenu = hasSteps || targetDsl !== undefined;
+ return showMenu ?
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', width: '100%'}}>
+ <Dropdown
+ popperProps={{position: "end"}}
+ isOpen={isMenuOpen}
+ onSelect={() => {
+ }}
+ onOpenChange={(isOpen: boolean) => setMenuOpen(isOpen)}
+ toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
+ <MenuToggle
+ className="header-menu-toggle"
+ ref={toggleRef}
+ aria-label="menu"
+ variant="plain"
+ onClick={() => setMenuOpen(!isMenuOpen)}
+ isExpanded={isMenuOpen}
+ >
+ <EllipsisVIcon/>
+ </MenuToggle>
+ )}
+ >
+ <DropdownList>
+ {isFrom &&
+ <DropdownItem key="changeFrom" onClick={(ev) => {
+ ev.preventDefault()
+ openSelectorToReplaceFrom((selectedStep as any).id)
+ setMenuOpen(false);
+ }}>
+ Change From...
+ </DropdownItem>}
+ {hasSteps &&
+ <DropdownItem key="saveStepsRoute" onClick={(ev) => {
+ ev.preventDefault()
+ if (selectedStep) {
+ saveAsRoute(selectedStep, true);
+ setMenuOpen(false);
+ }
+ }}>
+ Save Steps to Route
+ </DropdownItem>}
+ {hasSteps && !isFrom &&
+ <DropdownItem key="saveElementRoute" 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>
+ </div>
+ : <></>;
+ }
+
+ function getExchangePropertiesSection(): ReactElement {
+ return (
+ <ExpandableSection toggleText='Exchange Properties'
+ onToggle={(_event, isExpanded) => setIsExchangePropertiesExpanded(!isExchangePropertiesExpanded)}
+ isExpanded={isExchangePropertiesExpanded}>
+ <Flex className='component-headers' direction={{default: "column"}}>
+ {exchangeProperties.map((header, index, array) =>
+ <div key={index} style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', padding: 0}}>
+ <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
+ isCode>
+ {header.name}
+ </ClipboardCopy>
+ <Popover
+ position={"left"}
+ headerContent={header.name}
+ bodyContent={header.description}
+ footerContent={
+ <Flex>
+ <Content component={ContentVariants.p}>{header.javaType}</Content>
+ <FlexItem align={{default: 'alignRight'}}>
+ <Badge isRead>{header.label}</Badge>
+ </FlexItem>
+ </Flex>
+ }
+ >
+ <FormGroupLabelHelp aria-label="More info"/>
+ </Popover>
+ </div>
+ )}
+ </Flex>
+ </ExpandableSection>
+ )
+ }
+
+ function getComponentHeadersSection(): ReactElement {
+ return (
+ <ExpandableSection toggleText='Headers'
+ onToggle={(_event, isExpanded) => setIsHeadersExpanded(!isHeadersExpanded)}
+ isExpanded={isHeadersExpanded}>
+ <Flex className='component-headers' direction={{default: "column"}}>
+ {headers.filter((header) => groups.includes(header.group))
+ .map((header, index, array) =>
+ <Flex key={index}>
+ <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
+ isCode>
+ {header.name}
+ </ClipboardCopy>
+ <FlexItem align={{default: 'alignRight'}}>
+ <Popover
+ triggerRef={labelHelpRef}
+ position={"left"}
+ headerContent={header.name}
+ bodyContent={header.description}
+ footerContent={
+ <Flex>
+ <Content component={ContentVariants.p}>{header.javaType}</Content>
+ <FlexItem align={{default: 'alignRight'}}>
+ <Badge isRead>{header.group}</Badge>
+ </FlexItem>
+ </Flex>
+ }
+ >
+ <FormGroupLabelHelp ref={labelHelpRef} aria-label="More info"/>
+ </Popover>
+ </FlexItem>
+ </Flex>
+ )}
+ </Flex>
+ </ExpandableSection>
+ )
+ }
+
+ function getDescriptionSection(): ReactElement {
+ return (
+ <ExpandableSection toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'}
+ onToggle={(_event, isExpanded) => setIsDescriptionExpanded(!isDescriptionExpanded)}
+ isExpanded={isDescriptionExpanded}>
+ {descriptionLines.filter((value, index) => index > 0)
+ .map((desc, index, array) => <Content key={index} component={ContentVariants.p}>{desc}</Content>)}
+ </ExpandableSection>
+ )
+ }
+
+ const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep)
+ const description = selectedStep && CamelDisplayUtil.getDescription(selectedStep);
+ const descriptionLines: string [] = description ? description?.split("\n") : [""];
+ const headers = ComponentApi.getComponentHeadersList(selectedStep)
+ const exchangeProperties = selectedStep ? CamelMetadataApi.getExchangeProperties(selectedStep.dslName) : [];
+ const isFrom = selectedStep?.dslName === 'FromDefinition';
+ const isPoll = selectedStep?.dslName === 'PollDefinition';
+ const component = ComponentApi.findStepComponent(selectedStep);
+ const groups = (isFrom || isPoll) ? ['consumer', 'common'] : ['producer', 'common'];
+ const isKamelet = CamelUi.isKamelet(selectedStep);
+ const showSwitchers = !isFrom && selectedStep !== undefined && ['ToDefinition', 'PollDefinition', 'ToDynamicDefinition', 'WireTapDefinition']
+ .includes(selectedStep?.dslName);
+
+ function changeStepType(poll: boolean, dynamic: boolean, wireTap: boolean) {
+ if (selectedStep) {
+ if (poll) {
+ convertStep(selectedStep, 'PollDefinition');
+ setStepIsPoll(true);
+ setStepDynamic(false);
+ setStepWireTap(false);
+ } else if (dynamic) {
+ convertStep(selectedStep, 'ToDynamicDefinition');
+ setStepIsPoll(false);
+ setStepDynamic(true);
+ setStepWireTap(false);
+ } else if (wireTap) {
+ convertStep(selectedStep, 'WireTapDefinition');
+ setStepIsPoll(false);
+ setStepDynamic(false);
+ setStepWireTap(true);
+ } else {
+ convertStep(selectedStep, 'ToDefinition');
+ setStepIsPoll(false);
+ setStepDynamic(false);
+ setStepWireTap(false);
+ }
+ }
+ }
+
+ function getStepTypeSwitch() {
+ const pollSupported = !component?.component.producerOnly;
+ return (<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', width: '100%', gap: '16px'}}>
+ <Tooltip content='Send messages to a dynamic endpoint evaluated on-demand' position='top-end'>
+ <Switch
+ id="step-type-dynamic"
+ className='step-type-switch'
+ label="Dynamic"
+ isChecked={stepDynamic}
+ onChange={(event, checked) => {
+ changeStepType(stepIsPoll, checked, stepWireTap)
+ }}
+ ouiaId="step-type-switch"
+ isDisabled={stepIsPoll || stepWireTap}
+ isReversed
+ />
+ </Tooltip>
+ {pollSupported && !isKamelet &&
+ <Tooltip content='Simple Polling Consumer to obtain the additional data' position='top-end'>
+ <Switch
+ id="step-type-poll"
+ className='step-type-switch'
+ label="Poll"
+ isChecked={stepIsPoll}
+ onChange={(event, checked) => {
+ changeStepType(checked, stepDynamic, stepWireTap)
+ }}
+ ouiaId="step-type-switch"
+ isDisabled={stepDynamic || stepWireTap}
+ isReversed
+ />
+ </Tooltip>
+ }
+ <Tooltip content='Copy the original Exchange and route to a separate location' position='top-end'>
+ <Switch
+ id="step-type-wiretap"
+ className='step-type-switch'
+ label="WireTap"
+ isChecked={stepWireTap}
+ onChange={(event, checked) => {
+ changeStepType(stepIsPoll, stepDynamic, checked)
+ }}
+ ouiaId="step-type-switch"
+ isDisabled={stepIsPoll || stepDynamic}
+ isReversed
+ />
+ </Tooltip>
+ </div>
+ )
+ }
+
+ function getIdInput() {
+ return (
+ (selectedStep as any)?.id !== undefined
+ ? <Label isEditable color='blue' isCompact onEditComplete={(event, newText) => onPropertyChange("id", newText)}>
+ {(selectedStep as any)?.id || ''}
+ </Label>
+ : <Button variant="link" onClick={event => onPropertyChange("id", "rc-" + Math.floor(1000 + Math.random() * 9000).toString())}>
+ Add Id
+ </Button>
+ )
+ }
+
+ function getDslDescription() {
+ return (
+ <div style={{flex: 2, display: 'flex', justifyContent: 'flex-end'}}>
+ <Popover position={"left"} bodyContent={description}>
+ <FormGroupLabelHelp style={{padding: 0}} aria-label="More info"/>
+ </Popover>
+ </div>
+ )
+ }
+
+ return (
+ <div className="headers">
+ <div className="top">
+ <Title headingLevel="h1" size="md">{title}</Title>
+ {getIdInput()}
+ {getHeaderMenu()}
+ {getDslDescription()}
+ </div>
+ {/*<Content component={ContentVariants.p}>{descriptionLines.at(0)}</Content>*/}
+ {/*{descriptionLines.length > 1 && getDescriptionSection()}*/}
+ {showSwitchers && getStepTypeSwitch()}
+ {headers.length > 0 && getComponentHeadersSection()}
+ {exchangeProperties.length > 0 && getExchangePropertiesSection()}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertyStore.ts b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertyStore.ts
new file mode 100644
index 00000000..51149e1e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/PropertyStore.ts
@@ -0,0 +1,50 @@
+/*
+ * 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 {createWithEqualityFn} from "zustand/traditional";
+import {shallow} from "zustand/shallow";
+
+export const NO_INFRA_BUTTON_PROPERTIES = ["uri", "id", "description", "group", "note"]
+
+interface PropertiesState {
+ propertyFilter: string;
+ setPropertyFilter: (propertyFilter: string) => void
+ requiredOnly: boolean;
+ setRequiredOnly: (requiredOnly: boolean) => void
+ changedOnly: boolean;
+ setChangedOnly: (changedOnly: boolean) => void
+ sensitiveOnly: boolean;
+ setSensitiveOnly: (sensitiveOnly: boolean) => void
+}
+
+export const usePropertiesStore = createWithEqualityFn<PropertiesState>((set, get) => ({
+ requiredOnly: true,
+ changedOnly: true,
+ sensitiveOnly: false,
+ propertyFilter: '',
+ setPropertyFilter: (propertyFilter: string) => {
+ set({propertyFilter: propertyFilter});
+ },
+ setRequiredOnly: (requiredOnly: boolean) => {
+ set({requiredOnly: requiredOnly});
+ },
+ setChangedOnly: (changedOnly: boolean) => {
+ set({changedOnly: changedOnly});
+ },
+ setSensitiveOnly: (sensitiveOnly: boolean) => {
+ set({sensitiveOnly: sensitiveOnly});
+ },
+}), shallow)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionBottomPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionBottomPanel.tsx
new file mode 100644
index 00000000..c59ecf22
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionBottomPanel.tsx
@@ -0,0 +1,80 @@
+/*
+ * 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 {ClipboardCopy, Content, } from '@patternfly/react-core';
+import './ExpressionEditor.css'
+import {Table, Tbody, Td, Tr} from "@patternfly/react-table";
+import {Context, ExpressionFunctions, ExpressionVariables} from "./ExpressionContextModel";
+
+interface Props {
+ dslLanguage?: [string, string, string],
+}
+
+export function ExpressionBottomPanel(props: Props) {
+
+ const {dslLanguage} = props;
+ const language = dslLanguage?.[0];
+ const vars: Context[] = ExpressionVariables.filter(e => e.name === language)?.[0]?.information || [];
+ const funcs: Context[] = ExpressionFunctions.filter(e => e.name === language)?.at(0)?.information || []
+ const showVars = vars.length > 0;
+ const showFuncs = funcs.length > 0;
+
+ function getRows(data: Context[]) {
+ return (
+ data?.map((context, index, array) =>
+ <Tr key={index} style={{padding: '0'}}>
+ <Td style={{padding: '0px 0px 6px 0px'}} modifier='fitContent'>
+ <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied"
+ variant="inline-compact">
+ {context.key}
+ </ClipboardCopy>
+ </Td>
+ <Td style={{padding: '0px 0px 0px 16px'}}>
+ {context.value}
+ </Td>
+ </Tr>
+ )
+ )
+ }
+
+ function getRowHeader(data: string) {
+ return (
+ <Tr key='vars' style={{padding: '0'}}>
+ <Td style={{padding: '16px 6px 6px 0px'}}>
+ <Content>
+ <Content component='h3'>{data}</Content>
+ </Content>
+ </Td>
+ </Tr>
+ )
+ }
+
+ return (
+ <div className='context'>
+ <div className='context-column'>
+ <Table variant='compact' borders={false}>
+ <Tbody>
+ {showVars && getRowHeader('Variables')}
+ {showVars && getRows(vars)}
+ {showFuncs && getRowHeader('Functions')}
+ {showFuncs && getRows(funcs)}
+ </Tbody>
+ </Table>
+ </div>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionContextModel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionContextModel.tsx
new file mode 100644
index 00000000..3f0a3411
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionContextModel.tsx
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+export class ExpressionContext {
+ name: string = '';
+ information: Context[] = [];
+
+ constructor(name: string, information: Context[]) {
+ this.name = name;
+ this.information = information;
+ }
+}
+
+export class Context {
+ key: string = '';
+ value: string = '';
+
+ constructor(key: string, value: string) {
+ this.key = key;
+ this.value = value;
+ }
+}
+
+export const ExpressionVariables: ExpressionContext[] = [
+ new ExpressionContext('groovy', [
+ new Context('exchange', 'The Exchange itself.'),
+ new Context('exchangeProperties', 'The Exchange properties.'),
+ new Context('variables', 'The variables'),
+ new Context('headers', 'The headers of the In message.'),
+ new Context('camelContext', 'The Camel Context.'),
+ new Context('request', 'The In message.'),
+ new Context('body', 'The message body'),
+ new Context('response', 'The Out message (only for InOut message exchange pattern).')
+ ]
+ ),
+ new ExpressionContext('java', [
+ new Context('exchange', 'The Exchange itself.'),
+ new Context('message', 'The Camel message.'),
+ new Context('context', 'The Camel Context.'),
+ new Context('body', 'The message body')
+ ]
+ ),
+ new ExpressionContext('javascript', [
+ new Context('this', 'the Exchange is the root object.'),
+ new Context('context', 'The Camel Context.'),
+ new Context('exchange', 'The Exchange itself.'),
+ new Context('exchangeId', 'The ExchangeID.'),
+ new Context('message', 'The Camel message.'),
+ new Context('body', 'The message body'),
+ new Context('headers', 'The message headers'),
+ new Context('properties', 'The message properties')
+ ]
+ ),
+ new ExpressionContext('jq', [
+ new Context('header', 'Allow accessing the Message header ex. header(\\"MyHeader\\")'),
+ new Context('property', 'Allow accessing the Message property ex. property(\\"MyProperty\\")'),
+ new Context('constant', 'Allow accessing constant value as-is '),
+
+ ]
+ ),
+ new ExpressionContext('simple', [
+ new Context('camelId', 'the CamelContext name'),
+ new Context('camelContext.*OGNL*', 'the CamelContext invoked using a Camel OGNL expression.'),
+ new Context('exchange', 'the Exchange'),
+ new Context('exchange.*OGNL*', 'the Exchange invoked using a Camel OGNL expression.'),
+ new Context('exchangeId', 'the exchange id'),
+ new Context('id', 'the message id'),
+ new Context('messageTimestamp', 'the message timestamp (millis since epoc) that this message originates from.'),
+ new Context('body ', 'the body'),
+ new Context('body.*OGNL*', 'the body invoked using a Camel OGNL expression.'),
+ new Context('bodyAs(_type_)', 'Converts the body to the given type determined by its classname. The converted body can be null.'),
+ new Context('bodyAs(_type_).*OGNL* ', 'Converts the body to the given type determined by its classname and then invoke methods using a Camel OGNL expression. The converted body can be null.'),
+ new Context('bodyOneLine', 'Converts the body to a String and removes all line-breaks so the string is in one line.'),
+ new Context('prettyBody', 'Converts the body to a String, and attempts to pretty print if JSon or XML, otherwise the body is returned as the String value.'),
+ new Context('originalBody', 'The original incoming body (only available if allowUseOriginalMessage=true).'),
+ new Context('mandatoryBodyAs(_type_)', 'Converts the body to the given type determined by its classname, and expects the body to be not null.'),
+ new Context('mandatoryBodyAs(_type_).*OGNL* ', 'Converts the body to the given type determined by its classname and then invoke methods using a Camel OGNL expression.'),
+ new Context('header.foo ', 'refer to the foo header'),
+ new Context('header[foo] ', 'refer to the foo header'),
+ new Context('headers.foo ', 'refer to the foo header'),
+ new Context('headers:foo ', 'refer to the foo header'),
+ new Context('headers[foo] ', 'refer to the foo header'),
+ new Context('header.foo[bar] ', 'regard foo header as a map and perform lookup on the map with bar as key'),
+ new Context('header.foo.*OGNL*', 'refer to the foo header and invoke its value using a Camel OGNL expression.'),
+ new Context('headerAs(_key_,_type_)', 'converts the header to the given type determined by its classname'),
+ new Context('headers', 'refer to the headers'),
+ new Context('variable.foo ', 'refer to the foo variable'),
+ new Context('variable[foo] ', 'refer to the foo variable'),
+ new Context('variable.foo.*OGNL* ', 'refer to the foo variable and invoke its value using a Camel OGNL expression.'),
+ new Context('variableAs(_key_,_type_)', 'converts the variable to the given type determined by its classname'),
+ new Context('variables', 'refer to the variables'),
+ new Context('exchangeProperty.foo ', 'refer to the foo property on the exchange'),
+ new Context('exchangeProperty[foo] ', 'refer to the foo property on the exchange'),
+ new Context('exchangeProperty.foo.*OGNL* ', 'refer to the foo property on the exchange and invoke its value using a Camel OGNL expression.'),
+ new Context('messageAs(_type_)', 'Converts the message to the given type determined by its classname. The converted message can be null. '),
+ new Context('messageAs(_type_).*OGNL* ', 'Converts the message to the given type determined by its classname and then invoke methods using a Camel OGNL expression. The converted message can be null. '),
+ new Context('sys.foo', 'refer to the JVM system property'),
+ new Context('sysenv.foo', 'refer to the system environment variable'),
+ new Context('env.foo', 'refer to the system environment variable'),
+ new Context('exception ', 'refer to the exception object on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
+ new Context('exception.*OGNL* ', 'refer to the exchange exception invoked using a Camel OGNL expression object'),
+ new Context('exception.message', 'refer to the exception.message on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
+ new Context('exception.stacktrace', 'refer to the exception.stracktrace on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
+ new Context('date:_command_', `evaluates to a Date object. Supported commands are: *now* for current timestamp,
+*exchangeCreated* for the timestamp when the current exchange was created,
+*header.xxx* to use the Long/Date object in the header with the key xxx.
+*variable.xxx* to use the Long/Date in the variable with the key xxx.
+*exchangeProperty.xxx* to use the Long/Date object in the exchange property with the key xxx.
+*file* for the last modified timestamp of the file (available with a File consumer).
+Command accepts offsets such as: *now-24h* or *header.xxx+1h* or even *now+1h30m-100*.`),
+ new Context('date:_command:pattern_', 'Date formatting using `java.text.SimpleDateFormat` patterns.'),
+ new Context('date-with-timezone:_command:timezone:pattern_', 'Date formatting using `java.text.SimpleDateFormat` timezones and patterns.'),
+ new Context('bean:_bean expression_ ', `Invoking a bean expression using the xref:components::bean-component.adoc[Bean] language.'),
+Specifying a method name you must use dot as separator. We also support
+the ?method=methodname syntax that is used by the xref:components::bean-component.adoc[Bean]
+component. Camel will by default lookup a bean by the given name. However if you need to refer
+to a bean class (such as calling a static method) then you can prefix with type, such as 'bean:type:fqnClassName'. `),
+ new Context('properties:key:default', 'Lookup a property with the given key. If the key does not exists or has no value, then an optional default value can be specified.'),
+ new Context('propertiesExist:key', 'Checks whether a property placeholder with the given key exists or not. The result can be negated by prefixing the key with `!`.'),
+ new Context('routeId', 'Returns the route id of the current route the Exchange is being routed.'),
+ new Context('routeGroup', 'Returns the route group of the current route the Exchange is being routed. Not all routes has a group assigned, so this may be null.'),
+ new Context('stepId', 'Returns the id of the current step the Exchange is being routed.'),
+ new Context('threadId', 'Returns the id of the current thread. Can be used for logging purpose.'),
+ new Context('threadName', 'Returns the name of the current thread. Can be used for logging purpose.'),
+ new Context('hostname', 'Returns the local hostname (may be empty if not possible to resolve).'),
+ new Context('ref:xxx ', 'To lookup a bean from the Registry with the given id.'),
+ new Context('type:name.field ', 'To refer to a type or field by its FQN name. To refer to a field you can append .FIELD_NAME. For example, you can refer to the constant field from Exchange as: `org.apache.camel.Exchange.FILE_NAME`'),
+ new Context('empty(type)', `Creates a new empty object of the type given as parameter. The type-parameter-Strings are case-insensitive. +
+'string' -> empty String
+'list' -> empty ArrayList
+'map' -> empty HashMap `),
+ new Context('null', 'represents a *null*'),
+ new Context('random(value)', 'returns a random Integer between 0 (included) and _value_ (excluded)'),
+ new Context('random(min,max)', 'returns a random Integer between _min_ (included) and _max_ (excluded)'),
+ new Context('collate(group)', `The collate function iterates the message body and groups
+the data into sub lists of specified size. This can be used with the
+Splitter EIP to split a message body and group/batch
+the split sub message into a group of N sub lists. This method works
+similar to the collate method in Groovy.`),
+ new Context('skip(number)', ' The skip function iterates the message body and skips the first number of items. This can be used with the Splitter EIP to split a message body and skip the first N number of items.'),
+ new Context('join(separator,prefix,exp)', `The join function iterates the message body (by default) and joins the data into a string. The separator is by default a comma. The prefix is optional.'),
+
+The join uses the message body as source by default. It is possible to refer to another
+source (simple language) such as a header via the exp parameter. For example join('&','id=','$\{header.ids}')`),
+ new Context('messageHistory', 'The message history of the current exchange how it has been routed. This is similar to the route stack-trace message history the error handler logs in case of an unhandled exception.'),
+ new Context('messageHistory(false)', 'As messageHistory but without the exchange details (only includes the route stack-trace). This can be used if you do not want to log sensitive data from the message itself.'),
+ new Context('uuid(type)', 'Returns an UUID using the Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and `simple` as the type. If no type is given the default is used. It is also possible to use a custom `UuidGenerator` and bind the bean to the xref:manual::registry.adoc[Registry] with an id. For example `${uuid(myGenerator}` where the ID is _myGenerator_.'),
+ new Context('hash(exp,algorithm)', 'Returns a hashed value (string in hex decimal) using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.'),
+ new Context('jsonpath(exp)', 'When working with JSon data, then this allows to use the JsonPath language for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath.'),
+ new Context('jsonpath(input,exp)', 'When working with JSon data, then this allows to use the JsonPath language for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
+ new Context('jq(exp)', 'When working with JSon data, then this allows to use the JQ language for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath.'),
+ new Context('jq(input,exp)', 'When working with JSon data, then this allows to use the JQ language for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
+ new Context('xpath(exp)', 'When working with XML data, then this allows to use the XPath language for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath.'),
+ new Context('xpath(input,exp)', 'When working with XML data, then this allows to use the XPath language for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
+ new Context('pretty(exp)', 'Converts the inlined expression to a String, and attempts to pretty print if JSon or XML, otherwise the expression is returned as the String value.'),
+ ]
+ )
+]
+
+export const ExpressionFunctions: ExpressionContext[] = [
+ new ExpressionContext('java', [
+ new Context('bodyAs(type)', 'To convert the body to the given type'),
+ new Context('headerAs(name, type)', 'To convert the header with the name to the given type.'),
+ new Context('headerAs(name, defaultValue, type)', 'To convert the header with the name to the given type. If no header exists, then use the given default value.'),
+ new Context('exchangePropertyAs(name, type)', 'To convert the exchange property with the name to the given type.'),
+ new Context('exchangePropertyAs(name, defaultValue, type)', 'To convert the exchange property with the name to the given type. If no exchange property exists, then use the given default value.'),
+ new Context('optionalBodyAs(type)', 'To convert the body to the given type, returned wrapped in java.util.Optional.'),
+ new Context('optionalHeaderAs(name, type)', 'To convert the header with the name to the given type, returned wrapped in java.util.Optional.'),
+ new Context('optionalExchangePropertyAs(name, type)', 'To convert the exchange property with the name to the given type, returned wrapped in java.util.Optional.')
+ ]
+ ),
+ new ExpressionContext('xpath', [
+ new Context('in:body', 'Will return the message body.'),
+ new Context('in:header', 'Will return the message header.'),
+ new Context('function:properties', 'To use a Property Placeholder.'),
+ new Context('function:simple', 'To evaluate a Simple language.'),
+ ]
+ )
+]
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.css
new file mode 100644
index 00000000..399704ae
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.css
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+.expression-modal {
+ height: 80%;
+}
+
+.container {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: stretch;
+}
+
+.panel-top {
+ flex: 1;
+ height: 100%;
+ border: 1px solid lightgray;
+}
+
+.panel-middle {
+ /*height: 64px;*/
+}
+@keyframes smooth-appear {
+ to {
+ bottom: 20px;
+ opacity:1;
+ }
+}
+
+.panel-bottom {
+ flex: 1;
+ height: 100%;
+ overflow-y: auto;
+ opacity:0;
+ animation: smooth-appear 1s ease forwards;
+}
+
+.context {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ gap: 64px;
+}
+
+.context-column {
+ flex: 1;
+}
+
+.context-column-right {
+ margin-left: 12px;
+}
+
+.context-column .pf-v6-c-clipboard-copy.pf-m-inline {
+ display: flex;
+ width: fit-content;
+}
+
+.context-column .pf-v6-c-clipboard-copy__text{
+ white-space: nowrap;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.tsx
new file mode 100644
index 00000000..457b8eb5
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/expression/ExpressionEditor.tsx
@@ -0,0 +1,77 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import '@shared/monaco-setup';
+import Editor from "@monaco-editor/react";
+import './ExpressionEditor.css'
+import {ExpressionFunctions, ExpressionVariables} from "./ExpressionContextModel";
+import {useTheme} from "@app/theme/ThemeContext";
+
+interface Props {
+ customCode: any,
+ onChange: (value: string |undefined) => void,
+ title: string,
+ dslLanguage?: [string, string, string],
+ dark?: boolean,
+ name?: string
+}
+
+export function ExpressionEditor(props: Props) {
+
+ const {isDark} = useTheme();
+ const [customCode, setCustomCode] = useState<string | undefined>();
+ const [showVariables, setShowVariables] = useState<boolean>(false);
+ const [key, setKey] = useState<string>('');
+
+ const {dslLanguage, onChange} = props;
+
+ useEffect(() => {
+ setCustomCode(props.customCode)
+ },[]);
+
+ const language = dslLanguage?.[0];
+ const showVars = ExpressionVariables.findIndex(e => e.name === language) > - 1;
+ const showFuncs = ExpressionFunctions.findIndex(e => e.name === language) > - 1;
+ const show = showVars || showFuncs;
+
+ return (
+ <div className='container'>
+ <div className='panel-top'>
+ <Editor
+ key={key}
+ height={"100%"}
+ width="100%"
+ defaultLanguage={'java'}
+ language={'java'}
+ theme={isDark ? 'vs-dark' : 'light'}
+ options={{
+ lineNumbers: "off",
+ folding: false,
+ lineNumbersMinChars: 10,
+ showUnused: false,
+ fontSize: 12,
+ minimap: {enabled: false}
+ }}
+ value={customCode?.toString()}
+ className={'code-editor'}
+ onChange={(value, _) => setCustomCode(value)}
+ />
+ </div>
+
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.css
new file mode 100644
index 00000000..06b9bea6
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.css
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+.karavan .properties .bean-property {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+}
+
+.karavan .properties .bean-property .argument-name,
+.karavan .properties .bean-property .field-name {
+ flex: 1;
+}
+
+.karavan .properties .bean-property .field-value {
+ flex: 2;
+}
+.karavan .properties .bean-property .argument-value {
+ flex: 4;
+}
+
+.karavan .properties .bean-property .delete-button {
+ padding: 3px;
+ color: #b1b1b7;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.tsx
new file mode 100644
index 00000000..ad8f9f31
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/BeanProperties.tsx
@@ -0,0 +1,345 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {
+ Button,
+ FormGroupLabelHelp,
+ InputGroup,
+ InputGroupItem,
+ Popover,
+ TextInput,
+ TextInputGroup,
+ TextInputGroupMain,
+ TextInputGroupUtilities,
+ Tooltip,
+ ValidatedOptions,
+} from '@patternfly/react-core';
+import './BeanProperties.css';
+import {BeanFactoryDefinition,} from "@karavan-core/model/CamelDefinition";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {SensitiveKeys} from "@karavan-core/model/CamelMetadata";
+import {v4 as uuidv4} from "uuid";
+import {CogIcon, DockerIcon, PlusCircleIcon, TimesIcon} from '@patternfly/react-icons';
+import {ConfigurationSelectorModal} from "./ConfigurationSelectorModal";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
+import {useDesignerStore} from "../../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {KubernetesIcon} from "../../icons/ComponentIcons";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+
+interface Props {
+ type: 'constructors' | 'properties'
+ onChange: (bean: BeanFactoryDefinition) => void
+ onClone: (bean: BeanFactoryDefinition) => void
+ expressionEditor: React.ComponentType<any>
+}
+
+export function BeanProperties (props: Props) {
+
+ const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow);
+ const [configurationSelector, setConfigurationSelector] = useState<boolean>(false);
+ const [configurationSelectorProperty, setConfigurationSelectorProperty] = useState<string | undefined>(undefined);
+ const [configurationSelectorUuid, setConfigurationSelectorUuid] = useState<string | undefined>(undefined);
+ const [properties, setProperties] = useState<Map<string, [string, string]>>(new Map<string, [string, string]>());
+ const [constructors, setConstructors] = useState<Map<string, [number, string]>>(new Map<string, [number, string]>());
+
+ useEffect(()=> {
+ setProperties(preparePropertiesMap((selectedStep as BeanFactoryDefinition)?.properties))
+ setConstructors(prepareConstructorsMap((selectedStep as BeanFactoryDefinition)?.constructors))
+ }, [selectedStep?.uuid])
+
+ function preparePropertiesMap (properties: any): Map<string, [string, string]> {
+ const result = new Map<string, [string, string]>();
+ if (properties) {
+ Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k, properties[k]]));
+ }
+ return result;
+ }
+
+ function prepareConstructorsMap (constructors: any): Map<string, [number, string]> {
+ const result = new Map<string, [number, string]>();
+ if (constructors) {
+ Object.keys(constructors).forEach((k, i, a) => result.set(uuidv4(), [parseInt(k), constructors[k]]));
+ }
+ return result;
+ }
+
+ function onBeanPropertyUpdate () {
+ if (selectedStep) {
+ const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
+ const beanProperties: any = {};
+ properties.forEach((p: any) => beanProperties[p[0]] = p[1]);
+ bean.properties = beanProperties;
+ props.onChange(bean);
+ }
+ }
+
+ function onBeanConstructorsUpdate () {
+ if (selectedStep) {
+ const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
+ const beanConstructors: any = {};
+ constructors.forEach((p: any) => beanConstructors[p[0]] = p[1]);
+ bean.constructors = beanConstructors;
+ props.onChange(bean);
+ }
+ }
+
+ function beanFieldChanged (fieldId: string, value: string) {
+ if (selectedStep) {
+ const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
+ (bean as any)[fieldId] = value;
+ props.onChange(bean);
+ }
+ }
+
+ function propertyChanged (uuid: string, key: string, value: string) {
+ setProperties(prevState => {
+ prevState.set(uuid, [key, value]);
+ return prevState;
+ });
+ onBeanPropertyUpdate();
+ }
+
+ function constructorChanged (uuid: string, key: number, value: string) {
+ setConstructors(prevState => {
+ prevState.set(uuid, [key, value]);
+ return prevState;
+ });
+ onBeanConstructorsUpdate();
+ }
+
+ function propertyDeleted (uuid: string) {
+ setProperties(prevState => {
+ prevState.delete(uuid);
+ return prevState;
+ })
+ onBeanPropertyUpdate();
+ }
+
+ function constructorDeleted (uuid: string) {
+ setConstructors(prevState => {
+ prevState.delete(uuid);
+ return prevState;
+ })
+ onBeanConstructorsUpdate();
+ }
+
+ function selectConfiguration (value: string) {
+ const propertyId = configurationSelectorProperty;
+ const uuid = configurationSelectorUuid;
+ if (propertyId && uuid){
+ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
+ propertyChanged(uuid, propertyId, value);
+ setConfigurationSelector(false);
+ setConfigurationSelectorProperty(undefined);
+ }
+ }
+
+ function openConfigurationSelector (uuid: string, propertyName: string) {
+ setConfigurationSelector(true);
+ setConfigurationSelectorProperty(propertyName);
+ setConfigurationSelectorUuid(uuid);
+ }
+
+ function closeConfigurationSelector () {
+ setConfigurationSelector(false);
+ }
+
+ function getConfigurationSelectorModal() {
+ return (
+ configurationSelector && <ConfigurationSelectorModal
+ dark={false}
+ isOpen={configurationSelector}
+ onClose={() => closeConfigurationSelector()}
+ name={'configurationSelectorProperty'}
+ customCode={undefined}
+ defaultTabIndex={'properties'}
+ dslLanguage={undefined}
+ hideEditor={true}
+ title={'' + configurationSelectorProperty}
+ onSave={(fieldId, value1) => {
+ selectConfiguration(value1)
+ closeConfigurationSelector();
+ }}
+ expressionEditor={props.expressionEditor}
+ onSelect={selectConfiguration}/>)
+ }
+
+ function getOpenConfigButton(uuid: string, propertyName: string) {
+ return (
+ <Tooltip position="bottom-end" content="Open config selector">
+ <Button icon={<CogIcon/>} variant="control" className='open-config-buton' onClick={e => {
+ openConfigurationSelector(uuid, propertyName)
+ }}>
+
+ </Button>
+ </Tooltip>
+ )
+ }
+
+ function cloneBean () {
+ if (selectedStep) {
+ const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
+ bean.uuid = uuidv4();
+ props.onClone(bean);
+ }
+ }
+
+ function getLabelIcon (displayName: string, description: string) {
+ return (
+ <Popover
+ position={"left"}
+ headerContent={displayName}
+ bodyContent={description}
+ footerContent={
+ <div>
+ <b>Required</b>
+ </div>
+ }>
+ <FormGroupLabelHelp aria-label="More info" />
+ </Popover>
+ )
+ }
+
+ function getBeanConstructors() {
+ return (
+ <>
+ {Array.from(constructors.entries()).map((v, index, array) => {
+ const i = v[0];
+ const key = v[1][0];
+ const value = v[1][1];
+ const isSecret = false;
+ return (
+ <div key={"key-" + i} className="bean-property">
+ <TextInput placeholder="Argument Index" className="text-field argument-name" isRequired type="text" id={"key-" + i}
+ name={"key-" + i} value={key}
+ onChange={(_, beanFieldName) => {
+ constructorChanged(i, parseInt(beanFieldName) , value)
+ }}/>
+ <InputGroup className="text-field argument-value">
+ <InputGroupItem isFill>
+ <TextInput
+ placeholder="Argument Value"
+ type='text'
+ autoComplete="off"
+ className="text-field"
+ isRequired
+ id={"value-" + i}
+ name={"value-" + i}
+ value={value}
+ onChange={(_, value) => {
+ constructorChanged(i, key, value)
+ }}/>
+ </InputGroupItem>
+ </InputGroup>
+ <Button icon={<TimesIcon/>} isInline variant="link" className="delete-button" onClick={e => constructorDeleted(i)}>
+
+ </Button>
+ </div>
+ )
+ })}
+ <Button icon={<PlusCircleIcon/>} isInline variant="link" className="add-button" onClick={e => constructorChanged(uuidv4(), constructors.size, '')}>
+ Add argument</Button>
+ </>
+ )
+ }
+
+ function getBeanProperties() {
+ return (
+ <>
+ {Array.from(properties.entries()).map((v, index, array) => {
+ const i = v[0];
+ const key = v[1][0];
+ const value = v[1][1];
+ const isSecret = key !== undefined && SensitiveKeys.includes(key.toLowerCase());
+ const validated = (isSecret && !isSensitiveFieldValid(value)) ? ValidatedOptions.error : ValidatedOptions.default;
+ const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+ const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? KubernetesIcon("infra-button"): <DockerIcon/>
+ return (
+ <div key={"key-" + i} className="bean-property">
+ <TextInput placeholder="Bean Field Name" className="text-field field-name" isRequired type="text" id={"key-" + i}
+ name={"key-" + i} value={key}
+ onChange={(_, beanFieldName) => {
+ propertyChanged(i, beanFieldName, value)
+ }}/>
+ <InputGroup className='field-value'>
+ <TextInputGroup className='text-field'>
+ <TextInputGroupMain
+ placeholder="Bean Field Value"
+ type='text'
+ autoComplete="off"
+ className="text-field"
+ id={"value-" + i}
+ name={"value-" + i}
+ value={value}
+ onBlur={_ => propertyChanged(i, key, value)}
+ onChange={(_, v) => {
+ propertyChanged(i, key, v)
+ }}
+ />
+ <TextInputGroupUtilities>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" className='button-clear' onClick={_ => {
+ propertyChanged(i, key,'');
+ }} />
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ <InputGroupItem className=''>
+ {getOpenConfigButton(i, key)}
+ </InputGroupItem>
+ </InputGroup>
+ {/*<InputGroup>*/}
+ {/* {inInfrastructure &&*/}
+ {/* <Tooltip position="bottom-end" content={'Select from ' + capitalize(InfrastructureAPI.infrastructure)}>*/}
+ {/* <Button variant="control" onClick={e => openConfigurationSelector(i, key)}>*/}
+ {/* {icon}*/}
+ {/* </Button>*/}
+ {/* </Tooltip>}*/}
+ {/* <InputGroupItem isFill>*/}
+ {/* <TextInput*/}
+ {/* placeholder="Bean Field Value"*/}
+ {/* type='text'*/}
+ {/* autoComplete="off"*/}
+ {/* className="text-field"*/}
+ {/* isRequired*/}
+ {/* validated={validated}*/}
+ {/* id={"value-" + i}*/}
+ {/* name={"value-" + i}*/}
+ {/* value={value}*/}
+ {/* onChange={(_, value) => {*/}
+ {/* propertyChanged(i, key, value)*/}
+ {/* }}/>*/}
+ {/* </InputGroupItem>*/}
+ {/*</InputGroup>*/}
+ <Button icon={<TimesIcon/>} isInline variant="link" className="delete-button" onClick={e => propertyDeleted(i)}></Button>
+ </div>
+ )
+ })}
+ <Button icon={<PlusCircleIcon/>} isInline variant="link" className="add-button" onClick={e => propertyChanged(uuidv4(), '', '')}>
+ Add property</Button>
+ </>
+ )
+ }
+
+ const bean = (selectedStep as BeanFactoryDefinition);
+ return (
+ <div className='properties' key={bean ? bean.uuid : 'integration'}>
+ {props.type === 'constructors' && getBeanConstructors()}
+ {props.type === 'properties' && getBeanProperties()}
+ {getConfigurationSelectorModal()}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.css
new file mode 100644
index 00000000..c56e862a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.css
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+.switch-placeholder {
+ margin: auto;
+ padding-right: 12px;
+}
+
+.karavan .properties .route-variable .pf-v6-c-toggle-group__button:before,
+.karavan .properties .route-variable .pf-v6-c-toggle-group__button {
+ border-start-end-radius: 0;
+ border-end-end-radius: 0;
+}
+
+.karavan .properties .infra-button {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.125em;
+}
+
+.karavan .properties .component-property-form-group:hover .button-clear {
+ visibility: visible;
+}
+
+.karavan .properties .component-property-form-group .button-clear {
+ visibility: hidden;
+}
+.karavan .properties .component-property-form-group:hover .boolean-field {
+ visibility: visible;
+}
+
+.karavan .properties .component-property-form-group .boolean-field {
+ visibility: hidden;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.tsx
new file mode 100644
index 00000000..b645364c
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ComponentPropertyField.tsx
@@ -0,0 +1,513 @@
+/*
+ * 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, {useEffect, useRef, useState} from 'react';
+import {
+ Button,
+ Content,
+ ContentVariants,
+ FormGroup,
+ FormGroupLabelHelp,
+ FormHelperText,
+ HelperText,
+ HelperTextItem,
+ InputGroup,
+ InputGroupItem,
+ Popover,
+ SelectOptionProps,
+ Switch,
+ TextArea,
+ TextInputGroup,
+ TextInputGroupMain,
+ TextInputGroupUtilities,
+ Tooltip,
+ ValidatedOptions
+} from '@patternfly/react-core';
+import './ComponentPropertyField.css';
+import {ComponentProperty} from "@karavan-core/model/ComponentModels";
+import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
+import {CamelElement} from "@karavan-core/model/IntegrationDefinition";
+import {ToDefinition} from "@karavan-core/model/CamelDefinition";
+import {ConfigurationSelectorModal} from "./ConfigurationSelectorModal";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
+import {CogIcon, PlusIcon, TimesIcon} from '@patternfly/react-icons';
+import {usePropertiesHook} from "../usePropertiesHook";
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {INTERNAL_COMPONENTS} from "@karavan-core/api/ComponentApi";
+import {PropertyUtil} from "./PropertyUtil";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
+import {CamelDefaultStepProperty} from "../../utils/CamelDefaultStepProperty";
+import {FileReferenceDropdown} from "./FileReferenceDropdown";
+import {FieldSelectWithCreate} from "@shared/ui/FieldSelectWithCreate";
+import {FieldSelectScrollable} from "@shared/ui/FieldSelectScrollable";
+import {CamelMetadataApi} from "@karavan-core/model/CamelMetadata";
+import {NO_INFRA_BUTTON_PROPERTIES} from "@features/project/designer/property/PropertyStore";
+
+const prefix = "parameters";
+const beanPrefix = "#bean:";
+const filePrefix = 'resource:';
+
+interface Props {
+ property: ComponentProperty,
+ element?: CamelElement,
+ value: any,
+ onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => void,
+ expressionEditor: React.ComponentType<any>
+ hideConfigSelector?: boolean,
+}
+
+export function ComponentPropertyField(props: Props) {
+
+ const {onParametersChange, getInternalComponentName} = usePropertiesHook();
+ const {property, element, value, onParameterChange, expressionEditor, hideConfigSelector} = props;
+
+ const [integration, files] = useIntegrationStore((state) => [state.integration, state.files], shallow)
+ const [ beans, stepDoubleClicked] = useDesignerStore((s) => [s.beans, s.stepDoubleClicked], shallow)
+
+ const [configurationSelector, setConfigurationSelector] = useState<boolean>(false);
+ const [configurationSelectorProperty, setConfigurationSelectorProperty] = useState<string | undefined>(undefined);
+ const [configurationSelectorDefaultTab, setConfigurationSelectorDefaultTab] = useState<string>('properties');
+ const [id, setId] = useState<string>(prefix + "-" + property.name);
+ const [dslLanguage, setDslLanguage] = useState<any>();
+ const [textValue, setTextValue] = useState<any>();
+ const ref = useRef<any>(null);
+ const [checkChanges, setCheckChanges] = useState<boolean>(false);
+
+ useEffect(() => setTextValue(value), [])
+
+ useEffect(() => {
+ if (stepDoubleClicked && element) {
+ const dsp = CamelDefaultStepProperty.findDslDefaultProperty(element.dslName);
+ if (dsp?.propertyName === property.name) {
+ if (!property.supportFileReference) {
+ setConfigurationSelectorDefaultTab(dsp.tab)
+ openConfigurationSelector(property.name);
+ } else {
+ onFileReferenceClick(value);
+ }
+ }
+ }
+ }, [stepDoubleClicked])
+
+ useEffect(() => {
+ if (checkChanges) {
+ const interval = setInterval(() => {
+ if (value !== textValue) {
+ parametersChanged(property.name, textValue);
+ }
+ }, 700);
+ return () => {
+ clearInterval(interval)
+ }
+ }
+ }, [checkChanges, textValue])
+
+ function parametersChanged(parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
+ setCheckChanges(false);
+ onParametersChange(parameter, value, pathParameter, newRoute);
+ onParameterChange?.(parameter, value, pathParameter, newRoute);
+ }
+
+ function getSelectBean(property: ComponentProperty, value: any) {
+ const selectOptions: SelectOptionProps[] = [];
+ if (beans) {
+ selectOptions.push(...beans.map((bean) => ({key: value, value: beanPrefix + bean.name, description: bean.type, children: beanPrefix + bean.name})));
+ }
+ return (
+ <FieldSelectScrollable
+ selectOptions={selectOptions}
+ value={value}
+ placeholder={'Select...'}
+ onChange={selectedValue => parametersChanged(property.name, selectedValue)}
+ />
+ )
+ }
+
+ function canBeInternalUri(property: ComponentProperty): boolean {
+ if (element && ['ToDefinition', 'WireTapDefinition'].includes(element.dslName) && (property.name === 'name' || property.name === 'address')) {
+ const uri: string = (element as ToDefinition).uri || '';
+ const parts = uri.split(":");
+ return parts.length > 0 && INTERNAL_COMPONENTS.includes(parts[0]);
+ } else {
+ return false;
+ }
+ }
+
+ function checkUri(startsWith: string): boolean {
+ if (element && element.dslName === 'ToDefinition' && (property.name === 'name' || property.name === 'address')) {
+ const uri: string = (element as ToDefinition).uri || '';
+ return uri.startsWith(startsWith);
+ } else {
+ return false;
+ }
+ }
+
+ function getInternalUriSelect(property: ComponentProperty, value: any) {
+ const componentName = getInternalComponentName(property.name, element);
+ const internalUris = CamelUi.getInternalRouteUris(integration, componentName, false);
+ let uris: string[] = CamelUi.getInternalUris(files, checkUri('direct'), checkUri('seda'), checkUri('vertx'));
+ uris.push(...internalUris);
+ uris = [...new Set(uris.map(e => e.includes(":") ? e.split(":")?.at(1) || "" : e))]
+ if (value && value.length > 0 && !uris.includes(value)) {
+ uris.unshift(value);
+ }
+ return (
+ <FieldSelectWithCreate
+ placeholder={'Select a URI'}
+ className={valueChangedClassName}
+ listOfValues={[...uris]}
+ onSelectElement={selectedValue => parametersChanged(property.name, selectedValue, property.kind === 'path', undefined)}
+ value={value}
+ utilities={[
+ <Tooltip key={1} position="bottom-end" content={"Create route"}>
+ <Button isDisabled={value === undefined} variant="plain" onClick={e => {
+ if (value) {
+ InfrastructureAPI.onCreateNewRoute(componentName, property.name, value);
+ // const newRoute = !internalUris.includes(value.toString())
+ // ? CamelUi.createNewInternalRoute(componentName.concat(...':', value.toString()))
+ // : undefined;
+ // parametersChanged(property.name, value, property.kind === 'path', newRoute);
+ }
+ }}>
+ {<PlusIcon/>}
+ </Button>
+ </Tooltip>
+ ]}
+ />
+ )
+ }
+
+ function onFileReferenceClick(text: string) {
+ const filename = text?.replace(filePrefix, '');
+ if (text?.startsWith(filePrefix) && text?.endsWith("." + property.inputLanguage) && !files.find(f => f.name === filename)) {
+ InfrastructureAPI.onCreateNewFile(filename, "", true)
+ } else {
+ InfrastructureAPI.onInternalConsumerClick(undefined, undefined, undefined, filename)
+ }
+ }
+
+ function getFileReferencedField(property: ComponentProperty, value: any) {
+ const isNull: boolean = value === undefined || value === null || value?.toString().trim() === '';
+ const isResource: boolean = isNull || value?.startsWith(filePrefix);
+ const isText: boolean = isNull || !value?.startsWith(filePrefix);
+
+ const options: SelectOptionProps[] = files
+ .filter(f => property.inputLanguage === '' || property.inputLanguage === undefined || f.name.endsWith(property.inputLanguage))
+ .map(f => {
+ const val = f.name;
+ return {value: val, label: val, children: val}
+ })
+ const additionalItems = (!isNull) ? [getOpenConfigButton(property, 'editor')] : []
+ return (
+ <div>
+ {isText &&
+ <TextInputGroup className={'text-field ' + valueChangedClassName}>
+ <TextArea
+ className="text-field" isRequired
+ type={"text"}
+ id={property.name}
+ name={property.name}
+ height={"100px"}
+ value={textValue?.toString()}
+ onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')}
+ placeholder={`Type ${property.inputLanguage}`}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ {getOpenConfigButton(property, 'editor')}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ }
+ {isResource &&
+ <FileReferenceDropdown
+ initialValue={value}
+ placeholder={`Select or Create expression file (.${property.inputLanguage})`}
+ valueChangedClassName={valueChangedClassName}
+ inputLanguage={property.inputLanguage}
+ options={options}
+ additionalItems={additionalItems}
+ onChange={(text: string) => {
+ if (text?.endsWith(`.${property.inputLanguage}`)) {
+ const filename = text?.replace(filePrefix, '');
+ setTextValue(`${filePrefix}${filename}`)
+ } else if (text?.trim().length === 0) {
+ setTextValue(text);
+ }
+ setCheckChanges(true);
+ }}
+ onFileReferenceClick={onFileReferenceClick}
+ />
+ }
+ </div>
+ )
+ }
+
+ function selectInfrastructure(value: string) {
+ // check if there is a selection
+ const textVal = ref.current;
+ const cursorStart = textVal.selectionStart;
+ const cursorEnd = textVal.selectionEnd;
+ if (cursorStart !== cursorEnd) {
+ const prevValue = value;
+ const selectedText = prevValue.substring(cursorStart, cursorEnd)
+ value = prevValue.replace(selectedText, value);
+ }
+ const propertyName = configurationSelectorProperty;
+ if (propertyName) {
+ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
+ setTextValue(value);
+ parametersChanged(propertyName, value);
+ setConfigurationSelector(false);
+ setConfigurationSelectorProperty(undefined);
+ }
+ }
+
+ function openConfigurationSelector(propertyName: string) {
+ setConfigurationSelector(true);
+ setConfigurationSelectorProperty(propertyName);
+ }
+
+ function closeConfigurationSelector() {
+ setConfigurationSelector(false);
+ }
+
+
+ function getInfrastructureSelectorModal() {
+ return (
+ configurationSelector && <ConfigurationSelectorModal
+ dark={false}
+ isOpen={configurationSelector}
+ onClose={() => closeConfigurationSelector()}
+ name={property.name}
+ customCode={value}
+ defaultTabIndex={configurationSelectorDefaultTab}
+ dslLanguage={dslLanguage}
+ title={property.displayName}
+ onSave={(fieldId, value1) => {
+ parametersChanged(property.name, value1)
+ setTextValue(value1);
+ closeConfigurationSelector();
+ }}
+ expressionEditor={expressionEditor}
+ onSelect={selectInfrastructure}/>)
+ }
+
+ function getOpenConfigButton(property: ComponentProperty, configurationSelectorDefaultTab: string = 'properties') {
+ if (element?.dslName === 'ToDefinition' && (element as any)?.uri === 'sql' && property.name === 'query') {
+ configurationSelectorDefaultTab = 'editor'
+ }
+ return (
+ hideConfigSelector
+ ? <></>
+ : <Tooltip position="bottom-end" content="Open config selector">
+ <Button icon={<CogIcon/>} variant="plain" className='open-config-buton' onClick={e => {
+ const dslLanguage = (property.inputLanguage && CamelMetadataApi.getLanguage(property.inputLanguage)) ?? [property.inputLanguage, property.inputLanguage, property.inputLanguage];
+ setDslLanguage(dslLanguage);
+ setConfigurationSelectorDefaultTab(configurationSelectorDefaultTab)
+ openConfigurationSelector(property.name)
+ }}>
+ </Button>
+ </Tooltip>
+ )
+ }
+
+ function getStringInput(property: ComponentProperty) {
+ const noInfraSelectorButton = NO_INFRA_BUTTON_PROPERTIES.includes(property.name);
+ return <InputGroup className={valueChangedClassName}>
+ <TextInputGroup>
+ <TextInputGroupMain
+ className="text-field"
+ ref={ref}
+ type="text"
+ autoComplete="off"
+ id={id} name={id}
+ value={(textValue !== undefined ? textValue : property.defaultValue) || ''}
+ onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" className='button-clear' onClick={_ => {
+ parametersChanged(property.name, '');
+ setTextValue('');
+ setCheckChanges(true);
+ }}/>
+ {!noInfraSelectorButton && getOpenConfigButton(property)}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ </InputGroup>
+ }
+
+ function getSpecialStringInput(property: ComponentProperty) {
+ return (
+ <InputGroup className={valueChangedClassName}>
+ <InputGroupItem isFill>
+ <TextInputGroup className='special-text-field'>
+ <TextInputGroupMain
+ ref={ref}
+ className="text-field"
+ type="text"
+ autoComplete="off"
+ id={id} name={id}
+ value={(textValue !== undefined ? textValue : property.defaultValue) || ''}
+ onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ <Content component={ContentVariants.p}>{property.type}</Content>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" className='button-clear' onClick={_ => {
+ parametersChanged(property.name, '');
+ setTextValue('');
+ setCheckChanges(true);
+ }}/>
+ {getOpenConfigButton(property)}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ </InputGroupItem>
+ </InputGroup>
+ )
+ }
+
+ function getSelect(property: ComponentProperty, value: any) {
+ const selectOptions: SelectOptionProps[] = []
+ if (property.enum && property.enum.length > 0) {
+ property.enum.forEach(v => selectOptions.push({key: v?.trim(), value: v?.trim(), children: v?.trim()}));
+ }
+ return (
+ <FieldSelectScrollable
+ selectOptions={selectOptions}
+ value={value !== undefined ? value.toString() : property.defaultValue}
+ placeholder={'Select...'}
+ onChange={selectedValue => parametersChanged(property.name, selectedValue, property.kind === 'path')}
+ />
+ )
+ }
+
+ function getSwitch(property: ComponentProperty) {
+ const isValueBoolean = (textValue?.toString() === 'true' || textValue?.toString() === 'false');
+ const isDisabled = textValue?.toString().includes("{") || textValue?.toString().includes("}")
+ const isChecked = textValue !== undefined ? Boolean(textValue) : (property.defaultValue !== undefined && ['true', true].includes(property.defaultValue))
+ return (
+ <InputGroup className={"input-group " + valueChangedClassName}>
+ <InputGroupItem>
+ <Switch
+ id={id} name={id}
+ isDisabled={isDisabled}
+ className="switch-placeholder"
+ aria-label={id}
+ isChecked={isChecked}
+ value={textValue?.toString()}
+ onChange={(_, v) => {
+ setTextValue(v);
+ parametersChanged(property.name, v);
+ setCheckChanges(true);
+ }}/>
+ </InputGroupItem>
+ <TextInputGroup>
+ <TextInputGroupMain
+ ref={ref}
+ className="text-field"
+ type="text"
+ autoComplete="off"
+ id={id} name={id}
+ value={!isValueBoolean ? textValue?.toString() : ''}
+ onBlur={_ => onParametersChange(property.name, textValue)}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ {getOpenConfigButton(property)}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ </InputGroup>
+ )
+ }
+
+
+ function getLabel(property: ComponentProperty, value: any) {
+ const labelClassName = PropertyUtil.hasComponentPropertyValueChanged(property, value) ? 'value-changed-label' : '';
+ return (
+ <div style={{display: "flex", flexDirection: 'row', alignItems: 'center', gap: '3px'}}>
+ <Content component="p" className={labelClassName}>{property.displayName}</Content>
+ </div>
+ )
+ }
+
+ function getValidationHelper() {
+ return (
+ validated !== ValidatedOptions.default
+ ? <FormHelperText>
+ <HelperText>
+ <HelperTextItem icon={<ExclamationCircleIcon/>} variant={validated}>
+ {'Must be a placeholder {{ }} or secret {{secret:name/key}}'}
+ </HelperTextItem>
+ </HelperText>
+ </FormHelperText>
+ : <></>
+ )
+ }
+
+ const validated = (property.secret && !isSensitiveFieldValid(value)) ? ValidatedOptions.error : ValidatedOptions.default;
+ const valueChangedClassName = PropertyUtil.hasComponentPropertyValueChanged(property, value) ? 'value-changed' : '';
+ const supportFileReference = property.supportFileReference;
+ return (
+ <FormGroup
+ key={id}
+ className='component-property-form-group'
+ label={getLabel(property, value)}
+ isRequired={property.required}
+ labelHelp={
+ <Popover
+ position={"left"}
+ headerContent={property.displayName}
+ bodyContent={property.description}
+ footerContent={
+ <div>
+ {property.defaultValue !== undefined && <div>{"Default: " + property.defaultValue}</div>}
+ {property.required && <div>{property.displayName + " is required"}</div>}
+ </div>
+ }>
+ <FormGroupLabelHelp aria-label="More info"/>
+ </Popover>
+ }>
+ {supportFileReference && getFileReferencedField(property, value)}
+ {canBeInternalUri(property) && getInternalUriSelect(property, value)}
+ {property.type === 'string' && property.enum === undefined && !canBeInternalUri(property) && !supportFileReference
+ && getStringInput(property)}
+ {['duration', 'integer', 'int', 'number'].includes(property.type) && property.enum === undefined && !canBeInternalUri(property)
+ && getSpecialStringInput(property)}
+ {['object'].includes(property.type)
+ && getSelectBean(property, value)}
+ {['enum'].includes(property.type)
+ && getSelect(property, value)}
+ {property.type === 'boolean' && getSwitch(property)}
+ {getInfrastructureSelectorModal()}
+ {getValidationHelper()}
+ </FormGroup>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.css
new file mode 100644
index 00000000..3ac931ce
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.css
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+.configuration-selector-modal {
+ height: 99%;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.tsx
new file mode 100644
index 00000000..a8a0d51b
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/ConfigurationSelectorModal.tsx
@@ -0,0 +1,366 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {Badge, Button, capitalize, Content, Modal, ModalBody, ModalFooter, ModalHeader, TextInput, ToggleGroup, ToggleGroupItem} from '@patternfly/react-core';
+import {InnerScrollContainer, OuterScrollContainer, Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
+import {useDesignerStore} from "../../DesignerStore";
+import {shallow} from "zustand/shallow";
+import {ExpressionEditor} from "../expression/ExpressionEditor";
+import './ConfigurationSelectorModal.css'
+import {useCodeStore} from "@features/project/designer/CodeStore";
+
+const SYNTAX_EXAMPLES = [
+ {key: 'property:', value: 'group.property', description: 'Application property'},
+ {key: 'env:', value: 'env:ENV_NAME', description: 'OS environment variable'},
+ {key: 'sys:', value: 'sys:JvmPropertyName', description: 'JVM system property'},
+ {key: 'bean:', value: 'bean:beanName.method', description: 'Bean’s method'}
+]
+
+interface Props {
+ onSelect: (value: string) => void,
+ onClose: () => void,
+ isOpen: boolean,
+ name: string,
+ defaultTabIndex: string,
+ customCode: any,
+ onSave: (fieldId: string, value: string | number | boolean | any) => void,
+ title: string,
+ dslLanguage?: [string, string, string],
+ hideEditor?: boolean
+ dark: boolean,
+ expressionEditor: React.ComponentType<any>;
+}
+
+export function ConfigurationSelectorModal(props: Props) {
+ const ExEditor = props.expressionEditor ?? ExpressionEditor;
+ const {onSelect, onClose, isOpen, name, defaultTabIndex, customCode, onSave, title, dslLanguage, hideEditor, dark} = props;
+
+ const defaultTabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['properties', 'configMap', 'secret', 'services', 'examples', 'editor'] : ['properties', 'examples', 'services', 'editor'];
+ const [propertyPlaceholders] = useDesignerStore((s) => [s.propertyPlaceholders], shallow)
+ const [tabs, setTabs] = useState<string[]>([]);
+ const [tabIndex, setTabIndex] = useState<string | number>();
+ const [filter, setFilter] = useState<string>();
+ const [code, setCode] = useCodeStore((s) => [s.code, s.setCode], shallow);
+
+ useEffect(() => {
+ const newTabs = hideEditor ? defaultTabs.filter(tab => tab !== 'editor') : defaultTabs;
+ setTabs(newTabs)
+ setTabIndex(newTabs.includes(defaultTabIndex) ? defaultTabIndex : newTabs[0])
+ setCode(customCode);
+ }, [])
+
+ useEffect(() => {
+ setCode(customCode);
+ }, [customCode])
+
+ function checkFilter(name: string): boolean {
+ if (filter !== undefined && name) {
+ return name.toLowerCase().includes(filter.toLowerCase())
+ } else {
+ return true;
+ }
+ }
+
+ function searchInput() {
+ return (
+ <TextInput type="text" id="search" name="search" autoComplete="off"
+ value={filter}
+ onChange={(_, value) => setFilter(value)}/>
+ )
+ }
+
+ function getConfigMapTable() {
+ const configMaps = InfrastructureAPI.configMaps;
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th/>
+ <Th key='name'>Name</Th>
+ <Th key='data'>Data</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {configMaps
+ .filter(name => checkFilter(name))
+ .map((name, idx: number) => {
+ const configMapName = name.split("/")[0];
+ const data = name.split("/")[1];
+ return (
+ <Tr key={name}>
+ <Td noPadding isActionCell>
+ <Badge>CM</Badge>
+ </Td>
+ <Td noPadding>
+ {configMapName}
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.("configmap:" + name)}>
+ {data}
+ </Button>
+ </Td>
+ </Tr>
+ )
+ })}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ )
+ }
+
+ function getSecretsTable() {
+ const secrets = InfrastructureAPI.secrets;
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th/>
+ <Th key='name'>Name</Th>
+ <Th key='data'>Data</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {secrets
+ .filter(name => checkFilter(name))
+ .map((name, idx: number) => {
+ const configMapName = name.split("/")[0];
+ const data = name.split("/")[1];
+ return (
+ <Tr key={name}>
+ <Td noPadding isActionCell>
+ <Badge>S</Badge>
+ </Td>
+ <Td noPadding>
+ {configMapName}
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.("secret:" + name)}>
+ {data}
+ </Button>
+ </Td>
+ </Tr>
+ )
+ })}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ )
+ }
+
+ function getServicesTable() {
+ const services = InfrastructureAPI.services;
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th/>
+ <Th key='name'>Name</Th>
+ {/*<Th key='hostPort'>Host:Port</Th>*/}
+ <Th key='host'>Host</Th>
+ <Th key='port'>Port</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {services
+ .filter(name => checkFilter(name))
+ .map((name, idx: number) => {
+ const serviceName = name.split("|")[0];
+ const hostPort = name.split("|")[1];
+ const host = hostPort.split(":")[0];
+ const port = hostPort.split(":")[1];
+ return (
+ <Tr key={name}>
+ <Td noPadding isActionCell>
+ <Badge>S</Badge>
+ </Td>
+ {/*<Td noPadding>*/}
+ {/* {serviceName}*/}
+ {/*</Td>*/}
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.(hostPort)}>
+ {serviceName}
+ </Button>
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.(host)}>
+ {host}
+ </Button>
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.(port)}>
+ {port}
+ </Button>
+ </Td>
+ </Tr>
+ )
+ })}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ )
+ }
+
+ function getPropertiesTable() {
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th/>
+ <Th key='name'>Name</Th>
+ <Th key='port'>Value</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {propertyPlaceholders
+ .filter(pp => checkFilter(pp[0]))
+ .map((pp, index) => {
+ return (
+ <Tr key={pp[0]}>
+ <Td noPadding isActionCell>
+ <Badge>P</Badge>
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.(`{{${pp[0]}}}`)}>
+ {pp[0]}
+ </Button>
+ </Td>
+ <Td noPadding>
+ {pp[1]}
+ </Td>
+ </Tr>
+ )
+ })}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ )
+ }
+
+ function getExamplesTable() {
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th/>
+ <Th key='port'>Value</Th>
+ <Th key='port'>Description</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {SYNTAX_EXAMPLES
+ .filter(se => checkFilter(se.value))
+ .map(se => {
+ return (
+ <Tr key={se.key}>
+ <Td noPadding isActionCell>
+ <Badge>Syntax</Badge>
+ </Td>
+ <Td noPadding>
+ <Button style={{padding: '6px'}} variant={"link"} onClick={
+ e => onSelect?.(`{{${se.value}}}`)}>
+ {se.value}
+ </Button>
+ </Td>
+ <Td noPadding>
+ {se.description}
+ </Td>
+ </Tr>
+ )
+ })}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ )
+ }
+
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {
+ event.preventDefault();
+ onSave(props.name, code);
+ } else if (event.key === 'Escape') {
+ event.preventDefault();
+ onClose();
+ }
+ }
+
+ return (
+ <Modal
+ aria-label="Set property"
+ width={"99%"}
+ height={"99%"}
+ className='configuration-selector-modal'
+ isOpen={isOpen}
+ onClose={onClose}
+ position='top'
+ elementToFocus="#modal-special-focus"
+ onKeyDown={handleKeyDown}
+ >
+ <ModalHeader>
+ <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 8}}>
+ <div style={{flexGrow: 2, width: '100%'}}>
+ <Content component={'h3'}>{'Set from'}</Content>
+ </div>
+ <div style={{width: '300px'}}>
+ {tabIndex !== 'editor' && searchInput()}
+ </div>
+ <ToggleGroup>
+ {tabs.map(tab =>
+ <ToggleGroupItem buttonId={tab} key={tab} text={capitalize(tab)} isSelected={tab === tabIndex} onClick={() => setTabIndex(tab)}/>
+ )}
+ </ToggleGroup>
+ </div>
+ </ModalHeader>
+ <ModalBody>
+ {tabIndex === 'configMap' && getConfigMapTable()}
+ {tabIndex === 'secret' && getSecretsTable()}
+ {tabIndex === 'services' && getServicesTable()}
+ {tabIndex === 'properties' && getPropertiesTable()}
+ {tabIndex === 'examples' && getExamplesTable()}
+ {tabIndex === 'editor' && !hideEditor &&
+ <ExEditor dark={dark} customCode={customCode} name={name} onChange={setCode} title={title} dslLanguage={dslLanguage}/>}
+ </ModalBody>
+ <ModalFooter>
+ <Button key="save" variant="primary"
+ onClick={e => onSave(props.name, code)}>Save</Button>
+ <Button key="cancel" variant="secondary"
+ onClick={e => onClose()}>Close</Button>
+ </ModalFooter>
+ </Modal>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DataFormatField.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DataFormatField.tsx
new file mode 100644
index 00000000..f1cb0865
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DataFormatField.tsx
@@ -0,0 +1,161 @@
+/*
+ * 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, {useState} from 'react';
+import {ExpandableSection, SelectOptionProps} from '@patternfly/react-core';
+import {CamelMetadataApi, DataFormats, PropertyMeta} from "@karavan-core/model/CamelMetadata";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {DataFormatDefinition} from "@karavan-core/model/CamelDefinition";
+import {CamelElement, Integration} from "@karavan-core/model/IntegrationDefinition";
+import {CamelDefinitionApi} from "@karavan-core/api/CamelDefinitionApi";
+import {DslPropertyField} from "./DslPropertyField";
+import {usePropertiesStore} from "../PropertyStore";
+import {shallow} from "zustand/shallow";
+import {PropertyUtil} from "./PropertyUtil";
+import {FieldSelectScrollable} from "@shared/ui/FieldSelectScrollable";
+
+interface Props {
+ dslName: string,
+ value: CamelElement,
+ onDataFormatChange?: (value: DataFormatDefinition) => void
+ integration: Integration,
+ expressionEditor: React.ComponentType<any>
+}
+
+export function DataFormatField(props: Props) {
+
+ const [propertyFilter, changedOnly, requiredOnly] = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, s.requiredOnly], shallow)
+ const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
+
+ function getDataFormatString() {
+ return CamelDefinitionApiExt.getDataFormat(props.value)?.name || 'json';
+ }
+
+ function dataFormatChanged(dataFormat: string, value?: CamelElement) {
+ if (dataFormat !== (value as any).dataFormatName) {
+ const className = CamelMetadataApi.getCamelDataFormatMetadataByName(dataFormat)?.className;
+ value = CamelDefinitionApi.createDataFormat(className || '', {}); // perhaps copy other similar fields later
+ }
+ const df: any = CamelDefinitionApi.createStep(props.dslName, {});
+ const pValue = props.value as any
+ df[dataFormat] = value;
+ df.uuid = props.value.uuid;
+ df.variableReceive = pValue.variableReceive;
+ df.variableSend = pValue.variableSend;
+ df.description = pValue.description;
+ df.disabled = pValue.disabled;
+ df.id = pValue.id;
+
+ props.onDataFormatChange?.(df);
+ }
+
+ function propertyChanged(fieldId: string, value: string | number | boolean | any) {
+ const df = getDataFormatValue();
+ if (df) {
+ (df as any)[fieldId] = value;
+ dataFormatChanged(getDataFormatString(), df);
+ }
+ }
+
+ function getDataFormatValue(): CamelElement {
+ const dataFormatString = getDataFormatString();
+ return (props.value as any)[dataFormatString]
+ ? (props.value as any)[dataFormatString]
+ : CamelDefinitionApi.createDataFormat(dataFormatString, (props.value as any)[dataFormatString]);
+ }
+
+ function getPropertyValue(property: PropertyMeta) {
+ const value = getDataFormatValue();
+ return value ? (value as any)[property.name] : undefined;
+ }
+
+ function getFilteredProperties(): PropertyMeta[] {
+ let propertyMetas = CamelDefinitionApiExt.getElementPropertiesByName(dataFormatString).sort((a, b) => a.name === 'library' ? -1 : 1);
+ const filter = propertyFilter.toLocaleLowerCase()
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.name.toLocaleLowerCase().includes(filter) || p.label.toLocaleLowerCase().includes(filter) || p.displayName.toLocaleLowerCase().includes(filter));
+ if (requiredOnly) {
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.required);
+ }
+ if (changedOnly) {
+ propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+ }
+ return propertyMetas
+ }
+
+ function getPropertySelectorChanged(): boolean {
+ return requiredOnly || changedOnly || propertyFilter?.trim().length > 0;
+ }
+
+ function getShowExpanded(): boolean {
+ return showAdvanced || getPropertySelectorChanged();
+ }
+
+ function getPropertyFields(value: any, properties: PropertyMeta[]) {
+ return (<>
+ {value && properties?.map((property: PropertyMeta) =>
+ <DslPropertyField
+ key={property.name}
+ property={property}
+ value={value ? (value as any)[property.name] : undefined}
+ onPropertyChange={propertyChanged}
+ expressionEditor={props.expressionEditor}
+ />
+ )}
+ </>)
+ }
+ const value = getDataFormatValue();
+ const dataFormatString = getDataFormatString();
+ const dataFormat = DataFormats.find((l: [string, string, string]) => l[0] === dataFormatString);
+ const properties = getFilteredProperties();
+ const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
+ const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
+ const selectOptions: SelectOptionProps[] = [];
+ DataFormats.forEach((lang: [string, string, string]) => {
+ selectOptions.push({key: lang[0], value: lang[0], description: lang[2], children: lang[1]});
+ })
+ return (
+ <div>
+ <div>
+ <label className="-pf-v6-c-form__label" htmlFor="expression">
+ <span className="-pf-v6-c-form__label-text">{"Data Format"}</span>
+ <span className="-pf-v6-c-form__label-required" aria-hidden="true"> *</span>
+ </label>
+ <FieldSelectScrollable
+ className='value-changed'
+ selectOptions={selectOptions}
+ value={dataFormat?.[0]}
+ placeholder={'Select...'}
+ onChange={(selectedValue) => {
+ if (selectedValue) dataFormatChanged(selectedValue, value)
+ }}
+ />
+ </div>
+ <div className="object">
+ <div>
+ {getPropertyFields(value, propertiesMain)}
+ {propertiesAdvanced.length > 0 &&
+ <ExpandableSection
+ toggleText={'Advanced data format properties'}
+ onToggle={(_event, isExpanded) => setShowAdvanced(!showAdvanced)}
+ isExpanded={getShowExpanded()}>
+ {getPropertyFields(value, propertiesAdvanced)}
+ </ExpandableSection>}
+ </div>
+
+ </div>
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.css b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.css
new file mode 100644
index 00000000..a5c246ad
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.css
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+.switch-placeholder {
+ margin: auto;
+ padding-right: 12px;
+}
+
+.karavan .properties .route-variable .pf-v6-c-toggle-group__button:before,
+.karavan .properties .route-variable .pf-v6-c-toggle-group__button {
+ border-start-end-radius: 0;
+ border-end-end-radius: 0;
+}
+
+.karavan .properties .infra-button {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.125em;
+}
+
+.karavan .properties .object-field .dsl-property-form-group .boolean-text-field:hover .button-clear,
+.karavan .properties .object-field .dsl-property-form-group .text-field:hover .button-clear,
+.karavan .properties .dsl-property-form-group .kamelet-property-form-group .text-field:hover .button-clear,
+.karavan .properties .dsl-property-form-group:hover .boolean-text-field .button-clear,
+.karavan .properties .dsl-property-form-group:hover .text-field .button-clear {
+ visibility: visible;
+}
+
+.karavan .properties .object-field .dsl-property-form-group .boolean-text-field .button-clear,
+.karavan .properties .object-field .dsl-property-form-group .text-field .button-clear,
+.karavan .properties .dsl-property-form-group .kamelet-property-form-group .text-field .button-clear,
+.karavan .properties .dsl-property-form-group .boolean-text-field .button-clear,
+.karavan .properties .dsl-property-form-group .text-field .button-clear {
+ visibility: hidden;
+}
+.karavan .properties .dsl-property-form-group:hover .boolean-field{
+ visibility: visible;
+}
+
+.karavan .properties .dsl-property-form-group .boolean-field{
+ visibility: hidden;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.tsx
new file mode 100644
index 00000000..a12a9cbb
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/property/property/DslPropertyField.tsx
@@ -0,0 +1,1057 @@
+/*
+ * 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, {useEffect, useRef, useState} from 'react';
+import {
+ Button,
+ Content,
+ ContentVariants,
+ ExpandableSection,
+ FormGroup,
+ FormGroupLabelHelp,
+ FormHelperText,
+ HelperText,
+ HelperTextItem,
+ InputGroup,
+ InputGroupItem,
+ Label,
+ LabelGroup,
+ Popover,
+ SelectOptionProps,
+ Switch,
+ TextArea,
+ TextInput,
+ TextInputGroup,
+ TextInputGroupMain,
+ TextInputGroupUtilities,
+ Tooltip,
+ ValidatedOptions
+} from '@patternfly/react-core';
+import './DslPropertyField.css';
+import {CogIcon, ExclamationCircleIcon, PlusCircleIcon, PlusIcon, TimesCircleIcon, TimesIcon} from '@patternfly/react-icons';
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {CamelMetadataApi, PropertyMeta} from "@karavan-core/model/CamelMetadata";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {ExpressionField} from "./ExpressionField";
+import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
+import {ComponentPropertyField} from "./ComponentPropertyField";
+import {CamelElement} from "@karavan-core/model/IntegrationDefinition";
+import {KameletPropertyField} from "./KameletPropertyField";
+import {ObjectField} from "./ObjectField";
+import {CamelDefinitionApi} from "@karavan-core/api/CamelDefinitionApi";
+import {ComponentProperty} from "@karavan-core/model/ComponentModels";
+import {ConfigurationSelectorModal} from "./ConfigurationSelectorModal";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
+import {shallow} from "zustand/shallow";
+import {BeanFactoryDefinition, DataFormatDefinition, ExpressionDefinition} from "@karavan-core/model/CamelDefinition";
+import {TemplateApi} from "@karavan-core/api/TemplateApi";
+import {BeanProperties} from "./BeanProperties";
+import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
+import {VariablesDropdown} from "./VariablesDropdown";
+import {SpiBeanApi} from "@karavan-core/api/SpiBeanApi";
+import {PropertyUtil} from "./PropertyUtil";
+import {NO_INFRA_BUTTON_PROPERTIES, usePropertiesStore} from "../PropertyStore";
+import {Property} from "@karavan-core/model/KameletModels";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import {EventBus} from "../../utils/EventBus";
+import {CamelDefaultStepProperty} from "../../utils/CamelDefaultStepProperty";
+import {useDesignerStore, useIntegrationStore} from "@features/project/designer/DesignerStore";
+import {DslPropertyFieldSelect} from "@features/project/designer/property/property/DslPropertyFieldSelect";
+import {MEDIA_TYPES} from "@features/project/designer/utils/MediaTypes";
+import {DslPropertyFieldSelectScrollable} from "@features/project/designer/property/property/DslPropertyFieldSelectScrollable";
+import {FieldSelectWithCreate} from "@shared/ui/FieldSelectWithCreate";
+import {FileReferenceDropdown} from "@features/project/designer/property/property/FileReferenceDropdown";
+
+const beanPrefix = "#bean:";
+const classPrefix = "#class:";
+const filePrefix = 'resource:';
+
+interface Props {
+ property: PropertyMeta,
+ element?: CamelElement
+ value: any,
+ onPropertyChange?: (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) => void,
+ onExpressionChange?: (propertyName: string, exp: ExpressionDefinition) => void,
+ onDataFormatChange?: (value: DataFormatDefinition) => void,
+ onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => void,
+ hideLabel?: boolean,
+ dslLanguage?: [string, string, string],
+ expressionEditor: React.ComponentType<any>;
+}
+
+export function DslPropertyField(props: Props) {
+
+ const {property, element, value, onPropertyChange, onExpressionChange, onDataFormatChange, onParameterChange, hideLabel, dslLanguage, expressionEditor} = props;
+
+ const [integration, setIntegration, files, variables] = useIntegrationStore((s) => [s.integration, s.setIntegration, s.files, s.variables], shallow)
+ const [setSelectedStep, beans, selectedStep, stepDoubleClicked, setStepDoubleClicked] = useDesignerStore((s) => [s.setSelectedStep, s.beans, s.selectedStep, s.stepDoubleClicked, s.setStepDoubleClicked], shallow)
+ const [propertyFilter, changedOnly, requiredOnly, sensitiveOnly] = usePropertiesStore((s) =>
+ [s.propertyFilter, s.changedOnly, s.requiredOnly, s.sensitiveOnly], shallow)
+
+ const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
+ const [arrayValues, setArrayValues] = useState<Map<string, string>>(new Map<string, string>());
+ const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
+ const [configurationSelector, setConfigurationSelector] = useState<boolean>(false);
+ const [configurationSelectorProperty, setConfigurationSelectorProperty] = useState<string | undefined>(undefined);
+ const [configurationSelectorDefaultTab, setConfigurationSelectorDefaultTab] = useState<string>('properties');
+ const ref = useRef<any>(null);
+ const [textValue, setTextValue] = useState<any>();
+ const [checkChanges, setCheckChanges] = useState<boolean>(false);
+ const labelHelpRef = useRef(null);
+
+ useEffect(() => {
+ setTextValue(value)
+ }, [])
+
+ useEffect(() => {
+ if (stepDoubleClicked && selectedStep) {
+ const dsp = CamelDefaultStepProperty.findDslDefaultProperty(selectedStep.dslName);
+ if (dsp?.propertyName === property.name) {
+ if (dsp.isExpression && dslLanguage) {
+ setConfigurationSelectorDefaultTab(dsp.tab)
+ openConfigurationSelector(property.name);
+ }
+ }
+ setStepDoubleClicked(false)
+ }
+ }, [stepDoubleClicked])
+
+ useEffect(() => {
+ if (checkChanges) {
+ const interval = setInterval(() => {
+ if (value !== textValue) {
+ propertyChanged(property.name, textValue);
+ }
+ }, 700);
+ return () => {
+ clearInterval(interval)
+ }
+ }
+ }, [checkChanges, textValue])
+
+ function openSelect(propertyName: string, isExpanded: boolean) {
+ setSelectStatus(new Map<string, boolean>([[propertyName, isExpanded]]))
+ }
+
+ function clearSelection(propertyName: string) {
+ setSelectStatus(new Map<string, boolean>([[propertyName, false]]))
+ }
+
+ function isSelectOpen(propertyName: string): boolean {
+ return selectStatus.get(propertyName) === true;
+ }
+
+ function propertyChanged(fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) {
+ setCheckChanges(false);
+ onPropertyChange?.(fieldId, value, newRoute);
+ clearSelection(fieldId);
+ }
+
+ function arrayChanged(fieldId: string, value: string) {
+ setArrayValues(prevState => {
+ const map: Map<string, string> = new Map<string, string>(prevState);
+ map.set(fieldId, value);
+ return map;
+ })
+ }
+
+ function arrayDeleteValue(fieldId: string, element: string) {
+ const p: PropertyMeta = property;
+ let v = value;
+ if (p.isArray && p.type === 'string') {
+ propertyChanged(fieldId, (v as any).filter((x: string) => x !== element))
+ }
+ }
+
+ function arraySave(fieldId: string) {
+ const newValue = arrayValues.get(fieldId);
+ const p: PropertyMeta = property;
+ let v = value;
+ if (newValue !== undefined && newValue.length > 0 && p.isArray && p.type === 'string') {
+ if (v) (v as any).push(newValue)
+ else v = [newValue];
+ }
+ propertyChanged(fieldId, v);
+ arrayChanged(fieldId, "");
+ }
+
+ function isParameter(property: PropertyMeta): boolean {
+ return property.name === 'parameters' || property.description === 'parameters';
+ }
+
+ function getLabel(property: PropertyMeta, value: any, isKamelet: boolean) {
+ const labelClassName = PropertyUtil.hasDslPropertyValueChanged(property, value) ? 'value-changed-label' : '';
+ if (!isMultiValueField(property) && property.isObject && !property.isArray && !["ExpressionDefinition"].includes(property.type)) {
+ const tooltip = value ? "Delete " + property.name : "Add " + property.name;
+ const className = value ? "change-button delete-button" : "change-button add-button";
+ const x = value ? undefined : CamelDefinitionApi.createStep(property.type, {});
+ const meta = CamelMetadataApi.getCamelModelMetadataByClassName(property.type);
+ const title = meta?.title || property.displayName;
+ const icon = value ? (<TimesCircleIcon/>) : (<PlusCircleIcon/>);
+ return (
+ <div style={{display: "flex"}}>
+ <Content component="p" className={labelClassName}>{title}</Content>
+ <Tooltip position={"top"} content={<div>{tooltip}</div>}>
+ <button className={className} onClick={e => onPropertyChange?.(property.name, x)}
+ aria-label="Add element">
+ {icon}
+ </button>
+ </Tooltip>
+ </div>
+ )
+ }
+ if (isParameter(property)) {
+ return isKamelet ? "Kamelet properties:" : isRouteTemplate ? "Parameters:" : "Component parameters:";
+ } else if (!["ExpressionDefinition"].includes(property.type)) {
+ return (
+ <div style={{display: "flex", flexDirection: 'row', alignItems: 'center', gap: '3px'}}>
+ <Content component="p" className={labelClassName}>{CamelUtil.capitalizeName(property.displayName)}</Content>
+ </div>
+ )
+ }
+ }
+
+ function isUriReadOnly(property: PropertyMeta): boolean {
+ const dslName: string = element?.dslName || '';
+ return property.name === 'uri'
+ && !['ToDynamicDefinition', 'WireTapDefinition', 'InterceptFromDefinition', 'InterceptSendToEndpointDefinition'].includes(dslName)
+ }
+
+ function selectConfiguration(value: string) {
+ // check if there is a selection
+ const textVal = ref.current;
+ if (textVal != null) {
+ const cursorStart = textVal.selectionStart;
+ const cursorEnd = textVal.selectionEnd;
+ if (cursorStart !== cursorEnd) {
+ const prevValue = value;
+ const selectedText = prevValue.substring(cursorStart, cursorEnd)
+ value = prevValue.replace(selectedText, value);
+ }
+ const propertyName = configurationSelectorProperty;
+ if (propertyName) {
+ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
+ setTextValue(value);
+ propertyChanged(propertyName, value);
+ setConfigurationSelector(false);
+ setConfigurationSelectorProperty(undefined);
+ }
+ }
+ }
+
+ function openConfigurationSelector(propertyName: string) {
+ setConfigurationSelector(true);
+ setConfigurationSelectorProperty(propertyName);
+ }
+
+ function closeConfigurationSelector() {
+ setConfigurationSelector(false);
+ }
+
+ function getConfigurationSelectorModal() {
+ const {dslLanguage} = props;
+ return (
+ configurationSelector && <ConfigurationSelectorModal
+ dark={false}
+ isOpen={configurationSelector}
+ onClose={() => closeConfigurationSelector()}
+ name={property.name}
+ customCode={value}
+ defaultTabIndex={configurationSelectorDefaultTab}
+ dslLanguage={dslLanguage}
+ title={property.displayName}
+ onSave={(fieldId, value1) => {
+ propertyChanged(property.name, value1)
+ setTextValue(value1);
+ closeConfigurationSelector();
+ }}
+ expressionEditor={expressionEditor}
+ onSelect={selectConfiguration}/>)
+ }
+
+ function getVariableInput(property: PropertyMeta) {
+ const varName = textValue?.toString() || '';
+ return (
+ <VariablesDropdown
+ initialValue={varName}
+ valueChangedClassName={valueChangedClassName}
+ options={variables.map(v => ({value: v, children: v}))}
+ onChange={(variableType: string, variableName: string) => {
+ propertyChanged(property.name, variableType.concat(variableName));
+ setTextValue(variableType.concat(variableName));
+ }}
+ />
+ )
+ }
+
+ function isNumeric(num: any) {
+ return (typeof (num) === 'number' || typeof (num) === "string" && num.trim() !== '') && !isNaN(num as number);
+ }
+
+ function getSpecialStringInput(property: PropertyMeta) {
+ return (
+ <InputGroup className={valueChangedClassName}>
+ <InputGroupItem isFill>
+ <TextInput
+ ref={ref}
+ className="text-field" isRequired
+ type={property.secret ? "password" : "text"}
+ autoComplete="off"
+ id={property.name} name={property.name}
+ value={textValue?.toString() || ''}
+ customIcon={property.type !== 'string' ?
+ <Content component={ContentVariants.p}>{property.type}</Content> : undefined}
+ onBlur={_ => {
+ if (isNumeric((textValue))) {
+ propertyChanged(property.name, Number(textValue))
+ } else {
+ propertyChanged(property.name, textValue)
+ }
+ }}
+ onFocus={_ => setCheckChanges(true)}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ </InputGroupItem>
+ <InputGroupItem>
+ <PropertyPlaceholderDropdown
+ property={property} value={value}
+ onDslPropertyChange={(_, v, newRoute) => {
+ setTextValue(v);
+ propertyChanged(property.name, v)
+ setCheckChanges(true);
+ }}/>
+ </InputGroupItem>
+ </InputGroup>
+ )
+ }
+
+ function getStringInput(property: PropertyMeta) {
+ const noInfraSelectorButton = NO_INFRA_BUTTON_PROPERTIES.includes(property.name);
+ const isNumber = ['integer', 'number', 'duration'].includes(property.type);
+ const uriReadOnly = isUriReadOnly(property);
+ return (
+ <InputGroup className={valueChangedClassName}>
+ <TextInputGroup className='text-field'>
+ <TextInputGroupMain
+ ref={ref}
+ type={property.secret ? "password" : "text"}
+ autoComplete="off"
+ id={property.name} name={property.name}
+ value={textValue?.toString() || ''}
+ readOnly={uriReadOnly}
+ onBlur={_ => {
+ if (isNumber && isNumeric((textValue))) {
+ propertyChanged(property.name, Number(textValue))
+ } else if (!isNumber) {
+ propertyChanged(property.name, textValue)
+ }
+ }}
+ onFocus={_ => setCheckChanges(true)}
+ onChange={(_, v) => {
+ if (isNumber && isNumeric(v)) {
+ setTextValue(v);
+ setCheckChanges(true);
+ } else if (!isNumber) {
+ setTextValue(v);
+ setCheckChanges(true);
+ }
+ }}
+ />
+ <TextInputGroupUtilities>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" className='button-clear' onClick={_ => {
+ propertyChanged(property.name, '');
+ setTextValue('');
+ setCheckChanges(true);
+ }}/>
+ {!noInfraSelectorButton && getOpenConfigButton(property)}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ </InputGroup>
+ )
+ }
+
+ function showCode(name: string, javaType: string) {
+ const {property} = props;
+ InfrastructureAPI.onGetCustomCode?.(name, property.javaType).then(value => {
+ if (value === undefined) {
+ const code = TemplateApi.generateCode(property.javaType, name) || '';
+ InfrastructureAPI.onSaveCustomCode(name, code, true);
+ }
+ InfrastructureAPI.onInternalConsumerClick(undefined, undefined, undefined, name + '.java');
+ }).catch((reason: any) => console.error(reason))
+ }
+
+ function getJavaTypeGeneratedInput(property: PropertyMeta, value: any) {
+ const selectOptions: SelectOptionProps[] = [];
+ const allBeansByJavaInterface = SpiBeanApi.findByInterfaceType(property.javaType);
+ const allBeansJavaTypes: (string | undefined)[] = allBeansByJavaInterface.map(b => b.javaType).filter(b => b !== undefined) || [];
+ if (beans) {
+ selectOptions.push(...beans.filter(bean => allBeansJavaTypes.includes(bean.type.replace('#class:', ''))).map((bean) => {
+ return {value: beanPrefix + bean.name, children: bean.name, description: bean.name}
+ }));
+ selectOptions.push(...SpiBeanApi.findByInterfaceTypeSimple(property.javaType).map((bean) => {
+ return {
+ value: classPrefix + bean.javaType, children: bean.name, description: bean.description
+ }
+ })
+ );
+ }
+ files?.filter(f => f.name.endsWith('.java')).forEach((f) => {
+ const name = f.name.replace('.java', '');
+ selectOptions.push({value: name, children: name, description: 'Custom Java Class'})
+ });
+ return <DslPropertyFieldSelect
+ value={value?.toString()}
+ property={property}
+ selectOptions={selectOptions}
+ placeholder='Select bean'
+ onPropertyChange={(_, val) => propertyChanged(property.name, val)}
+ utilities={[
+ <Tooltip key={property?.name} position="bottom-end" content={"Open Java Class"}>
+ <Button icon={<PlusIcon/>} isDisabled={value === undefined || value?.length === 0} variant="plain"
+ onClick={e => showCode(value, property.javaType)}>
+ </Button>
+ </Tooltip>
+ ]}
+ />
+ }
+
+ function onFileReferenceClick(text: string) {
+ const inputLanguage = dslLanguage?.[0];
+ const filename = text?.replace(filePrefix, '');
+ if (text?.startsWith(filePrefix) && text?.endsWith("." + inputLanguage) && !files.find(f => f.name === filename)) {
+ InfrastructureAPI.onCreateNewFile(filename, "", true)
+ } else {
+ InfrastructureAPI.onInternalConsumerClick(undefined, undefined, undefined, filename)
+ }
+ }
+
+ function getExpressionFieldEditor(property: PropertyMeta, value: any) {
+ const isNull: boolean = value === undefined || value === null || value?.toString().trim() === '';
+ const isResource: boolean = isNull || value?.startsWith(filePrefix);
+ const isText: boolean = isNull || !value?.startsWith(filePrefix);
+
+ const inputLanguage = dslLanguage?.[0];
+ const options: SelectOptionProps[] = files
+ .filter(f => !inputLanguage || f.name.endsWith(inputLanguage))
+ .map(f => {
+ const val = f.name;
+ return {value: val, label: val, children: val}
+ })
+ const additionalItems = (!isNull) ? [getOpenConfigButton(property, 'editor')] : []
+ return (
+ <div>
+ {isText &&
+ <TextInputGroup className={'text-field ' + valueChangedClassName}>
+ <TextArea
+ className="text-field" isRequired
+ type={"text"}
+ id={property.name}
+ name={property.name}
+ height={"100px"}
+ value={textValue?.toString()}
+ onBlur={_ => propertyChanged(property.name, textValue)}
+ placeholder={`Type ${inputLanguage} expression`}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ {getOpenConfigButton(property, 'editor')}
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ }
+ {isResource &&
+ <FileReferenceDropdown
+ initialValue={value}
+ placeholder={`Select or Create expression file (.${inputLanguage})`}
+ valueChangedClassName={valueChangedClassName}
+ inputLanguage={inputLanguage}
+ options={options}
+ additionalItems={additionalItems}
+ onChange={(text: string) => {
+ if (text?.endsWith(`.${inputLanguage}`)) {
+ const filename = text?.replace(filePrefix, '');
+ setTextValue(`${filePrefix}${filename}`);
+ } else if (text?.trim().length === 0) {
+ setTextValue(text)
+ }
+ setCheckChanges(true);
+ }}
+ onFileReferenceClick={onFileReferenceClick}
+ />
+ }
+ </div>
+ )
+ }
+
+ function getExpressionField(property: PropertyMeta, value: any) {
+ return (
+ <div className="expression">
+ <ExpressionField
+ property={property}
+ value={value}
+ expressionEditor={expressionEditor}
+ onExpressionChange={onExpressionChange}/>
+ </div>
+ )
+ }
+
+ function getObjectField(property: PropertyMeta, value: any) {
+ return (
+ <div className="object">
+ {value && <ObjectField property={property}
+ value={value}
+ expressionEditor={expressionEditor}
+ onPropertyUpdate={propertyChanged}/>}
+ </div>
+ )
+ }
+
+ function getBooleanInput(property: PropertyMeta) {
+ const isValueBoolean = (textValue?.toString() === 'true' || textValue?.toString() === 'false');
+ const isDisabled = textValue?.toString().includes("{") || textValue?.toString().includes("}")
+ let isChecked = false;
+ if (textValue !== undefined && isValueBoolean) {
+ isChecked = Boolean(textValue);
+ } else if ((textValue === undefined || textValue.toString().length > 0) && property.defaultValue !== undefined) {
+ isChecked = property.defaultValue === 'true';
+ }
+ return (
+ <InputGroup className={"input-group " + valueChangedClassName}>
+ <InputGroupItem>
+ <Switch
+ isDisabled={isDisabled}
+ id={property.name + "-switch"}
+ name={property.name + "-switch"}
+ className="switch-placeholder"
+ value={textValue?.toString()}
+ aria-label={property.name}
+ isChecked={isChecked}
+ onChange={(_, v) => {
+ setTextValue(v);
+ propertyChanged(property.name, v);
+ setCheckChanges(false);
+ }}/>
+ </InputGroupItem>
+ <TextInputGroup className='boolean-text-field'>
+ <TextInputGroupMain
+ ref={ref}
+ id={property.name + "-placeholder"}
+ name={property.name + "-placeholder"}
+ type="text"
+ aria-label="placeholder"
+ value={!isValueBoolean ? textValue?.toString() : ''}
+ onBlur={_ => propertyChanged(property.name, textValue)}
+ onChange={(_, v) => {
+ setTextValue(v);
+ setCheckChanges(true);
+ }}
+ />
+ <TextInputGroupUtilities>
+ <Button icon={<TimesIcon aria-hidden={true}/>} isInline variant="link" className='button-clear' onClick={_ => {
+ propertyChanged(property.name, '');
+ setTextValue('');
+ setCheckChanges(true);
+ }}/>
+ </TextInputGroupUtilities>
+ {getOpenConfigButton(property)}
+ </TextInputGroup>
+ </InputGroup>
+ )
+ }
+
+ function getOpenConfigButton(property: PropertyMeta, configurationSelectorDefaultTab: string = 'properties') {
+ if (element?.dslName === 'LogDefinition' && property.name === 'message') {
+ configurationSelectorDefaultTab = 'editor'
+ }
+ return (
+ <Tooltip position="bottom-end" content="Open config selector">
+ <Button icon={<CogIcon/>} variant="plain" className='open-config-buton' onClick={e => {
+ setConfigurationSelectorDefaultTab(configurationSelectorDefaultTab)
+ openConfigurationSelector(property.name)
+ }}>
+ </Button>
+ </Tooltip>
+ )
+ }
+
+ function getSelectBean(property: PropertyMeta, value: any) {
+ const selectOptions: SelectOptionProps[] = [];
+ if (beans) {
+ selectOptions.push(...beans.map((bean) => ({key: value, value: bean.name, description: bean.type, children: bean.name})));
+ }
+ return <DslPropertyFieldSelect value={value}
+ property={property}
+ selectOptions={selectOptions}
+ onPropertyChange={(_, val) => propertyChanged(property.name, val)}
+ />
+ }
+
+ function getSelect(property: PropertyMeta, value: any) {
+ const selectOptions: SelectOptionProps[] = []
+ if (property.enumVals && property.enumVals.length > 0) {
+ selectOptions.push(...property.enumVals.split(',').map((enumVal: string) => {
+ const textValue: string = enumVal?.trim();
+ return ({key: textValue, value: textValue, children: textValue})
+ }));
+ }
+ return <DslPropertyFieldSelect value={value}
+ property={property}
+ selectOptions={selectOptions}
+ onPropertyChange={(_, val) => propertyChanged(property.name, val)}
+ />
+ }
+
+ function getMediaTypeSelectOptions(filter?: string): SelectOptionProps [] {
+ const options: SelectOptionProps [] = [];
+ const mediaTypes: SelectOptionProps[] = filter
+ ? MEDIA_TYPES.filter(mt => mt.includes(filter)).map((value: string) =>
+ ({value: value.trim(), children: value.trim(), description: value.trim()}))
+ : MEDIA_TYPES.map((value: string) =>
+ ({value: value.trim(), children: value.trim(), description: value.trim()}))
+ options.push(...mediaTypes);
+ return options;
+ }
+
+ function getMediaTypeSelect(property: PropertyMeta, value: any) {
+ return <DslPropertyFieldSelectScrollable
+ value={value}
+ property={property}
+ selectOptions={getMediaTypeSelectOptions()}
+ placeholder='Select Media Type'
+ onPropertyChange={(_, val) => propertyChanged(property.name, val)}
+ />
+ }
+
+ function canBeInternalUri(property: PropertyMeta, element?: CamelElement): boolean {
+ if (element?.dslName === 'WireTapDefinition' && property.name === 'uri') {
+ return true;
+ } else if (element?.dslName === 'SagaDefinition' && ['compensation', 'completion'].includes(property.name)) {
+ return true;
+ } else if (element && ['GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(element?.dslName) && property.name === 'to') {
+ return true;
+ } else if (property.name === 'deadLetterUri') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function canBeMediaType(property: PropertyMeta, element?: CamelElement): boolean {
+ if (element
+ && ['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(element.dslName)
+ && ['consumes', 'produces'].includes(property.name)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function javaTypeGenerated(property: PropertyMeta): boolean {
+ return property.javaType.length !== 0;
+ }
+
+ function createNewRoute(property: PropertyMeta, value: any): void {
+ try {
+ if (property.name === 'deadLetterUri' && selectedStep?.dslName === 'RouteConfigurationDefinition') {
+ const newRoute = CamelUi.createNewInternalRoute(value);
+ propertyChanged(property.name, value, newRoute)
+ } else {
+ const split: string = value?.toString().split(':');
+ const componentName = split[0];
+ const propertyName = componentName === 'vertx' ? 'address' : 'name';
+ InfrastructureAPI.onCreateNewRoute(componentName, propertyName, split[1]);
+ }
+ } catch (error: any) {
+ console.error(error);
+ EventBus.sendAlert('Error', error?.message, 'danger')
+ }
+ }
+
+ function getInternalUriSelect() {
+ const uris: string[] = CamelUi.getInternalUris(files, true, true, true);
+ return (
+ <FieldSelectWithCreate
+ placeholder={'Select a URI'}
+ listOfValues={[...uris]}
+ onSelectElement={selectedValue => propertyChanged(property.name, selectedValue)}
+ value={value}
+ className={valueChangedClassName}
+ utilities={[
+ <Tooltip key={'1'} position="bottom-end" content={"Create route"}>
+ <Button isDisabled={value === undefined} variant="plain" onClick={e => {
+ if (value) {
+ createNewRoute(property, value);
+ }
+ }}>
+ {<PlusIcon/>}
+ </Button>
+ </Tooltip>
+ ]}
+ />
+ )
+ }
+
+ function onMultiValueObjectUpdate(index: number, fieldId: string, v: CamelElement) {
+ const mValue = [...value];
+ mValue[index] = v;
+ onPropertyChange?.(fieldId, mValue);
+ }
+
+ function isKeyValueObject(property: PropertyMeta) {
+ const propertiesMetadata = CamelDefinitionApiExt.getElementProperties(property.type);
+ return propertiesMetadata.length === 2 && propertiesMetadata.filter(p => p.name === 'key').length === 1 && propertiesMetadata.filter(p => p.name === 'value').length === 1;
+ }
+
+ function getMultiObjectFieldProps(property: PropertyMeta, value: any, v: any, index: number, hideLabel: boolean = false) {
+ return (<>
+ <div className="object">
+ {v && <ObjectField property={property}
+ value={v}
+ hideLabel={hideLabel}
+ expressionEditor={expressionEditor}
+ onPropertyUpdate={(f, v) => onMultiValueObjectUpdate(index, f, v)}
+ />}
+ </div>
+ <Button icon={<TimesCircleIcon/>} variant="link" className="delete-button" onClick={e => {
+ const v = Array.from(value);
+ v.splice(index, 1);
+ propertyChanged(property.name, v);
+ }}></Button>
+ </>)
+ }
+
+ function getMultiValueObjectField(property: PropertyMeta, value: any) {
+ const isKeyValue = isKeyValueObject(property);
+ return (
+ <div style={{display: 'flex', flexDirection: 'column', gap: '6px', justifyContent: 'flex-start', alignItems: 'stretch'}}>
+ {value && Array.from(value).map((v: any, index: number) => {
+ if (isKeyValue)
+ return <div key={property + "-" + index} className="object-key-value">
+ {getMultiObjectFieldProps(property, value, v, index, index > 0)}
+ </div>
+ else
+ return (
+ <div key={property + "-" + index} className="object-value">
+ {getMultiObjectFieldProps(property, value, v, index)}
+ </div>
+ )
+ })}
+ <div>
+ <Button icon={<PlusCircleIcon/>} variant="link" className="add-button"
+ onClick={e => {
+ const valArray = value !== null ? [...value] : [];
+ valArray.push(CamelDefinitionApi.createStep(property.type, {}));
+ propertyChanged(property.name, valArray);
+ }}>
+
+ {"Add " + property.displayName}
+ </Button>
+ </div>
+ </div>
+ )
+ }
+
+ function getMultiValueField(property: PropertyMeta, value: any) {
+ return (
+ <div>
+ <TextInputGroup className={"input-group " + valueChangedClassName}>
+ <TextInputGroupMain value={arrayValues.get(property.name) || ''}
+ onChange={(e, v) => arrayChanged(property.name, v)}
+ onKeyUp={e => {
+ if (e.key === 'Enter') arraySave(property.name)
+ }}
+ >
+ <LabelGroup>
+ {value && Array.from(value).map((v: any, index: number) => (
+ <Label variant="outline" key={"chip-" + index} className="chip"
+ onClose={() => arrayDeleteValue(property.name, v)}>{v.toString()}</Label>))}
+ </LabelGroup>
+ </TextInputGroupMain>
+ <TextInputGroupUtilities>
+ <Button icon={<PlusIcon/>} variant="plain" onClick={e => arraySave(property.name)} aria-label="Add element"/>
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ </div>
+ )
+ }
+
+ function getKameletPropertyValue(property: Property) {
+ return CamelDefinitionApiExt.getParametersValue(element, property.id)
+ }
+
+ function getFilteredKameletProperties(): Property[] {
+ const requiredParameters = CamelUtil.getKameletRequiredParameters(element);
+ let properties = CamelUtil.getKameletProperties(element)
+ const filter = propertyFilter.toLocaleLowerCase()
+ properties = properties.filter(p => p.title?.toLocaleLowerCase().includes(filter) || p.id?.toLocaleLowerCase().includes(filter));
+ if (requiredOnly) {
+ properties = properties.filter(p => requiredParameters.includes(p.id));
+ }
+ if (changedOnly) {
+ properties = properties.filter(p => PropertyUtil.hasKameletPropertyValueChanged(p, getKameletPropertyValue(p)));
+ }
+ if (sensitiveOnly) {
+ properties = properties.filter(p => p.format == "password");
+ }
+ return properties;
+ }
+
... 13948 lines suppressed ...
(camel-karavan) 27/33: Front-end Projects for 4.18.0
Posted by ma...@apache.org.
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 2d790e4ec3d3f322d40652b6d097abac561b4674
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:52:44 2026 -0500
Front-end Projects for 4.18.0
---
.../src/karavan/features/projects/Complexity.css | 42 ++++++
.../karavan/features/projects/ComplexityApi.tsx | 40 ++++++
.../karavan/features/projects/ComplexityModels.ts | 72 ++++++++++
.../features/projects/CreateProjectModal.tsx | 150 +++++++++++++++++++++
.../features/projects/DeleteProjectModal.tsx | 69 ++++++++++
.../features/projects/ProjectStatusLabel.tsx | 80 +++++++++++
.../karavan/features/projects/ProjectZipApi.tsx | 39 ++++++
.../src/karavan/features/projects/ProjectsPage.tsx | 88 ++++++++++++
.../src/karavan/features/projects/ProjectsTab.tsx | 146 ++++++++++++++++++++
.../karavan/features/projects/ProjectsTableRow.tsx | 117 ++++++++++++++++
.../features/projects/ProjectsTableRowActivity.tsx | 19 +++
.../projects/ProjectsTableRowComplexity.tsx | 48 +++++++
.../features/projects/ProjectsTableRowTimeLine.css | 43 ++++++
.../features/projects/ProjectsTableRowTimeLine.tsx | 48 +++++++
.../karavan/features/projects/ProjectsToolbar.tsx | 105 +++++++++++++++
.../karavan/features/projects/SettingsToolbar.tsx | 59 ++++++++
.../features/projects/UploadProjectModal.tsx | 99 ++++++++++++++
17 files changed, 1264 insertions(+)
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/Complexity.css b/karavan-app/src/main/webui/src/karavan/features/projects/Complexity.css
new file mode 100644
index 00000000..9ff97868
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/Complexity.css
@@ -0,0 +1,42 @@
+.karavan .complexity .top-icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: middle;
+}
+.karavan .complexity svg {
+ vertical-align: middle;
+}
+
+.karavan .complexity .complexity-label {
+ .pf-v6-c-label__icon {
+ margin-right: 2px;
+ }
+}
+
+.karavan .files-table {
+ .icon {
+ height: 16px;
+ width: 16px;
+ }
+
+ .icon-docker {
+ fill: #0db7ed;
+ }
+}
+
+.validation-icon {
+ height: 16px;
+ width: 16px;
+}
+.validation-icon-danger {
+ color: var(--pf-t--global--icon--color--status--danger--default);
+ fill: var(--pf-t--global--icon--color--status--danger--default);
+}
+.validation-icon-pending {
+ fill: var(--pf-t--global--color--brand--default);
+ color: var(--pf-t--global--color--brand--default);
+}
+
+.rotated-run-forward {
+ animation: rotate-icon-forward 3s linear infinite
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityApi.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityApi.tsx
new file mode 100644
index 00000000..6172a8c5
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityApi.tsx
@@ -0,0 +1,40 @@
+import axios from "axios";
+import {ErrorEventBus} from "@bus/ErrorEventBus";
+import {ComplexityProject} from "./ComplexityModels";
+import {AuthApi} from "@api/auth/AuthApi";
+
+axios.defaults.headers.common['Accept'] = 'application/json';
+axios.defaults.headers.common['Content-Type'] = 'application/json';
+const instance = AuthApi.getInstance();
+
+export class ComplexityApi {
+
+ static async getComplexityProject(projectId: string, after: (complexity?: ComplexityProject) => void) {
+ instance.get('/ui/complexity/' + projectId)
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ } else {
+ after(undefined);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ after(undefined);
+ });
+ }
+
+ static async getComplexityProjects(after: (complexities: ComplexityProject[]) => void) {
+ instance.get('/ui/complexity')
+ .then(res => {
+ if (res.status === 200) {
+ const c: ComplexityProject[] = Array.isArray(res.data) ? res.data?.map(x => new ComplexityProject(x)) : [];
+ after(c);
+ } else {
+ after([]);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ after([]);
+ });
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityModels.ts b/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityModels.ts
new file mode 100644
index 00000000..b8e166fd
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ComplexityModels.ts
@@ -0,0 +1,72 @@
+export type ComplexityType = 'easy' | 'normal' | 'complex'
+
+export class ComplexityRoute {
+ routeId: string = ''
+ nodePrefixId: string = ''
+ fileName: string = ''
+ consumers: any = [];
+ producers: any[] = [];
+ routeTemplateRef: string;
+ isTemplated: boolean;
+}
+
+export class ComplexityFile {
+ fileName: string = '';
+ error: string = '';
+ type: string = '';
+ chars: number = 0;
+ routes: number = 0;
+ beans: number = 0;
+ rests: number = 0;
+ complexity: ComplexityType = 'easy';
+ complexityLines: ComplexityType = 'easy';
+ complexityRoutes: ComplexityType = 'easy';
+ complexityRests: ComplexityType = 'easy';
+ complexityBeans: ComplexityType = 'easy';
+ complexityProcessors: ComplexityType = 'easy';
+ complexityComponentsInt: ComplexityType = 'easy';
+ complexityComponentsExt: ComplexityType = 'easy';
+ complexityKamelets: ComplexityType = 'easy';
+ processors: any = {};
+ componentsInt: any = {};
+ componentsExt: any = {};
+ kamelets: any = {};
+ generated: boolean = false;
+
+ public constructor(init?: Partial<ComplexityFile>) {
+ Object.assign(this, init);
+ }
+}
+
+export class ComplexityProject {
+ projectId: string = '';
+ lastUpdateDate: number = 0;
+ complexityRoute: ComplexityType = 'easy';
+ complexityRest: ComplexityType = 'easy';
+ complexityJava: ComplexityType = 'easy';
+ complexityFiles: ComplexityType = 'easy';
+ files: ComplexityFile[] = []
+ routes: ComplexityRoute[] = []
+ dependencies: string[] = []
+ rests: number = 0;
+ exposesOpenApi: boolean = false;
+ type: string;
+
+ public constructor(init?: Partial<ComplexityProject>) {
+ Object.assign(this, init);
+ }
+}
+
+export function getComplexityColor(complexity: ComplexityType) {
+ return complexity === 'easy' ? 'green' : (complexity === 'complex' ? 'orange' : 'blue');
+}
+
+export function getMaxComplexity(complexities: (ComplexityType) []): ComplexityType {
+ if (complexities.filter(c => c === 'complex').length > 0) {
+ return 'complex'
+ } else if (complexities.filter(c => c === 'normal').length > 0) {
+ return 'normal'
+ } else {
+ return 'easy'
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/CreateProjectModal.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/CreateProjectModal.tsx
new file mode 100644
index 00000000..0d8c67d0
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/CreateProjectModal.tsx
@@ -0,0 +1,150 @@
+/*
+ * 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, {useEffect} from 'react';
+import {Alert, Button, Form, FormAlert, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant} from '@patternfly/react-core';
+import {useProjectsStore, useProjectStore} from "@stores/ProjectStore";
+import {Project, RESERVED_WORDS} from "@models/ProjectModels";
+import {isValidProjectId, nameToProjectId} from "@util/StringUtils";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {SubmitHandler, useForm} from "react-hook-form";
+import {useFormUtil} from "@util/useFormUtil";
+import {KaravanApi} from "@api/KaravanApi";
+import {AxiosResponse} from "axios";
+import {shallow} from "zustand/shallow";
+import {useNavigate} from "react-router-dom";
+import {ROUTES} from "@app/navigation/Routes";
+
+export function CreateProjectModal() {
+
+ const [project, operation, setOperation] = useProjectStore((s) => [s.project, s.operation, s.setOperation], shallow);
+ const [projects, setProjects] = useProjectsStore((s) => [s.projects, s.setProjects], shallow);
+ const [isReset, setReset] = React.useState(false);
+ const [isProjectIdChanged, setIsProjectIdChanged] = React.useState(false);
+ const [backendError, setBackendError] = React.useState<string>();
+ const formContext = useForm<Project>({mode: "all"});
+ const {getTextField} = useFormUtil(formContext);
+ const {
+ formState: {errors},
+ handleSubmit,
+ reset,
+ trigger,
+ setValue,
+ getValues
+ } = formContext;
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ const p = new Project();
+ if (operation === 'copy') {
+ p.projectId = project.projectId;
+ p.name = project.name;
+ p.type = project.type;
+ }
+ reset(p);
+ setBackendError(undefined);
+ setReset(true);
+ }, [reset]);
+
+ React.useEffect(() => {
+ isReset && trigger();
+ }, [trigger, isReset]);
+
+ function closeModal() {
+ setOperation("none");
+ }
+
+ const onSubmit: SubmitHandler<Project> = (data) => {
+ if (operation === 'copy') {
+ KaravanApi.copyProject(project.projectId, data, after)
+ } else {
+ KaravanApi.postProject(data, after)
+ }
+ }
+
+ function after (result: boolean, res: AxiosResponse<Project> | any) {
+ if (result) {
+ onSuccess(res.data.projectId);
+ } else {
+ setBackendError(res?.response?.data);
+ }
+ }
+
+ function onSuccess (projectId: string) {
+ const message = operation !== "copy" ? "Project successfully created." : "Project successfully copied.";
+ EventBus.sendAlert( "Success", message, "success");
+ KaravanApi.getProjects((projects: Project[]) => {
+ setProjects(projects);
+ setOperation("none");
+ navigate(`${ROUTES.PROJECTS}/${projectId}`);
+ });
+ }
+
+ function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {
+ if (event.key === 'Enter') {
+ handleSubmit(onSubmit)()
+ }
+ }
+
+ function onNameChange (value: string) {
+ if (!isProjectIdChanged) {
+ setValue('projectId', nameToProjectId(value), {shouldValidate: true})
+ }
+ }
+ function onIdChange (value: string) {
+ setIsProjectIdChanged(true)
+ }
+
+ return (
+ <Modal
+ variant={ModalVariant.small}
+ isOpen={["create", "copy"].includes(operation)}
+ onClose={closeModal}
+ onKeyDown={onKeyDown}
+ >
+
+ <ModalHeader title={operation !== 'copy' ? "Create Project" : "Copy Project from " + project?.projectId}/>
+ <ModalBody>
+ <Form isHorizontal={true} autoComplete="off">
+ {getTextField('name', 'Name', {
+ length: v => v.length > 5 || 'Project name should be longer that 5 characters',
+ }, 'text', onNameChange)}
+ {getTextField('projectId', 'Project ID', {
+ regex: v => isValidProjectId(v) || 'Only lowercase characters, numbers and dashes allowed',
+ length: v => v.length > 5 || 'Project ID should be longer that 5 characters',
+ name: v => !RESERVED_WORDS.includes(v) || "Reserved word",
+ uniques: v => !projects.map(p=> p.name).includes(v) || "Project already exists!",
+ }, 'text', onIdChange)}
+ {backendError &&
+ <FormAlert>
+ <Alert variant="danger" title={backendError} aria-live="polite" isInline />
+ </FormAlert>
+ }
+ </Form>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary"
+ onClick={handleSubmit(onSubmit)}
+ isDisabled={Object.getOwnPropertyNames(errors).length > 0}
+ >
+ Save
+ </Button>
+ <Button key="cancel" variant="secondary" onClick={closeModal}>Cancel</Button>
+ </ModalFooter>
+ </Modal>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/DeleteProjectModal.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/DeleteProjectModal.tsx
new file mode 100644
index 00000000..6fca6e12
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/DeleteProjectModal.tsx
@@ -0,0 +1,69 @@
+/*
+ * 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, {useState} from 'react';
+import {Content, ContentVariants, HelperText, HelperTextItem, Switch} from '@patternfly/react-core';
+import {useProjectStore} from "@stores/ProjectStore";
+import {ProjectService} from "@services/ProjectService";
+import {shallow} from "zustand/shallow";
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+
+export function DeleteProjectModal() {
+
+ const [project, operation] = useProjectStore((s) => [s.project, s.operation], shallow);
+ const [deleteContainers, setDeleteContainers] = useState(false);
+
+ function closeModal() {
+ useProjectStore.setState({operation: "none"})
+ }
+
+ function confirmAndCloseModal() {
+ ProjectService.deleteProject(project, deleteContainers);
+ useProjectStore.setState({operation: "none"});
+ }
+
+ const isOpen = operation === "delete";
+ return (
+ <ModalConfirmation
+ isOpen={isOpen}
+ message={
+ <>
+ <Content>
+ <Content component={ContentVariants.h3}>Delete project <b>{project?.projectId}</b> ?</Content>
+ <HelperText>
+ <HelperTextItem variant="warning">
+ Project will be also deleted from <b>git</b> repository
+ </HelperTextItem>
+ </HelperText>
+ <Content component={ContentVariants.p}></Content>
+ <Content component={ContentVariants.p}></Content>
+ </Content>
+ <Switch
+ label={"Delete related container and/or deployments?"}
+ isChecked={deleteContainers}
+ onChange={(_, checked) => setDeleteContainers(checked)}
+ isReversed
+ />
+ </>
+ }
+ btnConfirm='Delete'
+ btnConfirmVariant='danger'
+ onConfirm={() => confirmAndCloseModal()}
+ onCancel={() => closeModal()}
+ />
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectStatusLabel.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectStatusLabel.tsx
new file mode 100644
index 00000000..2a888102
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectStatusLabel.tsx
@@ -0,0 +1,80 @@
+/*
+ * 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, {ReactElement} from 'react';
+import {ContainerType} from '@models/ProjectModels';
+import {BuildIcon, CogIcon, CubesIcon, DevIcon, InProgressIcon, LockIcon, PackageIcon} from '@patternfly/react-icons';
+import {Label} from "@patternfly/react-core";
+import {useStatusesStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+interface Props {
+ projectId: string
+}
+
+export function ProjectStatusLabel(props: Props) {
+
+ const {projectId} = props;
+ const [deployments] = useStatusesStore((state) => [state.deployments], shallow)
+ const {containers} = useContainerStatusesStore();
+ const camelContainer = containers.filter(c => c.projectId === projectId && ['devmode', 'packaged'].includes(c.type)).at(0);
+ const isCamelRunning = camelContainer && camelContainer?.state === 'running';
+
+ const buildContainer = containers.filter(c => c.projectId === projectId && ['build'].includes(c.type)).at(0);
+ const isBuildRunning = buildContainer && buildContainer?.state === 'running';
+ const hasContainers = containers.filter(c => c.projectId === projectId).length > 0;
+ const isRunning = containers.filter(c => c.projectId === projectId && c.state === 'running').length > 0;
+
+ const colorRunBack = 'var(--pf-t--color--green--30)';
+ const colorRun = 'var(--pf-t--global--color--status--success--200)';
+ const colorControl = 'var(--pf-v6-c-button--m-control--Color)';
+ const colorBack = isRunning ? colorRunBack : colorControl;
+ const variant = hasContainers ? 'filled' : 'outline';
+ const firstIcon = (isRunning || isBuildRunning)
+ ? <CogIcon color={colorRun} className={'rotated-run-forward'}/>
+ : <InProgressIcon/>;
+
+ const typeIconColor = isRunning ? colorRun : colorControl;
+ const iconMap: Record<ContainerType, ReactElement | undefined> = {
+ devmode: <DevIcon color={typeIconColor}/>,
+ packaged: <PackageIcon color={typeIconColor}/>,
+ internal: <LockIcon color={typeIconColor}/>,
+ build: <BuildIcon color={typeIconColor}/>,
+ unknown: undefined,
+ };
+
+ const type: ContainerType = camelContainer?.type || buildContainer?.type || 'unknown';
+ const typeIcon = iconMap[type];
+
+ if (hasContainers) {
+ return (
+ <Label color={isRunning ? 'green' : 'grey'} variant={variant} style={{padding: '8px'}} >
+ <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '6px', width: '100%'}}>
+ {firstIcon}
+ {typeIcon ? typeIcon : <CubesIcon color={typeIconColor}/>}
+ </div>
+ </Label>
+ )
+ } else {
+ return (
+ <div style={{display: 'flex', justifyContent: 'space-around', alignItems: 'center', gap: '0.2rem', padding: '8px'}}>
+ {/*<InProgressIcon/>*/}
+ </div>
+ )
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectZipApi.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectZipApi.tsx
new file mode 100644
index 00000000..33a866f1
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectZipApi.tsx
@@ -0,0 +1,39 @@
+import axios from "axios";
+import {ErrorEventBus} from "@bus/ErrorEventBus";
+import {AuthApi} from "@api/auth/AuthApi";
+
+axios.defaults.headers.common['Accept'] = 'application/json';
+axios.defaults.headers.common['Content-Type'] = 'application/json';
+const instance = AuthApi.getInstance();
+
+export class ProjectZipApi {
+
+ static async downloadZip(projectId: string, after: (res: any) => void) {
+ instance.get('/ui/zip/project/' + projectId,
+ {
+ responseType: 'blob', headers: {'Accept': 'application/octet-stream'}
+ }).then(response => {
+ after(response.data);
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
+
+ static async uploadZip(fileHandle: File, after: (res: any) => void) {
+ const formData = new FormData();
+ formData.append('file', fileHandle);
+ formData.append('name', fileHandle.name);
+
+ instance.post('/ui/zip/project', formData,
+ {headers: {'Content-Type': 'multipart/form-data'}}
+ ).then(res => {
+ if (res.status === 200) {
+ after(res);
+ } else {
+ after(undefined);
+ }
+ }).catch(err => {
+ after(err);
+ });
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsPage.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsPage.tsx
new file mode 100644
index 00000000..5d1733c4
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsPage.tsx
@@ -0,0 +1,88 @@
+import React, {useEffect, useState} from 'react';
+import {capitalize, Content, Nav, NavItem, NavList,} from '@patternfly/react-core';
+import {RightPanel} from "@shared/ui/RightPanel";
+import {BUILD_IN_PROJECTS} from "@models/ProjectModels";
+import {useFileStore, useProjectsStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {DeveloperManager} from "@features/project/developer/DeveloperManager";
+import {ErrorBoundaryWrapper} from "@shared/ui/ErrorBoundaryWrapper";
+import {ProjectsTab} from "@features/projects/ProjectsTab";
+import {ProjectFunctionHook} from "@app/navigation/ProjectFunctionHook";
+import {useDataPolling} from "@shared/polling/useDataPolling";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+export const IntegrationsMenus = ['integrations'] as const;
+export type IntegrationsMenu = typeof IntegrationsMenus[number];
+
+export function ProjectsPage() {
+
+ const [fetchProjects, projects, fetchProjectsCommited] = useProjectsStore((s) => [s.fetchProjects, s.projects, s.fetchProjectsCommited], shallow)
+ const [setProject] = useProjectStore((s) => [s.setProject], shallow);
+ const {fetchContainers} = useContainerStatusesStore();
+ const [file, operation, setFile] = useFileStore((s) => [s.file, s.operation, s.setFile], shallow);
+ const showFilePanel = file !== undefined && operation === 'select';
+ const [currentMenu, setCurrentMenu] = useState<IntegrationsMenu>(IntegrationsMenus[0]);
+
+ const {refreshSharedData} = ProjectFunctionHook();
+ useDataPolling('ProjectPanel', fetchContainers, 10000);
+
+ useEffect(() => {
+ fetchProjects();
+ fetchProjectsCommited();
+ refreshSharedData();
+ }, []);
+
+ function title() {
+ return (<Content component="h2">Projects</Content>)
+ }
+
+ const onNavSelect = (_: any, selectedItem: {
+ groupId: number | string;
+ itemId: number | string;
+ to: string;
+ }
+ ) => {
+ const menu = selectedItem.itemId;
+ setCurrentMenu(menu as IntegrationsMenu);
+ const isBuildIn = BUILD_IN_PROJECTS.includes(menu?.toString());
+ if (isBuildIn) {
+ const p = projects.find(p => p.projectId === menu);
+ if (p) {
+ setProject(p, "select");
+ }
+ }
+ setFile('none', undefined);
+ };
+
+ function getNavigation() {
+ return (
+ <Nav onSelect={onNavSelect} aria-label="Nav" variant="horizontal">
+ <NavList>
+ {IntegrationsMenus.map((item, i) => {
+ return (
+ <NavItem key={item} preventDefault itemId={item} isActive={currentMenu === item} to={"#"}>
+ {capitalize(item?.toString())}
+ </NavItem>
+ )
+ })}
+ </NavList>
+ </Nav>
+ )
+ }
+
+ return (
+ <RightPanel
+ title={title()}
+ toolsStart={getNavigation()}
+ tools={undefined}
+ mainPanel={
+ <div className="right-panel-card">
+ <ErrorBoundaryWrapper onError={error => console.error(error)}>
+ {!showFilePanel && currentMenu === 'integrations' && <ProjectsTab/>}
+ {showFilePanel && <DeveloperManager/>}
+ </ErrorBoundaryWrapper>
+ </div>
+ }
+ />
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTab.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTab.tsx
new file mode 100644
index 00000000..6c568650
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTab.tsx
@@ -0,0 +1,146 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {Bullseye, EmptyState, EmptyStateVariant, ProgressStep, ProgressStepper} from '@patternfly/react-core';
+import {InnerScrollContainer, OuterScrollContainer, Table, Tbody, Td, Th, Thead, Tr} from '@patternfly/react-table';
+import {SearchIcon} from '@patternfly/react-icons';
+import {shallow} from "zustand/shallow";
+import {useProjectsStore, useProjectStore} from "@stores/ProjectStore";
+import {KaravanApi} from "@api/KaravanApi";
+import {CreateProjectModal} from "@features/projects/CreateProjectModal";
+import {DeleteProjectModal} from "@features/projects/DeleteProjectModal";
+import {useSearchStore} from "@stores/SearchStore";
+import {ComplexityProject} from "@features/projects/ComplexityModels";
+import {ComplexityApi} from "@features/projects/ComplexityApi";
+import ProjectsTableRow from "@features/projects/ProjectsTableRow";
+import {ProjectsToolbar} from "@features/projects/ProjectsToolbar";
+import {ProjectType} from "@models/ProjectModels";
+import {useDataPolling} from "@shared/polling/useDataPolling";
+
+export function ProjectsTab() {
+
+ const [projects, projectsCommited] = useProjectsStore((s) => [s.projects, s.projectsCommited], shallow)
+ const [operation] = useProjectStore((s) => [s.operation], shallow)
+ const [search, searchResults] = useSearchStore((s) => [s.search, s.searchResults], shallow)
+ const [complexities, setComplexities] = useState<ComplexityProject[]>([]);
+ const [labels, setLabels] = useState<any>();
+ const [selectedLabels, setSelectedLabels] = useState<string[]>([]);
+
+ useEffect(() => refreshActivity(), []);
+ useDataPolling('ProjectsTab', refreshActivity, 10000);
+
+ function refreshActivity() {
+ KaravanApi.getProjectsLabels(data => {
+ setLabels(data);
+ });
+ ComplexityApi.getComplexityProjects(complexities => {
+ setComplexities(complexities);
+ })
+ }
+
+ const toggleLabel = (label: string) => {
+ setSelectedLabels((prevSelectedLabels) => {
+ if (prevSelectedLabels.includes(label)) {
+ // Remove the label if it already exists in the array
+ return prevSelectedLabels.filter((item) => item !== label);
+ } else {
+ // Add the label if it doesn't exist in the array
+ return [...prevSelectedLabels, label];
+ }
+ });
+ };
+
+ function getEmptyState() {
+ return (
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ <EmptyState variant={EmptyStateVariant.sm} titleText="No results found" icon={SearchIcon} headingLevel="h2"/>
+ </Bullseye>
+ </Td>
+ </Tr>
+ )
+ }
+
+ function getProjectsTable() {
+ let projs = projects
+ .filter(p => p.type === ProjectType.integration)
+ .filter(p => searchResults.map(s => s.projectId).includes(p.projectId) || search === '');
+ if (selectedLabels.length > 0) {
+ projs = projs.filter(p => {
+ const labs: string[] = labels[p.projectId] !== undefined && Array.isArray(labels[p.projectId]) ? labels[p.projectId] : [];
+ return labs.some(l => selectedLabels.includes(l));
+ });
+ }
+ return (
+ <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
+ <ProjectsToolbar/>
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table aria-label="Projects" variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th key='status' screenReaderText='pass' modifier='fitContent'/>
+ <Th key='projectId'>Name</Th>
+ <Th key='name'>Description</Th>
+ <Th key='timeline' modifier={"fitContent"}>
+ <ProgressStepper isCenterAligned className={"projects-table-header-progress-stepper"}>
+ <ProgressStep id="commited" titleId="commited">
+ <div style={{textWrap: 'nowrap'}}>Commited</div>
+ </ProgressStep>
+ <ProgressStep id="saved" titleId="saved">
+ <div style={{textWrap: 'nowrap'}}>Saved</div>
+ </ProgressStep>
+ </ProgressStepper>
+ </Th>
+ <Th key='complexity' modifier={"fitContent"} textCenter>Complexity</Th>
+ <Th key='action' modifier={"fitContent"} aria-label='topology-modal'></Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {projs.map(project => {
+ const complexity = complexities.filter(c => c.projectId === project.projectId).at(0) || new ComplexityProject({projectId: project.projectId});
+ const projectCommited = projectsCommited.find(pc => pc.projectId === project.projectId);
+ return (
+ <ProjectsTableRow
+ key={project.projectId}
+ project={project}
+ projectCommited={projectCommited}
+ complexity={complexity}
+ labels={Array.isArray(labels?.[project.projectId]) ? labels?.[project.projectId] : []}
+ selectedLabels={selectedLabels}
+ onLabelClick={toggleLabel}
+ />
+ )
+ })}
+ {projs.length === 0 && getEmptyState()}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ </div>
+ )
+ }
+
+ return (
+ <div className="right-panel-card">
+ {getProjectsTable()}
+ {["create", "copy"].includes(operation) && <CreateProjectModal/>}
+ {["delete"].includes(operation) && <DeleteProjectModal/>}
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRow.tsx
new file mode 100644
index 00000000..e8d55b86
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRow.tsx
@@ -0,0 +1,117 @@
+import React from 'react';
+import {Badge, Button, Flex, FlexItem, Tooltip} from '@patternfly/react-core';
+import '@features/projects/Complexity.css';
+import {Td, Tr} from "@patternfly/react-table";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import CopyIcon from "@patternfly/react-icons/dist/esm/icons/copy-icon";
+import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
+import {shallow} from "zustand/shallow";
+import {useNavigate} from "react-router-dom";
+import {BUILD_IN_PROJECTS, Project, ProjectCommited} from "@models/ProjectModels";
+import {useProjectStore} from "@stores/ProjectStore";
+import FileSaver from "file-saver";
+import TimeAgo from 'javascript-time-ago'
+import en from 'javascript-time-ago/locale/en'
+import {ROUTES} from "@app/navigation/Routes";
+import {ProjectStatusLabel} from "@features/projects/ProjectStatusLabel";
+import {ComplexityProject} from "@features/projects/ComplexityModels";
+import {ProjectZipApi} from "@features/projects/ProjectZipApi";
+import {ProjectsTableRowComplexity} from "@features/projects/ProjectsTableRowComplexity";
+import {ProjectsTableRowTimeLine} from "@features/projects/ProjectsTableRowTimeLine";
+
+TimeAgo.addDefaultLocale(en)
+
+interface Props {
+ project: Project
+ projectCommited?: ProjectCommited
+ complexity: ComplexityProject
+ labels: string[]
+ selectedLabels: string[]
+ onLabelClick: (label: string) => void
+}
+
+function ProjectsTableRow(props: Props) {
+
+ const {project, complexity, labels, selectedLabels, onLabelClick, projectCommited} = props;
+ const [setProject] = useProjectStore((state) => [state.setProject], shallow);
+ const navigate = useNavigate();
+
+ const isBuildIn = BUILD_IN_PROJECTS.includes(project.projectId);
+
+ function downloadProject(projectId: string) {
+ ProjectZipApi.downloadZip(projectId, data => {
+ FileSaver.saveAs(data, projectId + ".zip");
+ });
+ }
+
+ return (
+ <Tr key={project.projectId} className={"projects-table-row"}>
+ <Td modifier='fitContent' style={{paddingInlineEnd: 0, paddingInlineStart: '6px'}}>
+ {!isBuildIn && <ProjectStatusLabel projectId={project.projectId}/>}
+ </Td>
+ <Td>
+ <Button style={{padding: '6px', paddingInlineStart: 0}} variant={"link"} onClick={e => {
+ navigate(`${ROUTES.PROJECTS}/${project.projectId}`);
+ }}>
+ {project.projectId}
+ </Button>
+ </Td>
+ <Td>
+ <div style={{display: 'flex', flexDirection: 'column', alignItems: 'start', justifyContent: 'start', gap: '3px'}}>
+ <div>
+ {project.name}
+ </div>
+ {labels.length > 0 &&
+ <div style={{display: 'flex', flexDirection: 'row', gap: '3px'}}>
+ {labels.map((label) => (
+ <Badge key={label} isRead={!selectedLabels.includes(label)} style={{fontWeight: 'normal', cursor: 'pointer'}}
+ onClick={event => onLabelClick(label)}>
+ {label}
+ </Badge>
+ ))}
+ </div>
+ }
+ </div>
+ </Td>
+ <Td modifier={"nowrap"} textCenter>
+ <ProjectsTableRowTimeLine project={project} projectCommited={projectCommited} />
+ </Td>
+ <Td noPadding textCenter>
+ {!isBuildIn && <ProjectsTableRowComplexity complexity={complexity}/>}
+ </Td>
+ <Td className="project-action-buttons" modifier={"fitContent"}>
+ <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}} spaceItems={{default: 'spaceItemsNone'}} flexWrap={{default: 'nowrap'}}>
+ {!isBuildIn &&
+ <FlexItem>
+ <Tooltip content={"Delete"} position={"bottom"}>
+ <Button className="dev-action-button" variant={"link"} isDanger icon={<DeleteIcon/>} onClick={e => {
+ setProject(project, "delete");
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ }
+ {!isBuildIn &&
+ <FlexItem>
+ <Tooltip content={"Copy"} position={"bottom"}>
+ <Button className="dev-action-button" variant={"link"} icon={<CopyIcon/>}
+ onClick={e => {
+ setProject(project, "copy");
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ }
+ <FlexItem>
+ <Tooltip content={"Export"} position={"bottom-end"}>
+ <Button className="dev-action-button" variant={"link"} icon={<DownloadIcon/>}
+ onClick={e => {
+ downloadProject(project.projectId);
+ }}></Button>
+ </Tooltip>
+ </FlexItem>
+ </Flex>
+ </Td>
+ </Tr>
+ )
+}
+
+export default ProjectsTableRow
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowActivity.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowActivity.tsx
new file mode 100644
index 00000000..06230798
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowActivity.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import {Label, LabelGroup} from "@patternfly/react-core";
+
+interface Props {
+ activeUsers: string[]
+}
+
+export function ProjectsTableRowActivity (props: Props) {
+
+ const {activeUsers} = props;
+
+ return (
+ <LabelGroup className='active-users' numLabels={3}>
+ {activeUsers.length > 0 && activeUsers.slice(0, 5).map(user =>
+ <Label key={user} color='blue' >{user}</Label>
+ )}
+ </LabelGroup>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowComplexity.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowComplexity.tsx
new file mode 100644
index 00000000..a15c70e7
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowComplexity.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import {Label, Tooltip} from '@patternfly/react-core';
+import './Complexity.css';
+import {ComplexityProject, ComplexityType, getComplexityColor, getMaxComplexity} from "./ComplexityModels";
+import IconEasy from "@patternfly/react-icons/dist/esm/icons/ok-icon";
+import IconNormal from "@patternfly/react-icons/dist/esm/icons/ok-icon";
+import IconComplex from "@patternfly/react-icons/dist/esm/icons/warning-triangle-icon";
+import {BUILD_IN_PROJECTS} from "@models/ProjectModels";
+
+interface Props {
+ complexity: ComplexityProject
+}
+
+export function ProjectsTableRowComplexity (props: Props) {
+
+ const {complexity} = props;
+ const routesComplexity = complexity.complexityRoute;
+ const restComplexity = complexity.complexityRest;
+ const javaComplexity = complexity.complexityJava;
+ const fileComplexity = complexity.complexityFiles;
+
+ const complexities: ComplexityType[] = [];
+ complexities.push(routesComplexity);
+ complexities.push(restComplexity);
+ complexities.push(javaComplexity);
+ complexities.push(fileComplexity);
+ const maxComplexity = getMaxComplexity(complexities)
+ const color = getComplexityColor(maxComplexity);
+ const isBuildIn = BUILD_IN_PROJECTS.includes(complexity.projectId);
+
+ const label = isBuildIn
+ ? <Label key='build-in' variant={"outline"} color={'blue'}><IconNormal color={'var(--pf-t--global--color--brand--default)'}/></Label>
+ : (
+ <Tooltip content={maxComplexity}>
+ <>
+ {maxComplexity === 'easy' && <Label key='success' color={color}><IconEasy/></Label>}
+ {maxComplexity === 'normal' && <Label key='info' color={color}><IconNormal/></Label>}
+ {maxComplexity === 'complex' && <Label key='warning' color={color}><IconComplex/></Label>}
+ </>
+ </Tooltip>
+ )
+
+ return (
+ <div style={{display: "flex", gap: "3px", justifyContent: 'center', marginLeft: '16px', marginRight: '16px'}} className='complexity'>
+ {label}
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.css b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.css
new file mode 100644
index 00000000..dc50f119
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.css
@@ -0,0 +1,43 @@
+.projects-table-row {
+ vertical-align: middle;
+}
+
+.projects-table-header-progress-stepper {
+ .pf-v6-c-progress-stepper__step-main {
+ margin: 0;
+ }
+ .pf-v6-c-progress-stepper__step-connector {
+ visibility: hidden;
+ height: 0;
+ }
+ .pf-v6-c-progress-stepper__step-title {
+ font-size: var(--pf-v6-c-table--cell--FontSize);
+ font-weight: var(--pf-v6-c-table--cell--FontWeight);
+ line-height: var(--pf-v6-c-table--cell--LineHeight);
+ color: var(--pf-v6-c-table--cell--Color);
+ text-overflow: var(--pf-v6-c-table--cell--TextOverflow);
+ }
+}
+
+.projects-table-progress-stepper-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ .commit-label {
+ .pf-v6-c-label__text {
+ font-size: var(--pf-t--global--font--size--xs);
+ }
+ }
+}
+
+.projects-table-progress-stepper {
+ min-width: 200px;
+ .pf-v6-c-progress-stepper__step-main {
+ margin: 0;
+ }
+ .pf-v6-c-progress-stepper__step-title {
+ font-size: var(--pf-t--global--font--size--xs);
+ font-weight: var(--pf-v6-c-progress-stepper__step-title--FontWeight);
+ color: var(--pf-v6-c-progress-stepper__step-title--Color);
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.tsx
new file mode 100644
index 00000000..d2fd4476
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsTableRowTimeLine.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import {Label, ProgressStep, ProgressStepper} from '@patternfly/react-core';
+import '@features/projects/Complexity.css';
+import {Project, ProjectCommited} from "@models/ProjectModels";
+import TimeAgo from 'javascript-time-ago'
+import en from 'javascript-time-ago/locale/en'
+import './ProjectsTableRowTimeLine.css'
+import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import {InProgress} from "@carbon/icons-react";
+
+TimeAgo.addDefaultLocale(en)
+
+interface Props {
+ project: Project
+ projectCommited?: ProjectCommited
+}
+
+export function ProjectsTableRowTimeLine(props: Props) {
+
+ const {project, projectCommited} = props;
+ const timeAgo = new TimeAgo('en-US')
+
+ const commitTimeStamp = projectCommited !== undefined ? projectCommited.lastCommitTimestamp : 0;
+ const commited = commitTimeStamp !== 0;
+ const lastUpdate = project.lastUpdate;
+ const synced = lastUpdate === commitTimeStamp;
+ const commitIcon = commited ? <CheckCircleIcon/> : undefined;
+ const commitLabel = commited ? timeAgo.format(new Date(commitTimeStamp)) : 'No commits yet';
+ const savedIcon = synced ? <CheckCircleIcon/> : <InProgress/>;
+ const savedLabel = synced ? '' : timeAgo.format(new Date(lastUpdate));
+ return (
+ <div className="projects-table-progress-stepper-wrapper">
+ <ProgressStepper isCenterAligned className={"projects-table-progress-stepper"}>
+ <ProgressStep icon={commitIcon} variant={commited ? "success" : "default"} id="commit" titleId="commit" aria-label="commit">
+ {!synced && <div style={{textWrap: 'nowrap'}}>{commitLabel}</div>}
+ </ProgressStep>
+ <ProgressStep icon={savedIcon} isCurrent={!synced} variant={synced ? "success" : "default"} id="saved" titleId="saved" aria-label="saved">
+ <div style={{textWrap: 'nowrap'}}>{savedLabel}</div>
+ </ProgressStep>
+ </ProgressStepper>
+ {synced &&
+ <Label color={"green"} isCompact className={"commit-label"}>
+ {commitLabel}
+ </Label>
+ }
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsToolbar.tsx
new file mode 100644
index 00000000..6a784332
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/ProjectsToolbar.tsx
@@ -0,0 +1,105 @@
+import React, {useEffect, useState} from 'react';
+import {Button, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, Tooltip, TooltipPosition,} from '@patternfly/react-core';
+import {SearchIcon} from '@patternfly/react-icons';
+import {useAppConfigStore, useProjectStore} from "@stores/ProjectStore";
+import {Project} from "@models/ProjectModels";
+import {shallow} from "zustand/shallow";
+import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
+import {ProjectService} from "@services/ProjectService";
+import {useSearchStore} from "@stores/SearchStore";
+import {useDebounceValue} from "usehooks-ts";
+import {SearchApi} from "@api/SearchApi";
+import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
+import PullIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
+import {UploadProjectModal} from "@features/projects/UploadProjectModal";
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+
+export function ProjectsToolbar() {
+
+ const [search, setSearch, setSearchResults] = useSearchStore((s) => [s.search, s.setSearch, s.setSearchResults], shallow)
+ const [setProject] = useProjectStore((s) => [s.setProject], shallow)
+ const [showUpload, setShowUpload] = useState<boolean>(false);
+ const [debouncedSearch] = useDebounceValue(search, 300);
+ const [pullIsOpen, setPullIsOpen] = useState(false);
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const isDev = config.environment === 'dev';
+
+ useEffect(() => {
+ if (search !== undefined && search !== '') {
+ SearchApi.searchAll(search, response => {
+ if (response) {
+ setSearchResults(response);
+ }
+ })
+ } else {
+ setSearchResults([])
+ }
+ }, [debouncedSearch]);
+
+ function searchInput() {
+ return (
+ <TextInputGroup style={{ width: "300px" }}>
+ <TextInputGroupMain
+ value={search}
+ id="search-input"
+ // placeholder='Search'
+ type="text"
+ autoComplete={"off"}
+ autoFocus={true}
+ icon={<SearchIcon />}
+ onChange={(_event, value) => {
+ setSearch(value);
+ }}
+ aria-label="text input example"
+ />
+ <TextInputGroupUtilities>
+ <Button variant="plain" onClick={_ => {
+ setSearch('');
+ }}>
+ <TimesIcon aria-hidden={true}/>
+ </Button>
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ )
+ }
+
+ return (
+ <div className="project-files-toolbar" style={{justifyContent: "flex-end"}}>
+ <Tooltip content='Pull new Integrations from git' position={TooltipPosition.left}>
+ <Button icon={<PullIcon/>}
+ variant={"link"}
+ isDanger
+ onClick={e => setPullIsOpen(true)}
+ />
+ </Tooltip>
+ <Button icon={<RefreshIcon/>}
+ variant={"link"}
+ onClick={e => ProjectService.refreshProjects()}
+ />
+ {searchInput()}
+ {isDev &&
+ <Button className="dev-action-button" variant="secondary"
+ onClick={e => setShowUpload(true)}>
+ Import project
+ </Button>
+ }
+ {isDev &&
+ <Button className="dev-action-button" variant="primary"
+ onClick={e => setProject(new Project(), 'create')}>
+ Create Project
+ </Button>
+ }
+ {showUpload && <UploadProjectModal open={showUpload} onClose={() => setShowUpload(false)}/>}
+ <ModalConfirmation isOpen={pullIsOpen}
+ message='Pull new Integrations from Git!'
+ onConfirm={() => {
+ ProjectService.pullAllProjects();
+ setPullIsOpen(false);
+ }}
+ onCancel={() => setPullIsOpen(false)}
+ btnConfirmVariant='danger'
+ btnConfirm='Confirm Pull'
+ />
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx
new file mode 100644
index 00000000..560c958d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx
@@ -0,0 +1,59 @@
+import React, {useState} from 'react';
+import {Button, Flex, FlexItem, Modal, ModalBody, ModalFooter, ModalHeader,} from '@patternfly/react-core';
+import {useAppConfigStore, useFileStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ProjectType} from "@models/ProjectModels";
+import {KaravanApi} from "@api/KaravanApi";
+import {CatalogIcon} from '@patternfly/react-icons';
+import {EditorToolbar} from "@features/project/developer/EditorToolbar";
+
+export function SettingsToolbar() {
+
+ const [project] = useProjectStore((state) => [state.project], shallow)
+ const [file, operation] = useFileStore((state) => [state.file, state.operation], shallow)
+ const {config} = useAppConfigStore();
+ const [showConfirmation, setShowConfirmation] = useState<boolean>(false);
+
+ const isConfiguration = project.projectId === ProjectType.configuration.toString();
+ const isKamelets = project.projectId === ProjectType.kamelets.toString();
+ const isKubernetes = config.infrastructure === 'kubernetes';
+ const tooltip = isKubernetes ? "Save All Configmaps" : "Save all on shared volume";
+ const confirmMessage = isKubernetes ? "Save all configurations as Configmaps" : "Save all configurations on shared volume";
+
+ function shareConfigurations () {
+ KaravanApi.shareConfigurations(res => {});
+ setShowConfirmation(false);
+ }
+
+ function getConfirmation() {
+ return (<Modal
+ className="modal-confirm"
+ variant={"small"}
+ isOpen={showConfirmation}
+ onClose={() => setShowConfirmation(false)}
+ onEscapePress={e => setShowConfirmation(false)}>
+ <ModalHeader title="Confirmation" />
+ <ModalBody>
+ <div>{confirmMessage}</div>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary" onClick={shareConfigurations}>Confirm</Button>,
+ <Button key="cancel" variant="link" onClick={_ => setShowConfirmation(false)}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ function getToolbar() {
+ if (file !== undefined && isConfiguration) {
+ return (<EditorToolbar/>)
+ } else {
+ return (
+ <Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
+ {showConfirmation && getConfirmation()}
+ </Flex>
+ )
+ }
+ }
+
+ return getToolbar();
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/UploadProjectModal.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/UploadProjectModal.tsx
new file mode 100644
index 00000000..da58a409
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/UploadProjectModal.tsx
@@ -0,0 +1,99 @@
+import React, {useState} from 'react';
+import {Button, Content, FileUpload, Form, FormGroup, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant,} from '@patternfly/react-core';
+import {Accept, DropEvent} from "react-dropzone";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ProjectService} from "@services/ProjectService";
+import {ProjectZipApi} from "./ProjectZipApi";
+import {ErrorEventBus} from "@bus/ErrorEventBus";
+
+interface Props {
+ open: boolean,
+ onClose: () => void
+}
+
+export function UploadProjectModal(props: Props) {
+
+ const [value, setValue] = React.useState<File>();
+ const [filename, setFilename] = React.useState<string>();
+ const [isLoading, setIsLoading] = useState(false);
+ const [isRejected, setIsRejected] = useState(false);
+
+ const handleFileInputChange = (_: any, file: File) => {
+ setFilename(file.name);
+ };
+
+ const onReadFinished = (event: DropEvent, fileHandle: File): void => {
+ setValue(fileHandle);
+ setIsLoading(false)
+ }
+
+ const handleClear = (_event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
+ setFilename(undefined);
+ setValue(undefined);
+ };
+
+
+ function onConfirm(){
+ if (filename !== undefined && value !== undefined) {
+ ProjectZipApi.uploadZip(value, res => {
+ if (res.status === 200) {
+ EventBus.sendAlert( "Success", "Integration uploaded", "success");
+ ProjectService.refreshProjects();
+ } else if (res.status === 304) {
+ EventBus.sendAlert( "Attention", "Integration already exists", "warning");
+ } else {
+ ErrorEventBus.sendApiError(res);
+ }
+ })
+ closeModal();
+ }
+ }
+
+ function closeModal() {
+ props.onClose?.()
+ }
+
+ const accept : Accept = {'application/x-zip': ['.zip']};
+ return (
+ <Modal
+ title="Upload project"
+ variant={ModalVariant.small}
+ isOpen={props.open}
+ onClose={closeModal}
+ >
+ <ModalHeader>
+ <Content component='h2'>Import Integration</Content>
+ </ModalHeader>
+ <ModalBody>
+ <Form>
+ <FormGroup fieldId="upload">
+ <FileUpload
+ id="file-upload"
+ value={value}
+ filename={filename}
+ type="dataURL"
+ hideDefaultPreview
+ browseButtonText="Upload"
+ isLoading={isLoading}
+ onFileInputChange={handleFileInputChange}
+ onReadStarted={(_event, fileHandle: File) => setIsLoading(true)}
+ onReadFinished={onReadFinished}
+ allowEditingUploadedText={false}
+ onClearClick={handleClear}
+ dropzoneProps={{accept: accept, onDropRejected: fileRejections => setIsRejected(true)}}
+ />
+ </FormGroup>
+ </Form>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary"
+ onClick={event => onConfirm()}
+ isDisabled={filename === undefined || value === undefined}
+ >
+ Save
+ </Button>
+ <Button key="cancel" variant="secondary" onClick={closeModal}>Cancel</Button>
+ </ModalFooter>
+ </Modal>
+ )
+}
\ No newline at end of file
(camel-karavan) 31/33: Fron-end fixes for 4.18.0
Posted by ma...@apache.org.
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 ebcb402257260fb6d6747d75c634300d0c6ef2bf
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 19:02:49 2026 -0500
Fron-end fixes for 4.18.0
---
.../src/main/webui/src/karavan/features/access/roles/RolesTable.tsx | 5 ++---
.../src/main/webui/src/karavan/features/access/users/UsersTable.tsx | 5 ++---
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
index c8200518..360c44dd 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
@@ -16,12 +16,11 @@
*/
import React, {useState} from 'react';
import {Bullseye, EmptyState, EmptyStateVariant, Spinner} from '@patternfly/react-core';
-import '../AccessPage.css';
import {InnerScrollContainer, OuterScrollContainer, Table, TableVariant, Tbody, Td, Th, Thead, Tr} from '@patternfly/react-table';
import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
import {shallow} from "zustand/shallow";
-import {useAccessStore} from "../../../stores/AccessStore";
-import {AccessRole} from "../../../models/AccessModels";
+import {useAccessStore} from "@stores/AccessStore";
+import {AccessRole} from "@models/AccessModels";
import {RolesTableRow} from "@features/access/roles/RolesTableRow";
export function RolesTable() {
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
index db763e3e..207337e1 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
@@ -16,13 +16,12 @@
*/
import React, {useState} from 'react';
import {Bullseye, EmptyState, EmptyStateVariant, Spinner} from '@patternfly/react-core';
-import '../AccessPage.css';
import {InnerScrollContainer, OuterScrollContainer, Table, TableVariant, Tbody, Td, Th, Thead, Tr} from '@patternfly/react-table';
import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
import {shallow} from "zustand/shallow";
import {UsersTableRow} from "./UsersTableRow";
-import {useAccessStore} from "../../../stores/AccessStore";
-import {AccessUser} from "../../../models/AccessModels";
+import {useAccessStore} from "@stores/AccessStore";
+import {AccessUser} from "@models/AccessModels";
export function UsersTable() {
(camel-karavan) 05/33: Front-end API for 4.18.0
Posted by ma...@apache.org.
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 629650b63bd88de801193e5e20cf4d056fedcc56
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:17:50 2026 -0500
Front-end API for 4.18.0
---
.../src/main/webui/src/karavan/api/AccessApi.tsx | 15 +++
.../src/main/webui/src/karavan/api/CustomApi.ts | 21 ---
.../main/webui/src/karavan/api/DeveloperApi.tsx | 22 ----
.../src/main/webui/src/karavan/api/KaravanApi.tsx | 141 +++++++++++++--------
.../src/main/webui/src/karavan/api/LogWatchApi.tsx | 2 +-
.../main/webui/src/karavan/api/NotificationApi.tsx | 2 -
.../src/main/webui/src/karavan/api/SearchApi.tsx | 2 +-
.../src/main/webui/src/karavan/api/SystemApi.tsx | 1 -
8 files changed, 108 insertions(+), 98 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx b/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
index b1de7bda..dbc1dd71 100644
--- a/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
@@ -97,6 +97,21 @@ export class AccessApi {
}
}
+ static async deleteRole(rolename: string, after: (result: boolean, res: AxiosResponse<any> | any) => void) {
+ try {
+ instance.delete('/ui/access/roles/' + rolename)
+ .then(res => {
+ if (res.status === 202) {
+ after(true, res);
+ }
+ }).catch(err => {
+ after(false, err);
+ });
+ } catch (error: any) {
+ after(false, error);
+ }
+ }
+
static setUserStatus(user: AccessUser, status: string, after: (result: AccessUser) => void) {
try {
instance.put(`/ui/access/users/${status}`, user)
diff --git a/karavan-app/src/main/webui/src/karavan/api/CustomApi.ts b/karavan-app/src/main/webui/src/karavan/api/CustomApi.ts
deleted file mode 100644
index 47c0d5e4..00000000
--- a/karavan-app/src/main/webui/src/karavan/api/CustomApi.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import axios from "axios";
-import {ErrorEventBus} from "@bus/ErrorEventBus";
-import {AuthApi} from "@api/auth/AuthApi";
-
-axios.defaults.headers.common['Accept'] = 'application/json';
-axios.defaults.headers.common['Content-Type'] = 'application/json';
-const instance = AuthApi.getInstance();
-
-export class CustomApi {
-
- static async getBrand(after: (config: any) => void) {
- instance.get('/brand', {headers: {'Accept': 'application/json'}})
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- ErrorEventBus.sendApiError(err);
- });
- }
-}
diff --git a/karavan-app/src/main/webui/src/karavan/api/DeveloperApi.tsx b/karavan-app/src/main/webui/src/karavan/api/DeveloperApi.tsx
deleted file mode 100644
index c85f156a..00000000
--- a/karavan-app/src/main/webui/src/karavan/api/DeveloperApi.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import axios from "axios";
-import {AuthApi} from "@api/auth/AuthApi";
-import {ErrorEventBus} from "@bus/ErrorEventBus";
-
-axios.defaults.headers.common['Accept'] = 'application/json';
-axios.defaults.headers.common['Content-Type'] = 'application/json';
-const instance = AuthApi.getInstance();
-
-export class DeveloperApi {
-
- static async transformRequest(json: string, yaml: string, after: (response: any) => void) {
- instance.post(`/platform/developer/transformRequest/`, {dataSample: json, route: yaml})
- .then(res => {
- console.log("res", res);
- after(res);
- }).catch(err => {
- console.error(err);
- ErrorEventBus.sendApiError(err.message);
- after(err);
- });
- }
-}
diff --git a/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
index 2171365d..845c33c5 100644
--- a/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
@@ -16,11 +16,25 @@
*/
import axios, {AxiosResponse} from "axios";
-import {AppConfig, CamelStatus, CamelStatusName, ContainerStatus, DeploymentStatus, PodEvent, Project, ProjectFile, ProjectType, ServiceStatus} from "../models/ProjectModels";
+import {
+ AppConfig,
+ CamelStatus,
+ CamelStatusName,
+ ContainerStatus,
+ DeploymentStatus,
+ PodEvent,
+ Project,
+ ProjectCommited,
+ ProjectFile,
+ ProjectFileCommited,
+ ProjectType,
+ ServiceStatus
+} from "@models/ProjectModels";
import {Buffer} from 'buffer';
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {ErrorEventBus} from "@bus/ErrorEventBus";
import {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
+import {ProjectFolderCommit} from "@stores/CommitsStore";
const instance = AuthApi.getInstance();
@@ -72,8 +86,8 @@ export class KaravanApi {
});
}
- static async getAllCamelStatuses(name: CamelStatusName, after: (statuses: CamelStatus[]) => void) {
- instance.get(`/ui/status/camel/${name}`)
+ static async getAllCamelStatuses(name: CamelStatusName | null, after: (statuses: CamelStatus[]) => void) {
+ instance.get(`/ui/status/camel/${name || ''}`)
.then(res => {
if (res.status === 200) {
after(res.data);
@@ -93,6 +107,16 @@ export class KaravanApi {
ErrorEventBus.sendApiError(err);
});
}
+ static async getProjectsCommited(after: (projects: ProjectCommited[]) => void) {
+ instance.get('/ui/project/commited/all')
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
static async postProject(project: Project, after: (result: boolean, res: AxiosResponse<Project> | any) => void) {
try {
@@ -104,10 +128,12 @@ export class KaravanApi {
}).catch(err => {
console.error(err);
after(false, err);
+ EventBus.sendAlert("Error", err?.message, "danger")
});
} catch (error: any) {
console.error(error);
after(false, error);
+ EventBus.sendAlert("Error", error?.message, "danger")
}
}
@@ -176,6 +202,49 @@ export class KaravanApi {
ErrorEventBus.sendApiError(err);
});
}
+ static async getCommitedFiles(projectId: string, after: (files: ProjectFileCommited[]) => void) {
+ instance.get(`/ui/file/commited/${projectId}`)
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
+
+ static async getProjectCommits(projectId: string, after: (commits: ProjectFolderCommit[]) => void) {
+ instance.get(`/ui/git/commits/${projectId}`)
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
+
+ static async loadProjectCommits(projectId: string, after: (res: any) => void) {
+ instance.post(`/ui/git/commits/${projectId}`)
+ .then(res => {
+ if (res.status === 202) {
+ after(res);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
+
+ static async getSystemCommits(after: (res: any) => void) {
+ instance.get(`/ui/git/system`)
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ });
+ }
static async getProjectFilesByName(projectId: string, filename: string, after: (files: ProjectFile) => void) {
instance.get(`/ui/file/${projectId}?filename=${filename}`)
@@ -304,48 +373,6 @@ export class KaravanApi {
});
}
- static async getConfigurationFiles(after: (files: []) => void) {
- instance.get('/ui/file/configuration')
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- ErrorEventBus.sendApiError(err);
- });
- }
-
-
- static async getTemplatesFiles(after: (files: []) => void) {
- instance.get('/ui/file/templates')
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- ErrorEventBus.sendApiError(err);
- });
- }
-
- static async getBeanTemplatesFiles(after: (files: ProjectFile []) => void) {
- instance.get('/ui/file/templates/beans')
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- ErrorEventBus.sendApiError(err);
- });
- }
-
- static async getDevModePodStatus(projectId: string, after: (res: AxiosResponse<ContainerStatus>) => void) {
- instance.get('/ui/devmode/container/' + projectId)
- .then(res => {
- after(res);
- }).catch(err => {
- after(err);
- });
- }
static async reloadDevModeCode(projectId: string, after: (res: AxiosResponse<any>) => void) {
instance.get('/ui/devmode/reload/' + projectId)
@@ -511,7 +538,7 @@ export class KaravanApi {
}
static async manageContainer(projectId: string,
- type: 'devmode' | 'devservice' | 'packaged' | 'internal' | 'build' | 'unknown',
+ type: 'devmode' | 'packaged' | 'internal' | 'build' | 'unknown',
name: string,
command: 'deploy' | 'run' | 'pause' | 'stop' | 'delete',
pullImage: 'always' | 'ifNotExists' | 'never',
@@ -524,7 +551,7 @@ export class KaravanApi {
});
}
- static async deleteContainer(projectId: string, type: 'devmode' | 'devservice' | 'packaged' | 'internal' | 'build' | 'unknown', name: string, after: (res: AxiosResponse<any>) => void) {
+ static async deleteContainer(projectId: string, type: 'devmode' | 'packaged' | 'internal' | 'build' | 'unknown', name: string, after: (res: AxiosResponse<any>) => void) {
instance.delete('/ui/container/' + projectId + '/' + type + "/" + name)
.then(res => {
after(res);
@@ -705,8 +732,22 @@ export class KaravanApi {
});
}
- static async getProjectActivity(after: (activity?: any) => void) {
- instance.get('/ui/activity')
+ static async getProjectsActivities(after: (activities?: any) => void) {
+ instance.get('/ui/activity/projects')
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ } else {
+ after(undefined);
+ }
+ }).catch(err => {
+ ErrorEventBus.sendApiError(err);
+ after(undefined);
+ });
+ }
+
+ static async getUsersActivities(after: (activities?: any) => void) {
+ instance.get('/ui/activity/users')
.then(res => {
if (res.status === 200) {
after(res.data);
diff --git a/karavan-app/src/main/webui/src/karavan/api/LogWatchApi.tsx b/karavan-app/src/main/webui/src/karavan/api/LogWatchApi.tsx
index bdbb9d73..76f9f493 100644
--- a/karavan-app/src/main/webui/src/karavan/api/LogWatchApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/LogWatchApi.tsx
@@ -17,7 +17,7 @@
import {SsoApi} from "@api/auth/SsoApi";
import {fetchEventSource} from "@microsoft/fetch-event-source";
-import {ProjectEventBus} from "../bus/ProjectEventBus";
+import {ProjectEventBus} from "@bus/ProjectEventBus";
import {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
export class LogWatchApi {
diff --git a/karavan-app/src/main/webui/src/karavan/api/NotificationApi.tsx b/karavan-app/src/main/webui/src/karavan/api/NotificationApi.tsx
index 98363c20..88732ce7 100644
--- a/karavan-app/src/main/webui/src/karavan/api/NotificationApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/NotificationApi.tsx
@@ -31,13 +31,11 @@ export class NotificationApi {
}
static onSystemMessage (ev: EventSourceMessage) {
- console.log(`onSystemMessage`, ev);
const ke = NotificationApi.getKaravanEvent(ev, 'system');
NotificationEventBus.sendEvent(ke);
}
static onUserMessage (ev: EventSourceMessage) {
- console.log(`onUserMessage`, ev);
const ke = NotificationApi.getKaravanEvent(ev, 'user');
NotificationEventBus.sendEvent(ke);
}
diff --git a/karavan-app/src/main/webui/src/karavan/api/SearchApi.tsx b/karavan-app/src/main/webui/src/karavan/api/SearchApi.tsx
index 31b7fa01..3e1f441d 100644
--- a/karavan-app/src/main/webui/src/karavan/api/SearchApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/SearchApi.tsx
@@ -1,6 +1,6 @@
import axios from "axios";
import {ErrorEventBus} from "@bus/ErrorEventBus";
-import {SearchResult} from "../models/SearchModels";
+import {SearchResult} from "@models/SearchModels";
import {AuthApi} from "@api/auth/AuthApi";
axios.defaults.headers.common['Accept'] = 'application/json';
diff --git a/karavan-app/src/main/webui/src/karavan/api/SystemApi.tsx b/karavan-app/src/main/webui/src/karavan/api/SystemApi.tsx
index ccacb098..b801e6d6 100644
--- a/karavan-app/src/main/webui/src/karavan/api/SystemApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/SystemApi.tsx
@@ -150,7 +150,6 @@ export class SystemApi {
static async getEnvVars(after: (envVars: string[]) => void) {
instance.get('/ui/diagnostics/env-vars', {headers: {'Accept': 'application/json'}})
.then(res => {
- console.log(res)
if (res.status === 200) {
after(res.data);
}
(camel-karavan) 24/33: Front-end Documentation for 4.18.0
Posted by ma...@apache.org.
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 70eff99bb3b539401a2745d9d2862831c4795289
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:49:15 2026 -0500
Front-end Documentation for 4.18.0
---
.../webui/src/karavan/features/documentation/Documentation.css | 1 -
.../src/karavan/features/documentation/DocumentationPage.tsx | 10 ++++++----
.../features/documentation/components/ComponentCard.tsx | 2 +-
.../features/documentation/components/ComponentModal.tsx | 4 ++--
.../webui/src/karavan/features/documentation/eip/EipCard.tsx | 2 +-
.../webui/src/karavan/features/documentation/eip/EipModal.tsx | 4 ++--
.../karavan/features/documentation/kamelets/KameletCard.tsx | 2 +-
.../karavan/features/documentation/kamelets/KameletModal.tsx | 2 +-
8 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/Documentation.css b/karavan-app/src/main/webui/src/karavan/features/documentation/Documentation.css
index 756cc34b..8b477627 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/Documentation.css
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/Documentation.css
@@ -16,7 +16,6 @@
*/
.karavan .documentation-section {
- padding: 16px;
height: 100%;
overflow: auto;
}
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/DocumentationPage.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/DocumentationPage.tsx
index 7ac03fdf..8e875075 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/DocumentationPage.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/DocumentationPage.tsx
@@ -33,8 +33,9 @@ import {extractTitleFromMarkdown} from "@util/StringUtils";
import MarkdownPreview from "@uiw/react-markdown-preview";
import {ErrorBoundaryWrapper} from "@shared/ui/ErrorBoundaryWrapper";
import {useTheme} from "@app/theme/ThemeContext";
+import {SourcesTab} from "@features/project/files/SourcesTab";
-const BUILD_IN_DOCUMENTATION_PAGES = ['processors', 'components', 'kamelets']
+const BUILD_IN_DOCUMENTATION_PAGES = ['processors', 'components', 'kamelets', 'source']
export const DocumentationPage = () => {
@@ -95,8 +96,8 @@ export const DocumentationPage = () => {
}
function getNavigation() {
const lengths: any = {
- 'processors': components.length,
- 'components': elements.length,
+ 'processors': elements.length,
+ 'components': components.length,
'kamelets': kameletList.length,
}
return (
@@ -149,13 +150,14 @@ export const DocumentationPage = () => {
<RightPanel
title={title()}
toolsStart={getNavigation()}
- tools={activeItemIsBuildIn() ? getTools() : <></>}
+ tools={activeItemIsBuildIn() ? getTools() : undefined}
mainPanel={
<div className="right-panel-card">
<div className="documentation-section">
{activeItem === 'kamelets' && <KameletsTab kameletList={kameletList}/>}
{activeItem === 'processors' && <EipTab elements={elements}/>}
{activeItem === 'components' && <ComponentsTab components={components}/>}
+ {activeItem === 'source' && <SourcesTab />}
{!activeItemIsBuildIn() &&
<ErrorBoundaryWrapper onError={error => console.error((error))}>
<MarkdownPreview key={"DocumentationMarkdownPreview"} source={markdown} wrapperElement={{'data-color-mode': isDark ? 'dark' : 'light'}}/>
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentCard.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentCard.tsx
index a6466bd5..f24bfe5a 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentCard.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentCard.tsx
@@ -16,7 +16,7 @@
*/
import React from 'react';
import {Badge, Card, CardBody, CardFooter, CardHeader, CardTitle, Content, Flex} from '@patternfly/react-core';
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {Component} from "@karavan-core/model/ComponentModels";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
import {shallow} from "zustand/shallow";
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentModal.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentModal.tsx
index 2abef808..5bae27e7 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/components/ComponentModal.tsx
@@ -17,9 +17,9 @@
import React, {useState} from 'react';
import {Badge, Button, CardHeader, Content, Flex, Modal, ModalBody, ModalFooter, ModalHeader, Tab, Tabs, TabTitleText} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
+import '@features/project/designer/karavan.css';
import {Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {ComponentApi} from "@karavan-core/api/ComponentApi";
import {ComponentHeader, ComponentProperty} from "@karavan-core/model/ComponentModels";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipCard.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipCard.tsx
index d1659954..6f7f3ae2 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipCard.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipCard.tsx
@@ -16,7 +16,7 @@
*/
import React from 'react';
import {Badge, Card, CardBody, CardFooter, CardHeader, CardTitle, Content} from '@patternfly/react-core';
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {ElementMeta} from "@karavan-core/model/CamelMetadata";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
import {shallow} from "zustand/shallow";
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipModal.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipModal.tsx
index 7d98e3de..85ccc71d 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/eip/EipModal.tsx
@@ -17,9 +17,9 @@
import React from 'react';
import {Badge, Button, CardHeader, CardTitle, Content, Flex, Modal, ModalBody, ModalFooter, ModalHeader} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
+import '@features/project/designer/karavan.css';
import {Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {PropertyMeta} from "@karavan-core/model/CamelMetadata";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
import {shallow} from "zustand/shallow";
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletCard.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletCard.tsx
index 175346af..4292c22d 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletCard.tsx
@@ -17,7 +17,7 @@
import React from 'react';
import {Badge, Card, CardBody, CardFooter, CardHeader, CardTitle, Flex} from '@patternfly/react-core';
import {KameletModel} from "@karavan-core/model/KameletModels";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {KameletApi} from "@karavan-core/api/KameletApi";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
import {shallow} from "zustand/shallow";
diff --git a/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletModal.tsx b/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletModal.tsx
index 3992b44c..c78a4217 100644
--- a/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/documentation/kamelets/KameletModal.tsx
@@ -18,7 +18,7 @@ import React from 'react';
import {Badge, Button, CardHeader, CardTitle, Content, Flex, Modal, ModalBody, ModalFooter, ModalHeader} from '@patternfly/react-core';
import {Property} from "@karavan-core/model/KameletModels";
import {Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {useDocumentationStore} from "../../../stores/DocumentationStore";
import {shallow} from "zustand/shallow";
(camel-karavan) 02/33: Resources for 4.18.0
Posted by ma...@apache.org.
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 bbfe6c20afea888fede42e4457642a5f8005657d
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 15:45:36 2026 -0500
Resources for 4.18.0
---
.../src/main/resources/application.properties | 40 +-
.../configuration/docker/components-blocklist.txt | 0
.../configuration/docker/kamelets-blocklist.txt | 0
.../kubernetes/components-blocklist.txt | 0
.../kubernetes/kamelets-blocklist.txt | 0
.../src/main/resources/contracts/docker/.gitignore | 19 +
.../main/resources/contracts/kubernetes/.gitignore | 19 +
.../src/main/resources/database/V1_0__karavan.sql | 33 +
karavan-app/src/main/resources/infinispan.xml | 120 -
.../src/main/resources/metadata/components.json | 765 +
.../src/main/resources/metadata/kamelets.yaml | 22588 +++++++++++++++++++
.../src/main/resources/metadata/spiBeans.json | 4253 ++++
.../templates/docker/application.properties | 2 +
.../docker/messaging-bean-template.camel.yaml | 9 -
....camel.yaml => wizard-bean-database.camel.yaml} | 0
.../docker/wizard-bean-messaging.camel.yaml | 11 +
.../templates/kubernetes/application.properties | 13 +-
.../kubernetes/messaging-bean-template.camel.yaml | 9 -
....camel.yaml => wizard-bean-database.camel.yaml} | 0
.../kubernetes/wizard-bean-messaging.camel.yaml | 11 +
20 files changed, 27735 insertions(+), 157 deletions(-)
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index 5bbfd2cb..22675323 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -14,22 +14,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+karavan.appName=karavan
karavan.title=Apache Camel Karavan
-karavan.version=4.14.5
+karavan.version=4.18.0
-karavan.camel.status.interval=2s
-karavan.container.status.interval=2s
+karavan.camel.status.interval=5s
+karavan.container.status.interval=3s
# karavan.container.status.interval should be off in kubernetes
karavan.container.statistics.interval=10s
# karavan.container.statistics.interval should be off in kubernetes
-karavan.devmode.image=ghcr.io/apache/camel-karavan-devmode:4.14.5
+karavan.devmode.image=ghcr.io/apache/camel-karavan-devmode:${${karavan.version}:latest}
karavan.devmode.service.account=karavan
karavan.builder.service.account=karavan
karavan.secret.name=karavan
-quarkus.infinispan-embedded.xml-config=infinispan.xml
-karavan.cache.state.path=./cache-data
karavan.docker.network=karavan
# Keycloak configuration
@@ -62,8 +61,9 @@ quarkus.http.auth.permission.public.policy=permit
quarkus.http.auth.permission.public.methods=GET
# SSO Authentication
-%oidc.platform.auth=oidc
+%platform.auth=oidc
quarkus.oidc.enabled=true
+# Important! Set quarkus.oidc.tenant-enabled=true for platform.auth=oidc
quarkus.oidc.tenant-enabled=false
quarkus.http.auth.basic=false
quarkus.oidc.auth-server-url=${karavan.keycloak.url}/realms/${karavan.keycloak.realm}
@@ -71,7 +71,6 @@ quarkus.oidc.client-id=${karavan.keycloak.backend.clientId}
quarkus.oidc.credentials.secret=${karavan.keycloak.backend.secret}
quarkus.oidc.application-type=service
quarkus.oidc.roles.source=accesstoken
-quarkus.keycloak.devservices.enabled=false
# Quarkus configuration
quarkus.quinoa.enable-spa-routing=true
@@ -94,10 +93,11 @@ quarkus.kubernetes-client.devservices.enabled=false
quarkus.quinoa.ci=false
quarkus.quinoa.package-manager-install=true
-quarkus.quinoa.package-manager-install.node-version=22.14.0
+quarkus.quinoa.package-manager-install.node-version=24.11.1
quarkus.quinoa.dev-server.port=3008
quarkus.quinoa.dev-server.check-timeout=60000
quarkus.quinoa.ignored-path-prefixes=/ui,/public,/api/,/auth
+quarkus.quinoa.package-manager-command.build-env.NODE_OPTIONS=--max-old-space-size=4096
#quarkus.jgit.devservices.enabled=true
#
@@ -106,5 +106,25 @@ quarkus.quinoa.ignored-path-prefixes=/ui,/public,/api/,/auth
#quarkus.jgit.devservices.oranizations=karavan
#quarkus.jgit.devservices.repositories=karavan
-platform.password=K@r@v@n414
+platform.password=K@r@v@n418
+
+karavan.datasource.username=karavan
+karavan.datasource.password=K@r@v@n418
+karavan.datasource.url=jdbc:postgresql://postgres:5432/karavan
+karavan.datasource.schemas=public
+
+quarkus.datasource.db-kind=postgresql
+quarkus.datasource.username=${KARAVAN_DATASOURCE_USERNAME:${karavan.datasource.username}}
+quarkus.datasource.password=${KARAVAN_DATASOURCE_PASSWORD:${karavan.datasource.password}}
+quarkus.datasource.jdbc.url=${KARAVAN_DATASOURCE_URL:${karavan.datasource.url}}
+quarkus.datasource.jdbc.max-size=13
+quarkus.flyway.schemas=${KARAVAN_DATASOURCE_SCHEMAS:public}
+quarkus.flyway.locations=classpath:database
+quarkus.flyway.clean-disabled=true
+quarkus.flyway.migrate-at-start=true
+quarkus.flyway.baseline-on-migrate=true
+quarkus.flyway.baseline-version=1.0
+quarkus.flyway.table=flyway_history
+quarkus.flyway.active=${KARAVAN_FLYWAY_ACTIVE:true}
+quarkus.hibernate-orm.active=${KARAVAN_HIBERNATE_ORM_ACTIVE:true}
diff --git a/karavan-app/src/main/resources/configuration/docker/components-blocklist.txt b/karavan-app/src/main/resources/configuration/docker/components-blocklist.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/karavan-app/src/main/resources/configuration/docker/kamelets-blocklist.txt b/karavan-app/src/main/resources/configuration/docker/kamelets-blocklist.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/karavan-app/src/main/resources/configuration/kubernetes/components-blocklist.txt b/karavan-app/src/main/resources/configuration/kubernetes/components-blocklist.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/karavan-app/src/main/resources/configuration/kubernetes/kamelets-blocklist.txt b/karavan-app/src/main/resources/configuration/kubernetes/kamelets-blocklist.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/karavan-app/src/main/resources/contracts/docker/.gitignore b/karavan-app/src/main/resources/contracts/docker/.gitignore
new file mode 100644
index 00000000..51a3373b
--- /dev/null
+++ b/karavan-app/src/main/resources/contracts/docker/.gitignore
@@ -0,0 +1,19 @@
+# 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.
+
+# Ignore everything in this directory
+.gitignore
+# Except this file
+!.gitignore
diff --git a/karavan-app/src/main/resources/contracts/kubernetes/.gitignore b/karavan-app/src/main/resources/contracts/kubernetes/.gitignore
new file mode 100644
index 00000000..51a3373b
--- /dev/null
+++ b/karavan-app/src/main/resources/contracts/kubernetes/.gitignore
@@ -0,0 +1,19 @@
+# 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.
+
+# Ignore everything in this directory
+.gitignore
+# Except this file
+!.gitignore
diff --git a/karavan-app/src/main/resources/database/V1_0__karavan.sql b/karavan-app/src/main/resources/database/V1_0__karavan.sql
new file mode 100644
index 00000000..da512a4b
--- /dev/null
+++ b/karavan-app/src/main/resources/database/V1_0__karavan.sql
@@ -0,0 +1,33 @@
+create table access_state
+(
+ last_update timestamp(6) with time zone,
+ data jsonb,
+ key varchar(255) not null primary key,
+ type varchar(255)
+);
+
+create index idx_access_type on access_state (type);
+create index idx_access_last_update on access_state (last_update);
+
+create table project_state
+(
+ last_update timestamp(6) with time zone,
+ data jsonb,
+ key varchar(255) not null primary key,
+ type varchar(255)
+);
+
+create index idx_project_type on project_state (type);
+create index idx_project_last_update on project_state (last_update);
+
+create table session_state
+(
+ expiry timestamp(6) with time zone,
+ last_update timestamp(6) with time zone,
+ data jsonb,
+ key varchar(255) not null primary key,
+ type varchar(255)
+);
+
+create index idx_session_type on session_state (type);
+create index idx_session_expire on session_state (expiry);
diff --git a/karavan-app/src/main/resources/infinispan.xml b/karavan-app/src/main/resources/infinispan.xml
deleted file mode 100644
index 519c0a85..00000000
--- a/karavan-app/src/main/resources/infinispan.xml
+++ /dev/null
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<infinispan
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="urn:infinispan:config:15.0 https://infinispan.org/schemas/infinispan-config-15.0.xsd"
- xmlns="urn:infinispan:config:15.0">
-
- <cache-container name="replicated" statistics="true">
- <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}" node-name="${infinispan.node.name:}"/>
- <global-state>
- <persistent-location path="./cache-data"/>
- </global-state>
-
- <replicated-cache-configuration name="replicated" mode="ASYNC" statistics="true">
- <encoding media-type="application/x-protostream"/>
- <persistence>
- <file-store shared="false">
- <write-behind modification-queue-size="2048"/>
- <index path="./index"/>
- <data path="./data"/>
- </file-store>
- </persistence>
- <memory max-count="1000000" when-full="REMOVE"/>
- </replicated-cache-configuration>
-
- <!-- Project-related caches -->
- <replicated-cache name="ProjectFolder" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.ProjectFolder</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="ProjectFile" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.ProjectFile</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
-
- <replicated-cache name="ProjectFileCommited" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.ProjectFileCommited</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
-
- <!-- Deployment-related caches -->
- <replicated-cache name="DeploymentStatus" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.DeploymentStatus</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="PodContainerStatus" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.PodContainerStatus</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="ServiceStatus" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.ServiceStatus</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="CamelStatus" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.CamelStatus</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
-
- <!-- Access/security caches -->
- <replicated-cache name="AccessUser" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.AccessUser</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="AccessRole" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.AccessRole</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="AccessPassword" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.AccessPassword</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- <replicated-cache name="AccessSession" configuration="replicated">
- <indexing enabled="true" path="./indexing">
- <index-reader refresh-interval="1000"/>
- <indexed-entities>
- <indexed-entity>org.apache.camel.karavan.cache.AccessSession</indexed-entity>
- </indexed-entities>
- </indexing>
- </replicated-cache>
- </cache-container>
-</infinispan>
diff --git a/karavan-app/src/main/resources/metadata/components.json b/karavan-app/src/main/resources/metadata/components.json
new file mode 100644
index 00000000..3aea3a42
--- /dev/null
+++ b/karavan-app/src/main/resources/metadata/components.json
@@ -0,0 +1,765 @@
+[
+{"component":{"kind":"component","name":"activemq","title":"ActiveMQ 5.x","description":"Send messages to (or consume from) Apache ActiveMQ 5.x. This component extends the Camel JMS component.","deprecated":false,"firstVersion":"1.0.0","label":"messaging","javaType":"org.apache.camel.component.activemq.ActiveMQComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-activemq","version":"4.18.0","scheme":"activemq","extendsScheme":"jms","syntax":"activemq:destin [...]
+,
+{"component":{"kind":"component","name":"activemq6","title":"ActiveMQ 6.x","description":"Send messages to (or consume from) Apache ActiveMQ 6.x. This component extends the Camel JMS component.","deprecated":false,"firstVersion":"4.7.0","label":"messaging","javaType":"org.apache.camel.component.activemq6.ActiveMQComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-activemq6","version":"4.18.0","scheme":"activemq6","extendsScheme":"jms","syntax":"activemq6:d [...]
+,
+{"component":{"kind":"component","name":"amqp","title":"AMQP","description":"Messaging with AMQP protocol using Apache QPid Client.","deprecated":false,"firstVersion":"1.2.0","label":"messaging","javaType":"org.apache.camel.component.amqp.AMQPComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-amqp","version":"4.18.0","scheme":"amqp","extendsScheme":"jms","syntax":"amqp:destinationType:destinationName","async":true,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"arangodb","title":"ArangoDb","description":"Perform operations on ArangoDb when used as a Document Database, or as a Graph Database","deprecated":false,"firstVersion":"3.5.0","label":"database","javaType":"org.apache.camel.component.arangodb.ArangoDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-arangodb","version":"4.18.0","scheme":"arangodb","extendsScheme":"","syntax":"arangodb:database","async":false,"api": [...]
+,
+{"component":{"kind":"component","name":"as2","title":"AS2","description":"Transfer data securely and reliably using the AS2 protocol (RFC4130).","deprecated":false,"firstVersion":"2.22.0","label":"file","javaType":"org.apache.camel.component.as2.AS2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-as2","version":"4.18.0","scheme":"as2","extendsScheme":"","syntax":"as2:apiName/methodName","async":false,"api":true,"apiSyntax":"apiName/methodName","consume [...]
+,
+{"component":{"kind":"component","name":"asterisk","title":"Asterisk","description":"Interact with Asterisk PBX Server (VoIP).","deprecated":false,"firstVersion":"2.18.0","label":"mobile","javaType":"org.apache.camel.component.asterisk.AsteriskComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-asterisk","version":"4.18.0","scheme":"asterisk","extendsScheme":"","syntax":"asterisk:name","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"le [...]
+,
+{"component":{"kind":"component","name":"atmosphere-websocket","title":"Atmosphere Websocket","description":"Expose WebSocket endpoints using the Atmosphere framework.","deprecated":false,"firstVersion":"2.14.0","label":"http,networking","javaType":"org.apache.camel.component.atmosphere.websocket.WebsocketComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-atmosphere-websocket","version":"4.18.0","scheme":"atmosphere-websocke [...]
+,
+{"component":{"kind":"component","name":"atom","title":"Atom","description":"Poll Atom RSS feeds.","deprecated":false,"firstVersion":"1.2.0","label":"document","javaType":"org.apache.camel.component.atom.AtomComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-atom","version":"4.18.0","scheme":"atom","extendsScheme":"","syntax":"atom:feedUri","async":false,"api":false,"consumerOnly":true,"producerOnly":false,"lenientProperties":true,"browsable":false,"remot [...]
+,
+{"component":{"kind":"component","name":"avro","title":"Avro RPC","description":"Produce or consume Apache Avro RPC services.","deprecated":false,"firstVersion":"2.10.0","label":"rpc","javaType":"org.apache.camel.component.avro.AvroComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-avro-rpc","version":"4.18.0","scheme":"avro","extendsScheme":"","syntax":"avro:transport:host:port/messageName","async":true,"api":false,"consumerOnly":false,"producerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"aws-bedrock","title":"AWS Bedrock","description":"Invoke Model of AWS Bedrock service.","deprecated":false,"firstVersion":"4.5.0","label":"ai,cloud","javaType":"org.apache.camel.component.aws2.bedrock.runtime.BedrockComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws-bedrock","version":"4.18.0","scheme":"aws-bedrock","extendsScheme":"","syntax":"aws-bedrock:label","async":false,"api":false,"consumerOnly":false," [...]
+,
+{"component":{"kind":"component","name":"aws-bedrock-agent","title":"AWS Bedrock Agent","description":"Operate on AWS Bedrock through its Agent.","deprecated":false,"firstVersion":"4.5.0","label":"ai,cloud","javaType":"org.apache.camel.component.aws2.bedrock.agent.BedrockAgentComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws-bedrock","version":"4.18.0","scheme":"aws-bedrock-agent","extendsScheme":"","syntax":"aws-bedrock-agent:label","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"aws-bedrock-agent-runtime","title":"AWS Bedrock Agent Runtime","description":"Invoke Model of AWS Bedrock Agent Runtime service.","deprecated":false,"firstVersion":"4.5.0","label":"ai,cloud","javaType":"org.apache.camel.component.aws2.bedrock.agentruntime.BedrockAgentRuntimeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws-bedrock","version":"4.18.0","scheme":"aws-bedrock-agent-runtime","extendsScheme":"","syn [...]
+,
+{"component":{"kind":"component","name":"aws-cloudtrail","title":"AWS Cloudtrail","description":"Consume events from Amazon Cloudtrail using AWS SDK version 2.x.","deprecated":false,"firstVersion":"3.19.0","label":"cloud,management,monitoring","javaType":"org.apache.camel.component.aws.cloudtrail.CloudtrailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws-cloudtrail","version":"4.18.0","scheme":"aws-cloudtrail","extendsScheme":"","syntax":"aws-cloudt [...]
+,
+{"component":{"kind":"component","name":"aws-config","title":"AWS Config Service","description":"Manage AWS Config service.","deprecated":false,"firstVersion":"4.3.0","label":"cloud,management","javaType":"org.apache.camel.component.aws.config.AWSConfigComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws-config","version":"4.18.0","scheme":"aws-config","extendsScheme":"","syntax":"aws-config:label","async":false,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"aws-secrets-manager","title":"AWS Secrets Manager","description":"Manage secrets using AWS Secrets Manager.","deprecated":false,"firstVersion":"3.9.0","label":"cloud,management","javaType":"org.apache.camel.component.aws.secretsmanager.SecretsManagerComponent","supportLevel":"Stable","metadata":{"vault":"aws-secrets-manager"},"groupId":"org.apache.camel","artifactId":"camel-aws-secrets-manager","version":"4.18.0","scheme":"aws-secrets-manager","ex [...]
+,
+{"component":{"kind":"component","name":"aws-security-hub","title":"AWS Security Hub","description":"Manage and interact with AWS Security Hub for security findings.","deprecated":false,"firstVersion":"4.18.0","label":"cloud,security","javaType":"org.apache.camel.component.aws.securityhub.SecurityHubComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-aws-security-hub","version":"4.18.0","scheme":"aws-security-hub","extendsScheme":"","syntax":"aws-security [...]
+,
+{"component":{"kind":"component","name":"aws2-athena","title":"AWS Athena","description":"Access AWS Athena.","deprecated":false,"firstVersion":"3.4.0","label":"cloud,database","javaType":"org.apache.camel.component.aws2.athena.Athena2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-athena","version":"4.18.0","scheme":"aws2-athena","extendsScheme":"","syntax":"aws2-athena:label","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"le [...]
+,
+{"component":{"kind":"component","name":"aws2-comprehend","title":"AWS Comprehend","description":"Perform natural language processing using AWS Comprehend and AWS SDK version 2.x.","deprecated":false,"firstVersion":"4.18.0","label":"cloud,ai","javaType":"org.apache.camel.component.aws2.comprehend.Comprehend2Component","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-aws2-comprehend","version":"4.18.0","scheme":"aws2-comprehend","extendsScheme":"","syntax":"aws2-c [...]
+,
+{"component":{"kind":"component","name":"aws2-cw","title":"AWS CloudWatch","description":"Sending metrics to AWS CloudWatch.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,monitoring","javaType":"org.apache.camel.component.aws2.cw.Cw2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-cw","version":"4.18.0","scheme":"aws2-cw","extendsScheme":"","syntax":"aws2-cw:namespace","async":false,"api":false,"consumerOnly":false,"producerOnly":true," [...]
+,
+{"component":{"kind":"component","name":"aws2-ddb","title":"AWS DynamoDB","description":"Store and retrieve data from AWS DynamoDB.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,database","javaType":"org.apache.camel.component.aws2.ddb.Ddb2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-ddb","version":"4.18.0","scheme":"aws2-ddb","extendsScheme":"","syntax":"aws2-ddb:tableName","async":false,"api":false,"consumerOnly":false,"producerOn [...]
+,
+{"component":{"kind":"component","name":"aws2-ddbstream","title":"AWS DynamoDB Streams","description":"Receive messages from AWS DynamoDB Stream.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.ddbstream.Ddb2StreamComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-ddb","version":"4.18.0","scheme":"aws2-ddbstream","extendsScheme":"","syntax":"aws2-ddbstream:tableName","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"aws2-ec2","title":"AWS Elastic Compute Cloud (EC2)","description":"Manage AWS EC2 instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.ec2.AWS2EC2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-ec2","version":"4.18.0","scheme":"aws2-ec2","extendsScheme":"","syntax":"aws2-ec2:label","async":false,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"aws2-ecs","title":"AWS Elastic Container Service (ECS)","description":"Manage AWS ECS cluster instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.ecs.ECS2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-ecs","version":"4.18.0","scheme":"aws2-ecs","extendsScheme":"","syntax":"aws2-ecs:label","async":false,"api":false,"consumerOnly":false [...]
+,
+{"component":{"kind":"component","name":"aws2-eks","title":"AWS Elastic Kubernetes Service (EKS)","description":"Manage AWS EKS cluster instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.eks.EKS2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-eks","version":"4.18.0","scheme":"aws2-eks","extendsScheme":"","syntax":"aws2-eks:label","async":false,"api":false,"consumerOnly":fals [...]
+,
+{"component":{"kind":"component","name":"aws2-eventbridge","title":"AWS Eventbridge","description":"Send events to AWS Eventbridge cluster instances.","deprecated":false,"firstVersion":"3.6.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.eventbridge.EventbridgeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-eventbridge","version":"4.18.0","scheme":"aws2-eventbridge","extendsScheme":"","syntax":"aws2-eventbridge://eventbus [...]
+,
+{"component":{"kind":"component","name":"aws2-iam","title":"AWS Identity and Access Management (IAM)","description":"Manage AWS IAM instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.iam.IAM2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-iam","version":"4.18.0","scheme":"aws2-iam","extendsScheme":"","syntax":"aws2-iam:label","async":false,"api":false,"consumerOnly":false,"p [...]
+,
+{"component":{"kind":"component","name":"aws2-kinesis","title":"AWS Kinesis","description":"Consume and produce records from and to AWS Kinesis Streams.","deprecated":false,"firstVersion":"3.2.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.kinesis.Kinesis2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-kinesis","version":"4.18.0","scheme":"aws2-kinesis","extendsScheme":"","syntax":"aws2-kinesis:streamName","async":false," [...]
+,
+{"component":{"kind":"component","name":"aws2-kinesis-firehose","title":"AWS Kinesis Firehose","description":"Produce data to AWS Kinesis Firehose streams.","deprecated":false,"firstVersion":"3.2.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.firehose.KinesisFirehose2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-kinesis","version":"4.18.0","scheme":"aws2-kinesis-firehose","extendsScheme":"","syntax":"aws2-kinesis-fireho [...]
+,
+{"component":{"kind":"component","name":"aws2-kms","title":"AWS Key Management Service (KMS)","description":"Manage keys stored in AWS KMS instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.kms.KMS2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-kms","version":"4.18.0","scheme":"aws2-kms","extendsScheme":"","syntax":"aws2-kms:label","async":false,"api":false,"consumerOnly":f [...]
+,
+{"component":{"kind":"component","name":"aws2-lambda","title":"AWS Lambda","description":"Manage and invoke AWS Lambda functions.","deprecated":false,"firstVersion":"3.2.0","label":"cloud,serverless","javaType":"org.apache.camel.component.aws2.lambda.Lambda2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-lambda","version":"4.18.0","scheme":"aws2-lambda","extendsScheme":"","syntax":"aws2-lambda:function","async":false,"api":false,"consumerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"aws2-mq","title":"AWS MQ","description":"Send messages to AWS MQ.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.mq.MQ2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-mq","version":"4.18.0","scheme":"aws2-mq","extendsScheme":"","syntax":"aws2-mq:label","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":fals [...]
+,
+{"component":{"kind":"component","name":"aws2-msk","title":"AWS Managed Streaming for Apache Kafka (MSK)","description":"Manage AWS MSK instances.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.msk.MSK2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-msk","version":"4.18.0","scheme":"aws2-msk","extendsScheme":"","syntax":"aws2-msk:label","async":false,"api":false,"consumerOnly":fals [...]
+,
+{"component":{"kind":"component","name":"aws2-polly","title":"AWS Polly","description":"Synthesize speech using AWS Polly and AWS SDK version 2.x.","deprecated":false,"firstVersion":"4.18.0","label":"cloud,ai","javaType":"org.apache.camel.component.aws2.polly.Polly2Component","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-aws2-polly","version":"4.18.0","scheme":"aws2-polly","extendsScheme":"","syntax":"aws2-polly:label","async":false,"api":false,"consumerOnly": [...]
+,
+{"component":{"kind":"component","name":"aws2-redshift-data","title":"AWS RedshiftData","description":"Perform operations on AWS Redshift using Redshift Data API.","deprecated":false,"firstVersion":"4.1.0","label":"cloud,serverless,database,bigdata","javaType":"org.apache.camel.component.aws2.redshift.data.RedshiftData2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-redshift","version":"4.18.0","scheme":"aws2-redshift-data","extendsScheme":"","syn [...]
+,
+{"component":{"kind":"component","name":"aws2-rekognition","title":"AWS Rekognition","description":"Manage and invoke AWS Rekognition.","deprecated":false,"firstVersion":"4.17.0","label":"cloud,ai","javaType":"org.apache.camel.component.aws2.rekognition.Rekognition2Component","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-aws2-rekognition","version":"4.18.0","scheme":"aws2-rekognition","extendsScheme":"","syntax":"aws2-rekognition:label","async":false,"api":fal [...]
+,
+{"component":{"kind":"component","name":"aws2-s3","title":"AWS S3 Storage Service","description":"Store and retrieve objects from AWS S3 Storage Service.","deprecated":false,"firstVersion":"3.2.0","label":"cloud,file","javaType":"org.apache.camel.component.aws2.s3.AWS2S3Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-s3","version":"4.18.0","scheme":"aws2-s3","extendsScheme":"","syntax":"aws2-s3://bucketNameOrArn","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"aws2-s3-vectors","title":"AWS S3 Vectors","description":"Store and query vector embeddings using AWS S3 Vectors with similarity search.","deprecated":false,"firstVersion":"4.17.0","label":"cloud,ai","javaType":"org.apache.camel.component.aws2.s3vectors.AWS2S3VectorsComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-aws2-s3-vectors","version":"4.18.0","scheme":"aws2-s3-vectors","extendsScheme":"","syntax":"aws2-s3- [...]
+,
+{"component":{"kind":"component","name":"aws2-ses","title":"AWS Simple Email Service (SES)","description":"Send e-mails through AWS SES service.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,mail","javaType":"org.apache.camel.component.aws2.ses.Ses2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-ses","version":"4.18.0","scheme":"aws2-ses","extendsScheme":"","syntax":"aws2-ses:from","async":false,"api":false,"consumerOnly":false,"produc [...]
+,
+{"component":{"kind":"component","name":"aws2-sns","title":"AWS Simple Notification System (SNS)","description":"Send messages to AWS Simple Notification Topic.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,messaging,mobile","javaType":"org.apache.camel.component.aws2.sns.Sns2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-sns","version":"4.18.0","scheme":"aws2-sns","extendsScheme":"","syntax":"aws2-sns:topicNameOrArn","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"aws2-sqs","title":"AWS Simple Queue Service (SQS)","description":"Send and receive messages to/from AWS SQS.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.sqs.Sqs2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-sqs","version":"4.18.0","scheme":"aws2-sqs","extendsScheme":"","syntax":"aws2-sqs:queueNameOrArn","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"aws2-step-functions","title":"AWS StepFunctions","description":"Manage and invoke AWS Step functions.","deprecated":false,"firstVersion":"4.0.0","label":"cloud,serverless","javaType":"org.apache.camel.component.aws2.stepfunctions.StepFunctions2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-step-functions","version":"4.18.0","scheme":"aws2-step-functions","extendsScheme":"","syntax":"aws2-step-functions:lab [...]
+,
+{"component":{"kind":"component","name":"aws2-sts","title":"AWS Security Token Service (STS)","description":"Manage AWS STS cluster instances.","deprecated":false,"firstVersion":"3.5.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.sts.STS2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-sts","version":"4.18.0","scheme":"aws2-sts","extendsScheme":"","syntax":"aws2-sts:label","async":false,"api":false,"consumerOnly":false,"p [...]
+,
+{"component":{"kind":"component","name":"aws2-textract","title":"AWS Textract","description":"Extract text and data from documents using AWS Textract and AWS SDK version 2.x.","deprecated":false,"firstVersion":"4.15.0","label":"cloud,document","javaType":"org.apache.camel.component.aws2.textract.Textract2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-textract","version":"4.18.0","scheme":"aws2-textract","extendsScheme":"","syntax":"aws2-textract: [...]
+,
+{"component":{"kind":"component","name":"aws2-timestream","title":"AWS Timestream","description":"Write records and execute queries on AWS time-series database","deprecated":false,"firstVersion":"4.1.0","label":"cloud,database","javaType":"org.apache.camel.component.aws2.timestream.Timestream2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-timestream","version":"4.18.0","scheme":"aws2-timestream","extendsScheme":"","syntax":"aws2-timestream:client [...]
+,
+{"component":{"kind":"component","name":"aws2-transcribe","title":"AWS Transcribe","description":"Automatically convert speech to text using AWS Transcribe service","deprecated":false,"firstVersion":"4.15.0","label":"cloud,messaging","javaType":"org.apache.camel.component.aws2.transcribe.Transcribe2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-transcribe","version":"4.18.0","scheme":"aws2-transcribe","extendsScheme":"","syntax":"aws2-transcribe: [...]
+,
+{"component":{"kind":"component","name":"aws2-translate","title":"AWS Translate","description":"Translate texts using AWS Translate and AWS SDK version 2.x.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,management","javaType":"org.apache.camel.component.aws2.translate.Translate2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-aws2-translate","version":"4.18.0","scheme":"aws2-translate","extendsScheme":"","syntax":"aws2-translate:label","asyn [...]
+,
+{"component":{"kind":"component","name":"azure-cosmosdb","title":"Azure CosmosDB","description":"To read and write records to the CosmosDB database on Azure cloud platform.","deprecated":false,"firstVersion":"3.10.0","label":"cloud,database","javaType":"org.apache.camel.component.azure.cosmosdb.CosmosDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-cosmosdb","version":"4.18.0","scheme":"azure-cosmosdb","extendsScheme":"","syntax":"azure-cosmosdb [...]
+,
+{"component":{"kind":"component","name":"azure-eventhubs","title":"Azure Event Hubs","description":"Send and receive events to/from Azure Event Hubs using AMQP protocol.","deprecated":false,"firstVersion":"3.5.0","label":"cloud,messaging","javaType":"org.apache.camel.component.azure.eventhubs.EventHubsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-eventhubs","version":"4.18.0","scheme":"azure-eventhubs","extendsScheme":"","syntax":"azure-eventhu [...]
+,
+{"component":{"kind":"component","name":"azure-files","title":"Azure Files","description":"Send and receive files to Azure storage file share","deprecated":false,"firstVersion":"3.22.0","label":"cloud,file","javaType":"org.apache.camel.component.file.azure.FilesComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-azure-files","version":"4.18.0","scheme":"azure-files","extendsScheme":"file","syntax":"azure-files:account/share","async":false,"api":false,"con [...]
+,
+{"component":{"kind":"component","name":"azure-key-vault","title":"Azure Key Vault","description":"Manage secrets and keys in Azure Key Vault Service","deprecated":false,"firstVersion":"3.17.0","label":"cloud,cloud","javaType":"org.apache.camel.component.azure.key.vault.KeyVaultComponent","supportLevel":"Stable","metadata":{"vault":"azure-key-vault"},"groupId":"org.apache.camel","artifactId":"camel-azure-key-vault","version":"4.18.0","scheme":"azure-key-vault","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"azure-servicebus","title":"Azure ServiceBus","description":"Send and receive messages to/from Azure Service Bus.","deprecated":false,"firstVersion":"3.12.0","label":"cloud,messaging","javaType":"org.apache.camel.component.azure.servicebus.ServiceBusComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-servicebus","version":"4.18.0","scheme":"azure-servicebus","extendsScheme":"","syntax":"azure-servicebus:topicOr [...]
+,
+{"component":{"kind":"component","name":"azure-storage-blob","title":"Azure Storage Blob Service","description":"Store and retrieve blobs from Azure Storage Blob Service.","deprecated":false,"firstVersion":"3.3.0","label":"cloud,file","javaType":"org.apache.camel.component.azure.storage.blob.BlobComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-storage-blob","version":"4.18.0","scheme":"azure-storage-blob","extendsScheme":"","syntax":"azure-storage [...]
+,
+{"component":{"kind":"component","name":"azure-storage-datalake","title":"Azure Storage Data Lake Service","description":"Sends and receives files to/from Azure Data Lake Storage.","deprecated":false,"firstVersion":"3.8.0","label":"cloud,file,bigdata","javaType":"org.apache.camel.component.azure.storage.datalake.DataLakeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-storage-datalake","version":"4.18.0","scheme":"azure-storage-datalake","extendsS [...]
+,
+{"component":{"kind":"component","name":"azure-storage-queue","title":"Azure Storage Queue Service","description":"Stores and retrieves messages to/from Azure Storage Queue.","deprecated":false,"firstVersion":"3.3.0","label":"cloud,messaging","javaType":"org.apache.camel.component.azure.storage.queue.QueueComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-azure-storage-queue","version":"4.18.0","scheme":"azure-storage-queue","extendsScheme":"","syntax":"a [...]
+,
+{"component":{"kind":"component","name":"bean","title":"Bean","description":"Invoke methods of Java beans stored in Camel registry.","deprecated":false,"firstVersion":"1.0.0","label":"core,script","javaType":"org.apache.camel.component.bean.BeanComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-bean","version":"4.18.0","scheme":"bean","extendsScheme":"","syntax":"bean:beanName","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientPro [...]
+,
+{"component":{"kind":"component","name":"bean-validator","title":"Bean Validator","description":"Validate the message body using the Java Bean Validation API.","deprecated":false,"firstVersion":"2.3.0","label":"validation","javaType":"org.apache.camel.component.bean.validator.BeanValidatorComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-bean-validator","version":"4.18.0","scheme":"bean-validator","extendsScheme":"","syntax":"bean-validator:label","async [...]
+,
+{"component":{"kind":"component","name":"bonita","title":"Bonita","description":"Communicate with a remote Bonita BPM process engine.","deprecated":false,"firstVersion":"2.19.0","label":"workflow","javaType":"org.apache.camel.component.bonita.BonitaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-bonita","version":"4.18.0","scheme":"bonita","extendsScheme":"","syntax":"bonita:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":true, [...]
+,
+{"component":{"kind":"component","name":"box","title":"Box","description":"Upload, download and manage files, folders, groups, collaborations, etc. on box.com.","deprecated":false,"firstVersion":"2.14.0","label":"cloud,file,api","javaType":"org.apache.camel.component.box.BoxComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-box","version":"4.18.0","scheme":"box","extendsScheme":"","syntax":"box:apiName/methodName","async":false,"api":true,"apiSyntax":"api [...]
+,
+{"component":{"kind":"component","name":"braintree","title":"Braintree","description":"Process payments using Braintree Payments.","deprecated":false,"firstVersion":"2.17.0","label":"saas,finance","javaType":"org.apache.camel.component.braintree.BraintreeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-braintree","version":"4.18.0","scheme":"braintree","extendsScheme":"","syntax":"braintree:apiName/methodName","async":false,"api":true,"apiSyntax":"apiNa [...]
+,
+{"component":{"kind":"component","name":"browse","title":"Browse","description":"Inspect the messages received on endpoints supporting BrowsableEndpoint.","deprecated":false,"firstVersion":"1.3.0","label":"core,monitoring","javaType":"org.apache.camel.component.browse.BrowseComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-browse","version":"4.18.0","scheme":"browse","extendsScheme":"","syntax":"browse:name","async":false,"api":false,"consumerOnly":false [...]
+,
+{"component":{"kind":"component","name":"caffeine-cache","title":"Caffeine Cache","description":"Perform caching operations using Caffeine Cache.","deprecated":false,"firstVersion":"2.20.0","label":"cache,clustering","javaType":"org.apache.camel.component.caffeine.cache.CaffeineCacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-caffeine","version":"4.18.0","scheme":"caffeine-cache","extendsScheme":"","syntax":"caffeine-cache:cacheName","async":false, [...]
+,
+{"component":{"kind":"component","name":"caffeine-loadcache","title":"Caffeine LoadCache","description":"Perform caching operations using Caffeine Cache with an attached CacheLoader.","deprecated":false,"firstVersion":"2.20.0","label":"cache,clustering","javaType":"org.apache.camel.component.caffeine.load.CaffeineLoadCacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-caffeine","version":"4.18.0","scheme":"caffeine-loadcache","extendsScheme":"","synta [...]
+,
+{"component":{"kind":"component","name":"chatscript","title":"ChatScript","description":"Chat with a ChatScript Server.","deprecated":false,"firstVersion":"3.0.0","label":"ai,chat","javaType":"org.apache.camel.component.chatscript.ChatScriptComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-chatscript","version":"4.18.0","scheme":"chatscript","extendsScheme":"","syntax":"chatscript:host:port/botName","async":false,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"chunk","title":"Chunk","description":"Transform messages using Chunk templating engine.","deprecated":false,"firstVersion":"2.15.0","label":"transformation","javaType":"org.apache.camel.component.chunk.ChunkComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-chunk","version":"4.18.0","scheme":"chunk","extendsScheme":"","syntax":"chunk:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"l [...]
+,
+{"component":{"kind":"component","name":"class","title":"Class","description":"Invoke methods of Java beans specified by class name.","deprecated":false,"firstVersion":"2.4.0","label":"core,script","javaType":"org.apache.camel.component.beanclass.ClassComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-bean","version":"4.18.0","scheme":"class","extendsScheme":"","syntax":"class:beanName","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"l [...]
+,
+{"component":{"kind":"component","name":"clickup","title":"ClickUp","description":"Receives events from ClickUp","deprecated":false,"firstVersion":"4.9.0","label":"cloud","javaType":"org.apache.camel.component.clickup.ClickUpComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-clickup","version":"4.18.0","scheme":"clickup","extendsScheme":"","syntax":"clickup:workspaceId","async":false,"api":false,"consumerOnly":true,"producerOnly":false,"lenientProperties [...]
+,
+{"component":{"kind":"component","name":"cm-sms","title":"CM SMS Gateway","description":"Send SMS messages via CM SMS Gateway.","deprecated":false,"firstVersion":"2.18.0","label":"mobile","javaType":"org.apache.camel.component.cm.CMComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-cm-sms","version":"4.18.0","scheme":"cm-sms","extendsScheme":"","syntax":"cm-sms:host","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":fa [...]
+,
+{"component":{"kind":"component","name":"coap","title":"CoAP","description":"Send and receive messages to/from CoAP (Constrained Application Protocol) capable devices.","deprecated":false,"firstVersion":"2.16.0","label":"iot","javaType":"org.apache.camel.coap.CoAPComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-coap","version":"4.18.0","scheme":"coap","extendsScheme":"","alternativeSchemes":"coap,coaps,coap+tcp,coaps+tcp","syntax":"coap:uri","async":fal [...]
+,
+{"component":{"kind":"component","name":"coap+tcp","title":"CoAP","description":"Send and receive messages to/from CoAP (Constrained Application Protocol) capable devices.","deprecated":false,"firstVersion":"2.16.0","label":"iot","javaType":"org.apache.camel.coap.CoAPComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-coap","version":"4.18.0","scheme":"coap+tcp","extendsScheme":"","alternativeSchemes":"coap,coaps,coap+tcp,coaps+tcp","syntax":"coap+tcp:uri" [...]
+,
+{"component":{"kind":"component","name":"coaps","title":"CoAP (Secure)","description":"Send and receive messages to/from CoAP (Constrained Application Protocol) capable devices.","deprecated":false,"firstVersion":"2.16.0","label":"iot","javaType":"org.apache.camel.coap.CoAPComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-coap","version":"4.18.0","scheme":"coaps","extendsScheme":"","alternativeSchemes":"coap,coaps,coap+tcp,coaps+tcp","syntax":"coaps:uri" [...]
+,
+{"component":{"kind":"component","name":"coaps+tcp","title":"CoAP","description":"Send and receive messages to/from CoAP (Constrained Application Protocol) capable devices.","deprecated":false,"firstVersion":"2.16.0","label":"iot","javaType":"org.apache.camel.coap.CoAPComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-coap","version":"4.18.0","scheme":"coaps+tcp","extendsScheme":"","alternativeSchemes":"coap,coaps,coap+tcp,coaps+tcp","syntax":"coaps+tcp:u [...]
+,
+{"component":{"kind":"component","name":"cometd","title":"CometD","description":"Offers publish/subscribe, peer-to-peer (via a server), and RPC style messaging using the CometD/Bayeux protocol.","deprecated":false,"firstVersion":"2.0.0","label":"networking,messaging","javaType":"org.apache.camel.component.cometd.CometdComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-cometd","version":"4.18.0","scheme":"cometd","extendsScheme":"","alternativeSchemes":"co [...]
+,
+{"component":{"kind":"component","name":"cometds","title":"CometD (Secure)","description":"Offers publish/subscribe, peer-to-peer (via a server), and RPC style messaging using the CometD/Bayeux protocol.","deprecated":false,"firstVersion":"2.0.0","label":"networking,messaging","javaType":"org.apache.camel.component.cometd.CometdComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-cometd","version":"4.18.0","scheme":"cometds","extendsScheme":"","alternativeS [...]
+,
+{"component":{"kind":"component","name":"consul","title":"Consul","description":"Integrate with Consul service discovery and configuration store.","deprecated":false,"firstVersion":"2.18.0","label":"cloud,api","javaType":"org.apache.camel.component.consul.ConsulComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-consul","version":"4.18.0","scheme":"consul","extendsScheme":"","syntax":"consul:apiEndpoint","async":false,"api":false,"consumerOnly":false,"prod [...]
+,
+{"component":{"kind":"component","name":"controlbus","title":"Control Bus","description":"Manage and monitor Camel routes.","deprecated":false,"firstVersion":"2.11.0","label":"core,monitoring","javaType":"org.apache.camel.component.controlbus.ControlBusComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-controlbus","version":"4.18.0","scheme":"controlbus","extendsScheme":"","syntax":"controlbus:command:language","async":false,"api":false,"consumerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"couchbase","title":"Couchbase","description":"Query Couchbase Views with a poll strategy and/or perform various operations against Couchbase databases.","deprecated":false,"firstVersion":"2.19.0","label":"database","javaType":"org.apache.camel.component.couchbase.CouchbaseComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-couchbase","version":"4.18.0","scheme":"couchbase","extendsScheme":"","syntax":"couchbase:prot [...]
+,
+{"component":{"kind":"component","name":"couchdb","title":"CouchDB","description":"Consume changesets for inserts, updates and deletes in a CouchDB database, as well as get, save, update and delete documents from a CouchDB database.","deprecated":false,"firstVersion":"2.11.0","label":"database","javaType":"org.apache.camel.component.couchdb.CouchDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-couchdb","version":"4.18.0","scheme":"couchdb","extendsSch [...]
+,
+{"component":{"kind":"component","name":"cql","title":"Cassandra CQL","description":"Integrate with Cassandra 2.0 using the CQL3 API (not the Thrift API). Based on Cassandra Java Driver provided by DataStax.","deprecated":false,"firstVersion":"2.15.0","label":"database,bigdata","javaType":"org.apache.camel.component.cassandra.CassandraComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-cassandraql","version":"4.18.0","scheme":"cql","extendsScheme":"","synt [...]
+,
+{"component":{"kind":"component","name":"cron","title":"Cron","description":"A generic interface for triggering events at times specified through the Unix cron syntax.","deprecated":false,"firstVersion":"3.1.0","label":"scheduling","javaType":"org.apache.camel.component.cron.CronComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-cron","version":"4.18.0","scheme":"cron","extendsScheme":"","syntax":"cron:name","async":false,"api":false,"consumerOnly":true," [...]
+,
+{"component":{"kind":"component","name":"crypto","title":"Crypto (JCE)","description":"Sign and verify exchanges using the Signature Service of the Java Cryptographic Extension (JCE).","deprecated":false,"firstVersion":"2.3.0","label":"security,transformation","javaType":"org.apache.camel.component.crypto.DigitalSignatureComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-crypto","version":"4.18.0","scheme":"crypto","extendsScheme":"","syntax":"crypto:cryp [...]
+,
+{"component":{"kind":"component","name":"cxf","title":"CXF","description":"Expose SOAP WebServices using Apache CXF or connect to external WebServices using CXF WS client.","deprecated":false,"firstVersion":"1.0.0","label":"http,webservice","javaType":"org.apache.camel.component.cxf.jaxws.CxfComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-cxf-soap","version":"4.18.0","scheme":"cxf","extendsScheme":"","syntax":"cxf:beanId: [...]
+,
+{"component":{"kind":"component","name":"cxfrs","title":"CXF-RS","description":"Expose JAX-RS REST services using Apache CXF or connect to external REST services using CXF REST client.","deprecated":false,"firstVersion":"2.0.0","label":"rest","javaType":"org.apache.camel.component.cxf.jaxrs.CxfRsComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-cxf-rest","version":"4.18.0","scheme":"cxfrs","extendsScheme":"","syntax":"cxfrs [...]
+,
+{"component":{"kind":"component","name":"cyberark-vault","title":"CyberArk Vault","description":"Retrieve secrets from CyberArk Conjur Vault.","deprecated":false,"firstVersion":"4.17.0","label":"cloud,security","javaType":"org.apache.camel.component.cyberark.vault.CyberArkVaultComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-cyberark-vault","version":"4.18.0","scheme":"cyberark-vault","extendsScheme":"","syntax":"cyberark-vault:label","async":false,"ap [...]
+,
+{"component":{"kind":"component","name":"dapr","title":"Dapr","description":"Dapr component which interfaces with Dapr Building Blocks.","deprecated":false,"firstVersion":"4.12.0","label":"cloud,saas","javaType":"org.apache.camel.component.dapr.DaprComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dapr","version":"4.18.0","scheme":"dapr","extendsScheme":"","syntax":"dapr:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"leni [...]
+,
+{"component":{"kind":"component","name":"dataformat","title":"Data Format","description":"Use a Camel Data Format as a regular Camel Component.","deprecated":false,"firstVersion":"2.12.0","label":"core,transformation","javaType":"org.apache.camel.component.dataformat.DataFormatComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dataformat","version":"4.18.0","scheme":"dataformat","extendsScheme":"","syntax":"dataformat:name:operation","async":false,"api":f [...]
+,
+{"component":{"kind":"component","name":"dataset","title":"Dataset","description":"Provide data for load and soak testing of your Camel application.","deprecated":false,"firstVersion":"1.3.0","label":"core,testing","javaType":"org.apache.camel.component.dataset.DataSetComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dataset","version":"4.18.0","scheme":"dataset","extendsScheme":"","syntax":"dataset:name","async":false,"api":false,"consumerOnly":false,"p [...]
+,
+{"component":{"kind":"component","name":"dataset-test","title":"DataSet Test","description":"Extends the mock component by pulling messages from another endpoint on startup to set the expected message bodies.","deprecated":false,"firstVersion":"1.3.0","label":"core,testing","javaType":"org.apache.camel.component.dataset.DataSetTestComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dataset","version":"4.18.0","scheme":"dataset-test","extendsScheme":"","syn [...]
+,
+{"component":{"kind":"component","name":"debezium-db2","title":"Debezium DB2 Connector","description":"Capture changes from a DB2 database.","deprecated":false,"firstVersion":"3.17.0","label":"database","javaType":"org.apache.camel.component.debezium.db2.DebeziumDb2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-db2","version":"4.18.0","scheme":"debezium-db2","extendsScheme":"","syntax":"debezium-db2:name","async":false,"api":false,"consumerOn [...]
+,
+{"component":{"kind":"component","name":"debezium-mongodb","title":"Debezium MongoDB Connector","description":"Capture changes from a MongoDB database.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.debezium.mongodb.DebeziumMongodbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-mongodb","version":"4.18.0","scheme":"debezium-mongodb","extendsScheme":"","syntax":"debezium-mongodb:name","async [...]
+,
+{"component":{"kind":"component","name":"debezium-mysql","title":"Debezium MySQL Connector","description":"Capture changes from a MySQL database.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.debezium.mysql.DebeziumMySqlComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-mysql","version":"4.18.0","scheme":"debezium-mysql","extendsScheme":"","syntax":"debezium-mysql:name","async":false,"api":fa [...]
+,
+{"component":{"kind":"component","name":"debezium-oracle","title":"Debezium Oracle Connector","description":"Capture changes from an Oracle database.","deprecated":false,"firstVersion":"3.17.0","label":"database","javaType":"org.apache.camel.component.debezium.oracle.DebeziumOracleComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-oracle","version":"4.18.0","scheme":"debezium-oracle","extendsScheme":"","syntax":"debezium-oracle:name","async":fals [...]
+,
+{"component":{"kind":"component","name":"debezium-postgres","title":"Debezium PostgresSQL Connector","description":"Capture changes from a PostgresSQL database.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.debezium.postgres.DebeziumPostgresComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-postgres","version":"4.18.0","scheme":"debezium-postgres","extendsScheme":"","syntax":"debezium-postgre [...]
+,
+{"component":{"kind":"component","name":"debezium-sqlserver","title":"Debezium SQL Server Connector","description":"Capture changes from an SQL Server database.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.debezium.sqlserver.DebeziumSqlserverComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-debezium-sqlserver","version":"4.18.0","scheme":"debezium-sqlserver","extendsScheme":"","syntax":"debezium-sql [...]
+,
+{"component":{"kind":"component","name":"dfdl","title":"DFDL","description":"Transforms fixed format data such as EDI message from/to XML using a Data Format Description Language (DFDL).","deprecated":false,"firstVersion":"4.11.0","label":"transformation","javaType":"org.apache.camel.component.dfdl.DfdlComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dfdl","version":"4.18.0","scheme":"dfdl","extendsScheme":"","syntax":"dfdl:schemaUri","async":false,"api [...]
+,
+{"component":{"kind":"component","name":"dhis2","title":"DHIS2","description":"Leverages the DHIS2 Java SDK to integrate Apache Camel with the DHIS2 Web API.","deprecated":false,"firstVersion":"4.0.0","label":"api","javaType":"org.apache.camel.component.dhis2.Dhis2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dhis2","version":"4.18.0","scheme":"dhis2","extendsScheme":"","syntax":"dhis2:apiName/methodName","async":false,"api":true,"apiSyntax":"apiName [...]
+,
+{"component":{"kind":"component","name":"digitalocean","title":"DigitalOcean","description":"Manage Droplets and resources within the DigitalOcean cloud.","deprecated":false,"firstVersion":"2.19.0","label":"cloud,management","javaType":"org.apache.camel.component.digitalocean.DigitalOceanComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-digitalocean","version":"4.18.0","scheme":"digitalocean","extendsScheme":"","syntax":"digitalocean:operation","async":f [...]
+,
+{"component":{"kind":"component","name":"direct","title":"Direct","description":"Call another endpoint from the same Camel Context synchronously.","deprecated":false,"firstVersion":"1.0.0","label":"core,messaging","javaType":"org.apache.camel.component.direct.DirectComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-direct","version":"4.18.0","scheme":"direct","extendsScheme":"","syntax":"direct:name","async":false,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"disruptor","title":"Disruptor","description":"Provides asynchronous SEDA behavior using LMAX Disruptor.","deprecated":false,"firstVersion":"2.12.0","label":"messaging","javaType":"org.apache.camel.component.disruptor.DisruptorComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-disruptor","version":"4.18.0","scheme":"disruptor","extendsScheme":"","alternativeSchemes":"disruptor,disruptor-vm","syntax":"disruptor:name" [...]
+,
+{"component":{"kind":"component","name":"disruptor-vm","title":"Disruptor VM","description":"Provides asynchronous SEDA behavior using LMAX Disruptor.","deprecated":false,"firstVersion":"2.12.0","label":"messaging","javaType":"org.apache.camel.component.disruptor.vm.DisruptorVmComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-disruptor","version":"4.18.0","scheme":"disruptor-vm","extendsScheme":"","alternativeSchemes":"disruptor,disruptor-vm","syntax":"d [...]
+,
+{"component":{"kind":"component","name":"djl","title":"Deep Java Library","description":"Infer Deep Learning models from message exchanges data using Deep Java Library (DJL).","deprecated":false,"firstVersion":"3.3.0","label":"ai","javaType":"org.apache.camel.component.djl.DJLComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-djl","version":"4.18.0","scheme":"djl","extendsScheme":"","syntax":"djl:application","async":false,"api":false,"consumerOnly":false [...]
+,
+{"component":{"kind":"component","name":"dns","title":"DNS","description":"Perform DNS queries using DNSJava.","deprecated":false,"firstVersion":"2.7.0","label":"networking","javaType":"org.apache.camel.component.dns.DnsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dns","version":"4.18.0","scheme":"dns","extendsScheme":"","syntax":"dns:dnsType","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":false,"browsable":fa [...]
+,
+{"component":{"kind":"component","name":"docker","title":"Docker","description":"Manage Docker containers.","deprecated":false,"firstVersion":"2.15.0","label":"cloud,container","javaType":"org.apache.camel.component.docker.DockerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-docker","version":"4.18.0","scheme":"docker","extendsScheme":"","syntax":"docker:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties" [...]
+,
+{"component":{"kind":"component","name":"docling","title":"Docling","description":"Process documents using Docling library for parsing and conversion.","deprecated":false,"firstVersion":"4.15.0","label":"transformation,ai","javaType":"org.apache.camel.component.docling.DoclingComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-docling","version":"4.18.0","scheme":"docling","extendsScheme":"","syntax":"docling:operationId","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"drill","title":"Drill","description":"Perform queries against an Apache Drill cluster.","deprecated":false,"firstVersion":"2.19.0","label":"database,bigdata","javaType":"org.apache.camel.component.drill.DrillComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-drill","version":"4.18.0","scheme":"drill","extendsScheme":"","syntax":"drill:host","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenient [...]
+,
+{"component":{"kind":"component","name":"dropbox","title":"Dropbox","description":"Upload, download and manage files, folders, groups, collaborations, etc on Dropbox.","deprecated":false,"firstVersion":"2.14.0","label":"cloud,file,api","javaType":"org.apache.camel.component.dropbox.DropboxComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dropbox","version":"4.18.0","scheme":"dropbox","extendsScheme":"","syntax":"dropbox:operation","async":false,"api":fal [...]
+,
+{"component":{"kind":"component","name":"dynamic-router","title":"Dynamic Router","description":"The Dynamic Router component routes exchanges to recipients, and the recipients (and their rules) may change at runtime.","deprecated":false,"firstVersion":"3.15.0","label":"messaging,core","javaType":"org.apache.camel.component.dynamicrouter.routing.DynamicRouterComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-dynamic-router","version":"4.18.0","scheme":"dy [...]
+,
+{"component":{"kind":"component","name":"dynamic-router-control","title":"Dynamic Router Control","description":"The Dynamic Router control endpoint for operations that allow routing participants to subscribe or unsubscribe to participate in dynamic message routing.","deprecated":false,"firstVersion":"4.4.0","label":"messaging","javaType":"org.apache.camel.component.dynamicrouter.control.DynamicRouterControlComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"cam [...]
+,
+{"component":{"kind":"component","name":"ehcache","title":"Ehcache","description":"Perform caching operations using Ehcache.","deprecated":false,"firstVersion":"2.18.0","label":"cache,clustering","javaType":"org.apache.camel.component.ehcache.EhcacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ehcache","version":"4.18.0","scheme":"ehcache","extendsScheme":"","syntax":"ehcache:cacheName","async":false,"api":false,"consumerOnly":false,"producerOnly":f [...]
+,
+{"component":{"kind":"component","name":"elasticsearch","title":"Elasticsearch","description":"Send requests to ElasticSearch via Java Client API.","deprecated":false,"firstVersion":"3.19.0","label":"search,monitoring","javaType":"org.apache.camel.component.es.ElasticsearchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-elasticsearch","version":"4.18.0","scheme":"elasticsearch","extendsScheme":"","syntax":"elasticsearch:clusterName","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"elasticsearch-rest-client","title":"Elasticsearch Low level Rest Client","description":"Perform queries and other operations on Elasticsearch or OpenSearch (uses low-level client).","deprecated":false,"firstVersion":"4.3.0","label":"search","javaType":"org.apache.camel.component.elasticsearch.rest.client.ElasticsearchRestClientComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-elasticsearch-rest-client","version":" [...]
+,
+{"component":{"kind":"component","name":"exec","title":"Exec","description":"Execute commands on the underlying operating system.","deprecated":false,"firstVersion":"2.3.0","label":"core","javaType":"org.apache.camel.component.exec.ExecComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-exec","version":"4.18.0","scheme":"exec","extendsScheme":"","syntax":"exec:executable","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties [...]
+,
+{"component":{"kind":"component","name":"fhir","title":"FHIR","description":"Exchange information in the healthcare domain using the FHIR (Fast Healthcare Interoperability Resources) standard.","deprecated":false,"firstVersion":"2.23.0","label":"api","javaType":"org.apache.camel.component.fhir.FhirComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-fhir","version":"4.18.0","scheme":"fhir","extendsScheme":"","syntax":"fhir:apiName/methodName","async":false, [...]
+,
+{"component":{"kind":"component","name":"file","title":"File","description":"Read and write files.","deprecated":false,"firstVersion":"1.0.0","label":"file,core","javaType":"org.apache.camel.component.file.FileComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-file","version":"4.18.0","scheme":"file","extendsScheme":"","syntax":"file:directoryName","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":false,"browsable":tr [...]
+,
+{"component":{"kind":"component","name":"file-watch","title":"File Watch","description":"Get notified about file events in a directory using java.nio.file.WatchService.","deprecated":false,"firstVersion":"3.0.0","label":"file","javaType":"org.apache.camel.component.file.watch.FileWatchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-file-watch","version":"4.18.0","scheme":"file-watch","extendsScheme":"","syntax":"file-watch:path","async":false,"api":fal [...]
+,
+{"component":{"kind":"component","name":"flatpack","title":"Flatpack","description":"Parse fixed width and delimited files using the FlatPack library.","deprecated":false,"firstVersion":"1.4.0","label":"transformation","javaType":"org.apache.camel.component.flatpack.FlatpackComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-flatpack","version":"4.18.0","scheme":"flatpack","extendsScheme":"","syntax":"flatpack:type:resourceUri","async":false,"api":false,"c [...]
+,
+{"component":{"kind":"component","name":"flink","title":"Flink","description":"Send DataSet jobs to an Apache Flink cluster.","deprecated":false,"firstVersion":"2.18.0","label":"transformation,bigdata","javaType":"org.apache.camel.component.flink.FlinkComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-flink","version":"4.18.0","scheme":"flink","extendsScheme":"","syntax":"flink:endpointType","async":false,"api":false,"consumerOnly":false,"producerOnly":tr [...]
+,
+{"component":{"kind":"component","name":"flowable","title":"Flowable","description":"Send and receive messages from the Flowable BPMN and CMMN engines.","deprecated":false,"firstVersion":"4.9.0","label":"workflow","javaType":"org.apache.camel.component.flowable.FlowableComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-flowable","version":"4.18.0","scheme":"flowable","extendsScheme":"","syntax":"flowable:channelKey","async":false,"api":false,"consumerOnly [...]
+,
+{"component":{"kind":"component","name":"fop","title":"FOP","description":"Render messages into PDF and other output formats supported by Apache FOP.","deprecated":false,"firstVersion":"2.10.0","label":"file,transformation","javaType":"org.apache.camel.component.fop.FopComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-fop","version":"4.18.0","scheme":"fop","extendsScheme":"","syntax":"fop:outputType","async":false,"api":false,"consumerOnly":false,"produc [...]
+,
+{"component":{"kind":"component","name":"freemarker","title":"Freemarker","description":"Transform messages using FreeMarker templates.","deprecated":false,"firstVersion":"2.10.0","label":"transformation","javaType":"org.apache.camel.component.freemarker.FreemarkerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-freemarker","version":"4.18.0","scheme":"freemarker","extendsScheme":"","syntax":"freemarker:resourceUri","async":false,"api":false,"consumerOn [...]
+,
+{"component":{"kind":"component","name":"ftp","title":"FTP","description":"Upload and download files to/from FTP servers.","deprecated":false,"firstVersion":"1.1.0","label":"file","javaType":"org.apache.camel.component.file.remote.FtpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ftp","version":"4.18.0","scheme":"ftp","extendsScheme":"file","syntax":"ftp:host:port/directoryName","alternativeSyntax":"ftp:username:password@host:port/directoryName","asyn [...]
+,
+{"component":{"kind":"component","name":"ftps","title":"FTPS","description":"Upload and download files to/from FTP servers supporting the FTPS protocol.","deprecated":false,"firstVersion":"2.2.0","label":"file","javaType":"org.apache.camel.component.file.remote.FtpsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ftp","version":"4.18.0","scheme":"ftps","extendsScheme":"file","syntax":"ftps:host:port/directoryName","alternativeSyntax":"ftps:username:pass [...]
+,
+{"component":{"kind":"component","name":"geocoder","title":"Geocoder","description":"Find geocodes (latitude and longitude) for a given address or the other way round.","deprecated":false,"firstVersion":"2.12.0","label":"api,search","javaType":"org.apache.camel.component.geocoder.GeoCoderComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-geocoder","version":"4.18.0","scheme":"geocoder","extendsScheme":"","syntax":"geocoder:address:latlng","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"git","title":"Git","description":"Perform operations on git repositories.","deprecated":false,"firstVersion":"2.16.0","label":"file","javaType":"org.apache.camel.component.git.GitComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-git","version":"4.18.0","scheme":"git","extendsScheme":"","syntax":"git:localPath","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":false,"browsable" [...]
+,
+{"component":{"kind":"component","name":"github2","title":"GitHub2","description":"Interact with the GitHub API.","deprecated":false,"firstVersion":"4.18.0","label":"file,cloud,api","javaType":"org.apache.camel.component.github2.GitHub2Component","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-github2","version":"4.18.0","scheme":"github2","extendsScheme":"","syntax":"github2:type/branchName","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"l [...]
+,
+{"component":{"kind":"component","name":"google-bigquery","title":"Google BigQuery","description":"Google BigQuery data warehouse for analytics.","deprecated":false,"firstVersion":"2.20.0","label":"cloud,bigdata","javaType":"org.apache.camel.component.google.bigquery.GoogleBigQueryComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-bigquery","version":"4.18.0","scheme":"google-bigquery","extendsScheme":"","syntax":"google-bigquery:projectId:datasetI [...]
+,
+{"component":{"kind":"component","name":"google-bigquery-sql","title":"Google BigQuery Standard SQL","description":"Access Google Cloud BigQuery service using SQL queries.","deprecated":false,"firstVersion":"2.23.0","label":"cloud,messaging","javaType":"org.apache.camel.component.google.bigquery.sql.GoogleBigQuerySQLComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-bigquery","version":"4.18.0","scheme":"google-bigquery-sql","extendsScheme":"","syn [...]
+,
+{"component":{"kind":"component","name":"google-calendar","title":"Google Calendar","description":"Perform various operations on a Google Calendar.","deprecated":false,"firstVersion":"2.15.0","label":"api,cloud","javaType":"org.apache.camel.component.google.calendar.GoogleCalendarComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-calendar","version":"4.18.0","scheme":"google-calendar","extendsScheme":"","syntax":"google-calendar:apiName/methodName" [...]
+,
+{"component":{"kind":"component","name":"google-calendar-stream","title":"Google Calendar Stream","description":"Poll for changes in a Google Calendar.","deprecated":false,"firstVersion":"2.23.0","label":"cloud","javaType":"org.apache.camel.component.google.calendar.stream.GoogleCalendarStreamComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-calendar","version":"4.18.0","scheme":"google-calendar-stream","extendsScheme":"","syntax":"google-calendar [...]
+,
+{"component":{"kind":"component","name":"google-drive","title":"Google Drive","description":"Manage files in Google Drive.","deprecated":false,"firstVersion":"2.14.0","label":"file,cloud,api","javaType":"org.apache.camel.component.google.drive.GoogleDriveComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-drive","version":"4.18.0","scheme":"google-drive","extendsScheme":"","syntax":"google-drive:apiName/methodName","async":false,"api":true,"apiSynta [...]
+,
+{"component":{"kind":"component","name":"google-functions","title":"Google Cloud Functions","description":"Manage and invoke Google Cloud Functions","deprecated":false,"firstVersion":"3.9.0","label":"cloud","javaType":"org.apache.camel.component.google.functions.GoogleCloudFunctionsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-functions","version":"4.18.0","scheme":"google-functions","extendsScheme":"","syntax":"google-functions:functionName", [...]
+,
+{"component":{"kind":"component","name":"google-mail","title":"Google Mail","description":"Manage messages in Google Mail.","deprecated":false,"firstVersion":"2.15.0","label":"cloud,api,mail","javaType":"org.apache.camel.component.google.mail.GoogleMailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-mail","version":"4.18.0","scheme":"google-mail","extendsScheme":"","syntax":"google-mail:apiName/methodName","async":false,"api":true,"apiSyntax":"a [...]
+,
+{"component":{"kind":"component","name":"google-mail-stream","title":"Google Mail Stream","description":"Poll for incoming messages in Google Mail.","deprecated":false,"firstVersion":"2.22.0","label":"cloud,mail","javaType":"org.apache.camel.component.google.mail.stream.GoogleMailStreamComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-mail","version":"4.18.0","scheme":"google-mail-stream","extendsScheme":"","syntax":"google-mail-stream:index","asy [...]
+,
+{"component":{"kind":"component","name":"google-pubsub","title":"Google Pubsub","description":"Send and receive messages to/from Google Cloud Platform PubSub Service.","deprecated":false,"firstVersion":"2.19.0","label":"cloud,messaging","javaType":"org.apache.camel.component.google.pubsub.GooglePubsubComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-pubsub","version":"4.18.0","scheme":"google-pubsub","extendsScheme":"","syntax":"google-pubsub:proj [...]
+,
+{"component":{"kind":"component","name":"google-secret-manager","title":"Google Secret Manager","description":"Manage Google Secret Manager Secrets","deprecated":false,"firstVersion":"3.16.0","label":"cloud","javaType":"org.apache.camel.component.google.secret.manager.GoogleSecretManagerComponent","supportLevel":"Stable","metadata":{"vault":"google-secret-manager"},"groupId":"org.apache.camel","artifactId":"camel-google-secret-manager","version":"4.18.0","scheme":"google-secret-manager", [...]
+,
+{"component":{"kind":"component","name":"google-sheets","title":"Google Sheets","description":"Manage spreadsheets in Google Sheets.","deprecated":false,"firstVersion":"2.23.0","label":"cloud,document","javaType":"org.apache.camel.component.google.sheets.GoogleSheetsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-sheets","version":"4.18.0","scheme":"google-sheets","extendsScheme":"","syntax":"google-sheets:apiName/methodName","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"google-sheets-stream","title":"Google Sheets Stream","description":"Poll for changes in Google Sheets.","deprecated":false,"firstVersion":"2.23.0","label":"cloud,document","javaType":"org.apache.camel.component.google.sheets.stream.GoogleSheetsStreamComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-sheets","version":"4.18.0","scheme":"google-sheets-stream","extendsScheme":"","syntax":"google-sheets-stream:s [...]
+,
+{"component":{"kind":"component","name":"google-storage","title":"Google Storage","description":"Store and retrieve objects from Google Cloud Storage Service using the google-cloud-storage library.","deprecated":false,"firstVersion":"3.9.0","label":"cloud","javaType":"org.apache.camel.component.google.storage.GoogleCloudStorageComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-google-storage","version":"4.18.0","scheme":"google-storage","extendsScheme":"" [...]
+,
+{"component":{"kind":"component","name":"google-vertexai","title":"Google Vertex AI","description":"Interact with Google Cloud Vertex AI generative models.","deprecated":false,"firstVersion":"4.17.0","label":"ai,cloud","javaType":"org.apache.camel.component.google.vertexai.GoogleVertexAIComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-google-vertexai","version":"4.18.0","scheme":"google-vertexai","extendsScheme":"","syntax":"google-vertexai:projectId:l [...]
+,
+{"component":{"kind":"component","name":"graphql","title":"GraphQL","description":"Send GraphQL queries and mutations to external systems.","deprecated":false,"firstVersion":"3.0.0","label":"api","javaType":"org.apache.camel.component.graphql.GraphqlComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-graphql","version":"4.18.0","scheme":"graphql","extendsScheme":"","syntax":"graphql:httpUri","async":false,"api":false,"consumerOnly":false,"producerOnly":tru [...]
+,
+{"component":{"kind":"component","name":"grpc","title":"gRPC","description":"Expose gRPC endpoints and access external gRPC endpoints.","deprecated":false,"firstVersion":"2.19.0","label":"rpc","javaType":"org.apache.camel.component.grpc.GrpcComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-grpc","version":"4.18.0","scheme":"grpc","extendsScheme":"","syntax":"grpc:host:port/service","async":false,"api":false,"consumerOnly":f [...]
+,
+{"component":{"kind":"component","name":"hashicorp-vault","title":"Hashicorp Vault","description":"Manage secrets in Hashicorp Vault Service","deprecated":false,"firstVersion":"3.18.0","label":"cloud,cloud","javaType":"org.apache.camel.component.hashicorp.vault.HashicorpVaultComponent","supportLevel":"Stable","metadata":{"vault":"hashicorp-vault"},"groupId":"org.apache.camel","artifactId":"camel-hashicorp-vault","version":"4.18.0","scheme":"hashicorp-vault","extendsScheme":"","syntax":"h [...]
+,
+{"component":{"kind":"component","name":"hazelcast-atomicvalue","title":"Hazelcast Atomic Number","description":"Increment, decrement, set, etc. Hazelcast atomic number (a grid wide number).","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.atomicnumber.HazelcastAtomicnumberComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-atomicvalue"," [...]
+,
+{"component":{"kind":"component","name":"hazelcast-instance","title":"Hazelcast Instance","description":"Consume join/leave events of a cache instance in a Hazelcast cluster.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.instance.HazelcastInstanceComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-instance","extendsScheme":"","syntax": [...]
+,
+{"component":{"kind":"component","name":"hazelcast-list","title":"Hazelcast List","description":"Perform operations on Hazelcast distributed list.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.list.HazelcastListComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-list","extendsScheme":"","syntax":"hazelcast-list:cacheName","async":false [...]
+,
+{"component":{"kind":"component","name":"hazelcast-map","title":"Hazelcast Map","description":"Perform operations on Hazelcast distributed map.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.map.HazelcastMapComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-map","extendsScheme":"","syntax":"hazelcast-map:cacheName","async":false,"api": [...]
+,
+{"component":{"kind":"component","name":"hazelcast-multimap","title":"Hazelcast Multimap","description":"Perform operations on Hazelcast distributed multimap.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.multimap.HazelcastMultimapComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-multimap","extendsScheme":"","syntax":"hazelcast-multi [...]
+,
+{"component":{"kind":"component","name":"hazelcast-queue","title":"Hazelcast Queue","description":"Perform operations on Hazelcast distributed queue.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering,messaging","javaType":"org.apache.camel.component.hazelcast.queue.HazelcastQueueComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-queue","extendsScheme":"","syntax":"hazelcast-queue:cacheNa [...]
+,
+{"component":{"kind":"component","name":"hazelcast-replicatedmap","title":"Hazelcast Replicated Map","description":"Perform operations on Hazelcast replicated map.","deprecated":false,"firstVersion":"2.16.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.replicatedmap.HazelcastReplicatedmapComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-replicatedmap","extendsScheme":"","syn [...]
+,
+{"component":{"kind":"component","name":"hazelcast-ringbuffer","title":"Hazelcast Ringbuffer","description":"Perform operations on Hazelcast distributed ringbuffer.","deprecated":false,"firstVersion":"2.16.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.ringbuffer.HazelcastRingbufferComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-ringbuffer","extendsScheme":"","syntax":"ha [...]
+,
+{"component":{"kind":"component","name":"hazelcast-seda","title":"Hazelcast SEDA","description":"Asynchronously send/receive Exchanges between Camel routes running on potentially distinct JVMs/hosts backed by Hazelcast BlockingQueue.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.seda.HazelcastSedaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme [...]
+,
+{"component":{"kind":"component","name":"hazelcast-set","title":"Hazelcast Set","description":"Perform operations on Hazelcast distributed set.","deprecated":false,"firstVersion":"2.7.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.set.HazelcastSetComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-set","extendsScheme":"","syntax":"hazelcast-set:cacheName","async":false,"api": [...]
+,
+{"component":{"kind":"component","name":"hazelcast-topic","title":"Hazelcast Topic","description":"Send and receive messages to/from Hazelcast distributed topic.","deprecated":false,"firstVersion":"2.15.0","label":"cache,clustering","javaType":"org.apache.camel.component.hazelcast.topic.HazelcastTopicComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-hazelcast","version":"4.18.0","scheme":"hazelcast-topic","extendsScheme":"","syntax":"hazelcast-topic:cach [...]
+,
+{"component":{"kind":"component","name":"http","title":"HTTP","description":"Send requests to external HTTP servers using Apache HTTP Client 5.x.","deprecated":false,"firstVersion":"2.3.0","label":"http","javaType":"org.apache.camel.component.http.HttpComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-http","version":"4.18.0","scheme":"http","extendsScheme":"","alternativeSchemes":"http,https","syntax":"http://httpUri","asyn [...]
+,
+{"component":{"kind":"component","name":"https","title":"HTTPS (Secure)","description":"Send requests to external HTTP servers using Apache HTTP Client 5.x.","deprecated":false,"firstVersion":"2.3.0","label":"http","javaType":"org.apache.camel.component.http.HttpComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-http","version":"4.18.0","scheme":"https","extendsScheme":"","alternativeSchemes":"http,https","syntax":"https://h [...]
+,
+{"component":{"kind":"component","name":"hwcloud-dms","title":"Huawei Distributed Message Service (DMS)","description":"To integrate with a fully managed, high-performance message queuing service on Huawei Cloud","deprecated":false,"firstVersion":"3.12.0","label":"cloud","javaType":"org.apache.camel.component.huaweicloud.dms.DMSComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-dms","version":"4.18.0","scheme":"hwcloud-dms","extendsScheme":"", [...]
+,
+{"component":{"kind":"component","name":"hwcloud-frs","title":"Huawei Cloud Face Recognition Service (FRS)","description":"Face Recognition Service (FRS) is an intelligent service that uses computers to process, analyze, and understand facial images based on human facial features.","deprecated":false,"firstVersion":"3.15.0","label":"cloud,messaging","javaType":"org.apache.camel.component.huaweicloud.frs.FaceRecognitionComponent","supportLevel":"Stable","groupId":"org.apache.camel","artif [...]
+,
+{"component":{"kind":"component","name":"hwcloud-functiongraph","title":"Huawei FunctionGraph","description":"To call serverless functions on Huawei Cloud","deprecated":false,"firstVersion":"3.11.0","label":"cloud,serverless","javaType":"org.apache.camel.FunctionGraphComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-functiongraph","version":"4.18.0","scheme":"hwcloud-functiongraph","extendsScheme":"","syntax":"hwcloud-functiongraph:operation" [...]
+,
+{"component":{"kind":"component","name":"hwcloud-iam","title":"Huawei Identity and Access Management (IAM)","description":"To securely manage users on Huawei Cloud","deprecated":false,"firstVersion":"3.11.0","label":"cloud","javaType":"org.apache.camel.component.huaweicloud.iam.IAMComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-iam","version":"4.18.0","scheme":"hwcloud-iam","extendsScheme":"","syntax":"hwcloud-iam:operation","async":false," [...]
+,
+{"component":{"kind":"component","name":"hwcloud-imagerecognition","title":"Huawei Cloud Image Recognition","description":"To identify objects, scenes, and concepts in images on Huawei Cloud","deprecated":false,"firstVersion":"3.12.0","label":"cloud,messaging","javaType":"org.apache.camel.component.huaweicloud.image.ImageRecognitionComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-imagerecognition","version":"4.18.0","scheme":"hwcloud-imagere [...]
+,
+{"component":{"kind":"component","name":"hwcloud-obs","title":"Huawei Object Storage Service (OBS)","description":"To provide stable, secure, efficient, and easy-to-use cloud storage service on Huawei Cloud","deprecated":false,"firstVersion":"3.12.0","label":"cloud","javaType":"org.apache.camel.component.huaweicloud.obs.OBSComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-obs","version":"4.18.0","scheme":"hwcloud-obs","extendsScheme":"","synt [...]
+,
+{"component":{"kind":"component","name":"hwcloud-smn","title":"Huawei Simple Message Notification (SMN)","description":"To broadcast messages and connect cloud services through notifications on Huawei Cloud","deprecated":false,"firstVersion":"3.8.0","label":"cloud,messaging","javaType":"org.apache.camel.component.huaweicloud.smn.SimpleNotificationComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-huaweicloud-smn","version":"4.18.0","scheme":"hwcloud-smn", [...]
+,
+{"component":{"kind":"component","name":"ibm-cos","title":"IBM Cloud Object Storage","description":"Store and retrieve objects from IBM Cloud Object Storage.","deprecated":false,"firstVersion":"4.16.0","label":"cloud,file","javaType":"org.apache.camel.component.ibm.cos.IBMCOSComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ibm-cos","version":"4.18.0","scheme":"ibm-cos","extendsScheme":"","syntax":"ibm-cos:bucketName","async":false,"api":false,"consumerO [...]
+,
+{"component":{"kind":"component","name":"ibm-secrets-manager","title":"IBM Secrets Manager","description":"Manage secrets in IBM Secrets Manager Service","deprecated":false,"firstVersion":"4.11.0","label":"cloud,cloud","javaType":"org.apache.camel.component.ibm.secrets.manager.IBMSecretsManagerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ibm-secrets-manager","version":"4.18.0","scheme":"ibm-secrets-manager","extendsScheme":"","syntax":"ibm-secrets-m [...]
+,
+{"component":{"kind":"component","name":"ibm-watson-discovery","title":"IBM Watson Discovery","description":"Perform document understanding and search using IBM Watson Discovery","deprecated":false,"firstVersion":"4.16.0","label":"ai,cloud","javaType":"org.apache.camel.component.ibm.watson.discovery.WatsonDiscoveryComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ibm-watson-discovery","version":"4.18.0","scheme":"ibm-watson-discovery","extendsScheme":"", [...]
+,
+{"component":{"kind":"component","name":"ibm-watson-language","title":"IBM Watson Language","description":"Perform natural language processing using IBM Watson Natural Language Understanding","deprecated":false,"firstVersion":"4.16.0","label":"ai,cloud","javaType":"org.apache.camel.component.ibm.watson.language.WatsonLanguageComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ibm-watson-language","version":"4.18.0","scheme":"ibm-watson-language","extendsSc [...]
+,
+{"component":{"kind":"component","name":"ibm-watson-speech-to-text","title":"IBM Watson Speech to Text","description":"Convert speech audio to text using IBM Watson Speech to Text","deprecated":false,"firstVersion":"4.17.0","label":"ai,cloud","javaType":"org.apache.camel.component.ibm.watson.stt.WatsonSpeechToTextComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-ibm-watson-speech-to-text","version":"4.18.0","scheme":"ibm-watson-speech-to-text","extendsS [...]
+,
+{"component":{"kind":"component","name":"ibm-watson-text-to-speech","title":"IBM Watson Text to Speech","description":"Convert text to natural-sounding speech using IBM Watson Text to Speech","deprecated":false,"firstVersion":"4.17.0","label":"ai,cloud","javaType":"org.apache.camel.component.ibm.watson.tts.WatsonTextToSpeechComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-ibm-watson-text-to-speech","version":"4.18.0","scheme":"ibm-watson-text-to-speech [...]
+,
+{"component":{"kind":"component","name":"ibm-watsonx-ai","title":"IBM watsonx.ai","description":"Interact with IBM watsonx.ai foundation models for text generation, chat, embeddings, and more.","deprecated":false,"firstVersion":"4.18.0","label":"ai,cloud","javaType":"org.apache.camel.component.ibm.watsonx.ai.WatsonxAiComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-ibm-watsonx-ai","version":"4.18.0","scheme":"ibm-watsonx-ai","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"iec60870-client","title":"IEC 60870 Client","description":"IEC 60870 supervisory control and data acquisition (SCADA) client using NeoSCADA implementation.","deprecated":false,"firstVersion":"2.20.0","label":"iot","javaType":"org.apache.camel.component.iec60870.client.ClientComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-iec60870","version":"4.18.0","scheme":"iec60870-client","extendsScheme":"","syntax":"iec6087 [...]
+,
+{"component":{"kind":"component","name":"iec60870-server","title":"IEC 60870 Server","description":"IEC 60870 supervisory control and data acquisition (SCADA) server using NeoSCADA implementation.","deprecated":false,"firstVersion":"2.20.0","label":"iot","javaType":"org.apache.camel.component.iec60870.server.ServerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-iec60870","version":"4.18.0","scheme":"iec60870-server","extendsScheme":"","syntax":"iec6087 [...]
+,
+{"component":{"kind":"component","name":"iggy","title":"Iggy","description":"Send and receive message to Apache Iggy streaming platform.","deprecated":false,"firstVersion":"4.17.0","label":"messaging","javaType":"org.apache.camel.component.iggy.IggyComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-iggy","version":"4.18.0","scheme":"iggy","extendsScheme":"","syntax":"iggy:topicName","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"len [...]
+,
+{"component":{"kind":"component","name":"ignite-cache","title":"Ignite Cache","description":"Perform cache operations on an Ignite cache or consume changes from a continuous query.","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering","javaType":"org.apache.camel.component.ignite.cache.IgniteCacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-cache","extendsScheme":"","syntax":"ignite-cache: [...]
+,
+{"component":{"kind":"component","name":"ignite-compute","title":"Ignite Compute","description":"Run compute operations on an Ignite cluster.","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering","javaType":"org.apache.camel.component.ignite.compute.IgniteComputeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-compute","extendsScheme":"","syntax":"ignite-compute:endpointId","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"ignite-events","title":"Ignite Events","description":"Receive events from an Ignite cluster by creating a local event listener.","deprecated":false,"firstVersion":"2.17.0","label":"messaging,cache,clustering","javaType":"org.apache.camel.component.ignite.events.IgniteEventsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-events","extendsScheme":"","syntax":"ignite-event [...]
+,
+{"component":{"kind":"component","name":"ignite-idgen","title":"Ignite ID Generator","description":"Interact with Ignite Atomic Sequences and ID Generators .","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering","javaType":"org.apache.camel.component.ignite.idgen.IgniteIdGenComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-idgen","extendsScheme":"","syntax":"ignite-idgen:name","async":false,"ap [...]
+,
+{"component":{"kind":"component","name":"ignite-messaging","title":"Ignite Messaging","description":"Send and receive messages from an Ignite topic.","deprecated":false,"firstVersion":"2.17.0","label":"messaging","javaType":"org.apache.camel.component.ignite.messaging.IgniteMessagingComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-messaging","extendsScheme":"","syntax":"ignite-messaging:topic","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"ignite-queue","title":"Ignite Queues","description":"Interact with Ignite Queue data structures.","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering,messaging","javaType":"org.apache.camel.component.ignite.queue.IgniteQueueComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-queue","extendsScheme":"","syntax":"ignite-queue:name","async":false,"api":false," [...]
+,
+{"component":{"kind":"component","name":"ignite-set","title":"Ignite Sets","description":"Interact with Ignite Set data structures.","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering","javaType":"org.apache.camel.component.ignite.set.IgniteSetComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ignite","version":"4.18.0","scheme":"ignite-set","extendsScheme":"","syntax":"ignite-set:name","async":false,"api":false,"consumerOnly":false,"pro [...]
+,
+{"component":{"kind":"component","name":"imap","title":"IMAP","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"imap","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"imap:host:port","alternativeSyntax":"i [...]
+,
+{"component":{"kind":"component","name":"imaps","title":"IMAPS (Secure)","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"imaps","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"imaps:host:port","alternat [...]
+,
+{"component":{"kind":"component","name":"infinispan","title":"Infinispan","description":"Read and write from/to Infinispan distributed key/value store and data grid.","deprecated":false,"firstVersion":"2.13.0","label":"cache,clustering","javaType":"org.apache.camel.component.infinispan.remote.InfinispanRemoteComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-infinispan","version":"4.18.0","scheme":"infinispan","extendsScheme":"","syntax":"infinispan:cache [...]
+,
+{"component":{"kind":"component","name":"infinispan-embedded","title":"Infinispan Embedded","description":"Read and write from/to Infinispan distributed key/value store and data grid.","deprecated":false,"firstVersion":"2.13.0","label":"cache,clustering","javaType":"org.apache.camel.component.infinispan.embedded.InfinispanEmbeddedComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-infinispan-embedded","version":"4.18.0","scheme":"infinispan-embedded","exte [...]
+,
+{"component":{"kind":"component","name":"influxdb","title":"InfluxDB","description":"Interact with InfluxDB v1, a time series database.","deprecated":false,"firstVersion":"2.18.0","label":"database","javaType":"org.apache.camel.component.influxdb.InfluxDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-influxdb","version":"4.18.0","scheme":"influxdb","extendsScheme":"","syntax":"influxdb:connectionBean","async":false,"api":false,"consumerOnly":false,"pr [...]
+,
+{"component":{"kind":"component","name":"influxdb2","title":"InfluxDB2","description":"Interact with InfluxDB v2, a time series database.","deprecated":false,"firstVersion":"3.20.0","label":"database","javaType":"org.apache.camel.component.influxdb2.InfluxDb2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-influxdb2","version":"4.18.0","scheme":"influxdb2","extendsScheme":"","syntax":"influxdb2:connectionBean","async":false,"api":false,"consumerOnly":fa [...]
+,
+{"component":{"kind":"component","name":"irc","title":"IRC","description":"Send and receive messages to/from and IRC chat.","deprecated":false,"firstVersion":"1.1.0","label":"chat","javaType":"org.apache.camel.component.irc.IrcComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-irc","version":"4.18.0","scheme":"irc","extendsScheme":"","syntax":"irc:hostname:port","alternativeSyntax":"irc:username:password@hostname:port","async":false,"api":false,"consumerO [...]
+,
+{"component":{"kind":"component","name":"ironmq","title":"IronMQ","description":"Send and receive messages to/from IronMQ an elastic and durable hosted message queue as a service.","deprecated":false,"firstVersion":"2.17.0","label":"cloud,messaging","javaType":"org.apache.camel.component.ironmq.IronMQComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ironmq","version":"4.18.0","scheme":"ironmq","extendsScheme":"","syntax":"ironmq:queueName","async":false, [...]
+,
+{"component":{"kind":"component","name":"jcache","title":"JCache","description":"Perform caching operations against JSR107/JCache.","deprecated":false,"firstVersion":"2.17.0","label":"cache,clustering","javaType":"org.apache.camel.component.jcache.JCacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jcache","version":"4.18.0","scheme":"jcache","extendsScheme":"","syntax":"jcache:cacheName","async":false,"api":false,"consumerOnly":false,"producerOnly": [...]
+,
+{"component":{"kind":"component","name":"jcr","title":"JCR","description":"Read and write nodes to/from a JCR compliant content repository.","deprecated":false,"firstVersion":"1.3.0","label":"database,cms","javaType":"org.apache.camel.component.jcr.JcrComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jcr","version":"4.18.0","scheme":"jcr","extendsScheme":"","syntax":"jcr:host/base","alternativeSyntax":"jcr:username:password@host/base","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"jdbc","title":"JDBC","description":"Access databases through SQL and JDBC.","deprecated":false,"firstVersion":"1.2.0","label":"database","javaType":"org.apache.camel.component.jdbc.JdbcComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jdbc","version":"4.18.0","scheme":"jdbc","extendsScheme":"","syntax":"jdbc:dataSourceName","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":fals [...]
+,
+{"component":{"kind":"component","name":"jetty","title":"Jetty","description":"Expose HTTP endpoints using Jetty 12.","deprecated":false,"firstVersion":"1.2.0","label":"http","javaType":"org.apache.camel.component.jetty12.JettyHttpComponent12","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-jetty","version":"4.18.0","scheme":"jetty","extendsScheme":"http","syntax":"jetty:httpUri","async":true,"api":false,"consumerOnly":true,"produce [...]
+,
+{"component":{"kind":"component","name":"jgroups","title":"JGroups","description":"Exchange messages with JGroups clusters.","deprecated":false,"firstVersion":"2.13.0","label":"clustering,messaging","javaType":"org.apache.camel.component.jgroups.JGroupsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jgroups","version":"4.18.0","scheme":"jgroups","extendsScheme":"","syntax":"jgroups:clusterName","async":false,"api":false,"consumerOnly":false,"producerOn [...]
+,
+{"component":{"kind":"component","name":"jgroups-raft","title":"JGroups raft","description":"Exchange messages with JGroups-raft clusters.","deprecated":false,"firstVersion":"2.24.0","label":"clustering,messaging","javaType":"org.apache.camel.component.jgroups.raft.JGroupsRaftComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jgroups-raft","version":"4.18.0","scheme":"jgroups-raft","extendsScheme":"","syntax":"jgroups-raft:clusterName","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"jira","title":"Jira","description":"Interact with JIRA issue tracker.","deprecated":false,"firstVersion":"3.0","label":"document","javaType":"org.apache.camel.component.jira.JiraComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jira","version":"4.18.0","scheme":"jira","extendsScheme":"","syntax":"jira:type","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":false,"browsable":fa [...]
+,
+{"component":{"kind":"component","name":"jms","title":"JMS","description":"Send and receive messages to/from JMS message brokers.","deprecated":false,"firstVersion":"1.0.0","label":"messaging","javaType":"org.apache.camel.component.jms.JmsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jms","version":"4.18.0","scheme":"jms","extendsScheme":"","syntax":"jms:destinationType:destinationName","async":true,"api":false,"consumerOnly":false,"producerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"jmx","title":"JMX","description":"Receive JMX notifications.","deprecated":false,"firstVersion":"2.6.0","label":"monitoring","javaType":"org.apache.camel.component.jmx.JMXComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jmx","version":"4.18.0","scheme":"jmx","extendsScheme":"","syntax":"jmx:serverURL","async":false,"api":false,"consumerOnly":true,"producerOnly":false,"lenientProperties":false,"browsable":false,"r [...]
+,
+{"component":{"kind":"component","name":"jolt","title":"JOLT","description":"JSON to JSON transformation using JOLT.","deprecated":false,"firstVersion":"2.16.0","label":"transformation","javaType":"org.apache.camel.component.jolt.JoltComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jolt","version":"4.18.0","scheme":"jolt","extendsScheme":"","syntax":"jolt:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties" [...]
+,
+{"component":{"kind":"component","name":"jooq","title":"JOOQ","description":"Store and retrieve Java objects from an SQL database using JOOQ.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.jooq.JooqComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jooq","version":"4.18.0","scheme":"jooq","extendsScheme":"","syntax":"jooq:entityType","async":false,"api":false,"consumerOnly":false,"producerOnly":false," [...]
+,
+{"component":{"kind":"component","name":"jpa","title":"JPA","description":"Store and retrieve Java objects from databases using Java Persistence API (JPA).","deprecated":false,"firstVersion":"1.0.0","label":"database","javaType":"org.apache.camel.component.jpa.JpaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jpa","version":"4.18.0","scheme":"jpa","extendsScheme":"","syntax":"jpa:entityType","async":false,"api":false,"consumerOnly":false,"producerOnly [...]
+,
+{"component":{"kind":"component","name":"jslt","title":"JSLT","description":"Query or transform JSON payloads using JSLT.","deprecated":false,"firstVersion":"3.1.0","label":"transformation","javaType":"org.apache.camel.component.jslt.JsltComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jslt","version":"4.18.0","scheme":"jslt","extendsScheme":"","syntax":"jslt:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientPropert [...]
+,
+{"component":{"kind":"component","name":"json-patch","title":"JsonPatch","description":"Transforms JSON using JSON patch (RFC 6902).","deprecated":false,"firstVersion":"3.12.0","label":"transformation","javaType":"org.apache.camel.component.jsonpatch.JsonPatchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-json-patch","version":"4.18.0","scheme":"json-patch","extendsScheme":"","syntax":"json-patch:resourceUri","async":false,"api":false,"consumerOnly":f [...]
+,
+{"component":{"kind":"component","name":"json-validator","title":"JSON Schema Validator","description":"Validate JSON payloads using NetworkNT JSON Schema.","deprecated":false,"firstVersion":"2.20.0","label":"validation","javaType":"org.apache.camel.component.jsonvalidator.JsonValidatorComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-json-validator","version":"4.18.0","scheme":"json-validator","extendsScheme":"","syntax":"json-validator:resourceUri","as [...]
+,
+{"component":{"kind":"component","name":"jsonata","title":"JSONata","description":"Transforms JSON payload using JSONata transformation.","deprecated":false,"firstVersion":"3.5.0","label":"transformation","javaType":"org.apache.camel.component.jsonata.JsonataComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jsonata","version":"4.18.0","scheme":"jsonata","extendsScheme":"","syntax":"jsonata:resourceUri","async":false,"api":false,"consumerOnly":false,"prod [...]
+,
+{"component":{"kind":"component","name":"jt400","title":"JT400","description":"Exchanges messages with an IBM i system using data queues, message queues, or program call. IBM i is the replacement for AS/400 and iSeries servers.","deprecated":false,"firstVersion":"1.5.0","label":"messaging","javaType":"org.apache.camel.component.jt400.Jt400Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jt400","version":"4.18.0","scheme":"jt400","extendsScheme":"","synt [...]
+,
+{"component":{"kind":"component","name":"jte","title":"JTE","description":"Transform messages using a Java based template engine (JTE).","deprecated":false,"firstVersion":"4.4.0","label":"transformation","javaType":"org.apache.camel.component.jte.JteComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jte","version":"4.18.0","scheme":"jte","extendsScheme":"","syntax":"jte:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenie [...]
+,
+{"component":{"kind":"component","name":"kafka","title":"Kafka","description":"Send and receive messages to/from an Apache Kafka broker.","deprecated":false,"firstVersion":"2.13.0","label":"messaging","javaType":"org.apache.camel.component.kafka.KafkaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kafka","version":"4.18.0","scheme":"kafka","extendsScheme":"","syntax":"kafka:topic","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"len [...]
+,
+{"component":{"kind":"component","name":"keycloak","title":"Keycloak","description":"Manage Keycloak instances via Admin API.","deprecated":false,"firstVersion":"4.15.0","label":"security,management","javaType":"org.apache.camel.component.keycloak.KeycloakComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-keycloak","version":"4.18.0","scheme":"keycloak","extendsScheme":"","syntax":"keycloak:label","async":false,"api":false,"consumerOnly":false,"producerOn [...]
+,
+{"component":{"kind":"component","name":"knative","title":"Knative","description":"Send and receive events from Knative.","deprecated":false,"firstVersion":"3.15.0","label":"cloud","javaType":"org.apache.camel.component.knative.KnativeComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-knative","version":"4.18.0","scheme":"knative","extendsScheme":"","syntax":"knative:type/typeId","async":false,"api":false,"consumerOnly":fals [...]
+,
+{"component":{"kind":"component","name":"kserve","title":"KServe","description":"Provide access to AI model servers with the KServe standard to run inference with remote models","deprecated":false,"firstVersion":"4.10.0","label":"ai","javaType":"org.apache.camel.component.kserve.KServeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kserve","version":"4.18.0","scheme":"kserve","extendsScheme":"","syntax":"kserve:api","async":false,"api":false,"consumerO [...]
+,
+{"component":{"kind":"component","name":"kubernetes-config-maps","title":"Kubernetes ConfigMap","description":"Perform operations on Kubernetes ConfigMaps and get notified on ConfigMaps changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.config_maps.KubernetesConfigMapsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-config-ma [...]
+,
+{"component":{"kind":"component","name":"kubernetes-cronjob","title":"Kubernetes Cronjob","description":"Perform operations on Kubernetes CronJob.","deprecated":false,"firstVersion":"4.3.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.cronjob.KubernetesCronJobComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-cronjob","extendsScheme":"","syntax":"kubernetes-cronjob:masterUr [...]
+,
+{"component":{"kind":"component","name":"kubernetes-custom-resources","title":"Kubernetes Custom Resources","description":"Perform operations on Kubernetes Custom Resources and get notified on Deployment changes.","deprecated":false,"firstVersion":"3.7.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.customresources.KubernetesCustomResourcesComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","sch [...]
+,
+{"component":{"kind":"component","name":"kubernetes-deployments","title":"Kubernetes Deployments","description":"Perform operations on Kubernetes Deployments and get notified on Deployment changes.","deprecated":false,"firstVersion":"2.20.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.deployments.KubernetesDeploymentsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-deplo [...]
+,
+{"component":{"kind":"component","name":"kubernetes-events","title":"Kubernetes Event","description":"Perform operations on Kubernetes Events and get notified on Events changes.","deprecated":false,"firstVersion":"3.20.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.events.KubernetesEventsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-events","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"kubernetes-hpa","title":"Kubernetes HPA","description":"Perform operations on Kubernetes Horizontal Pod Autoscalers (HPA) and get notified on HPA changes.","deprecated":false,"firstVersion":"2.23.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.hpa.KubernetesHPAComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-hpa","extendsScheme":"" [...]
+,
+{"component":{"kind":"component","name":"kubernetes-job","title":"Kubernetes Job","description":"Perform operations on Kubernetes Jobs.","deprecated":false,"firstVersion":"2.23.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.job.KubernetesJobComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-job","extendsScheme":"","syntax":"kubernetes-job:masterUrl","async":false,"api":fal [...]
+,
+{"component":{"kind":"component","name":"kubernetes-namespaces","title":"Kubernetes Namespaces","description":"Perform operations on Kubernetes Namespaces and get notified on Namespace changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.namespaces.KubernetesNamespacesComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-namespaces" [...]
+,
+{"component":{"kind":"component","name":"kubernetes-nodes","title":"Kubernetes Nodes","description":"Perform operations on Kubernetes Nodes and get notified on Node changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.nodes.KubernetesNodesComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-nodes","extendsScheme":"","syntax":"kuber [...]
+,
+{"component":{"kind":"component","name":"kubernetes-persistent-volumes","title":"Kubernetes Persistent Volume","description":"Perform operations on Kubernetes Persistent Volumes and get notified on Persistent Volume changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.persistent_volumes.KubernetesPersistentVolumesComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","vers [...]
+,
+{"component":{"kind":"component","name":"kubernetes-persistent-volumes-claims","title":"Kubernetes Persistent Volume Claim","description":"Perform operations on Kubernetes Persistent Volumes Claims and get notified on Persistent Volumes Claim changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.persistent_volumes_claims.KubernetesPersistentVolumesClaimsComponent","supportLevel":"Stable","groupId":"org.apache.came [...]
+,
+{"component":{"kind":"component","name":"kubernetes-pods","title":"Kubernetes Pods","description":"Perform operations on Kubernetes Pods and get notified on Pod changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.pods.KubernetesPodsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-pods","extendsScheme":"","syntax":"kubernetes-p [...]
+,
+{"component":{"kind":"component","name":"kubernetes-replication-controllers","title":"Kubernetes Replication Controller","description":"Perform operations on Kubernetes Replication Controllers and get notified on Replication Controllers changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.replication_controllers.KubernetesReplicationControllersComponent","supportLevel":"Stable","groupId":"org.apache.camel","artif [...]
+,
+{"component":{"kind":"component","name":"kubernetes-resources-quota","title":"Kubernetes Resources Quota","description":"Perform operations on Kubernetes Resources Quotas.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.resources_quota.KubernetesResourcesQuotaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-resources-quota","extend [...]
+,
+{"component":{"kind":"component","name":"kubernetes-secrets","title":"Kubernetes Secrets","description":"Perform operations on Kubernetes Secrets.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.secrets.KubernetesSecretsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-secrets","extendsScheme":"","syntax":"kubernetes-secrets:masterU [...]
+,
+{"component":{"kind":"component","name":"kubernetes-service-accounts","title":"Kubernetes Service Account","description":"Perform operations on Kubernetes Service Accounts.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.service_accounts.KubernetesServiceAccountsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-service-accounts","ex [...]
+,
+{"component":{"kind":"component","name":"kubernetes-services","title":"Kubernetes Services","description":"Perform operations on Kubernetes Services and get notified on Service changes.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.kubernetes.services.KubernetesServicesComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"kubernetes-services","extendsSchem [...]
+,
+{"component":{"kind":"component","name":"kudu","title":"Kudu","description":"Interact with Apache Kudu, a free and open source column-oriented data store of the Apache Hadoop ecosystem.","deprecated":false,"firstVersion":"3.0","label":"database,iot,cloud","javaType":"org.apache.camel.component.kudu.KuduComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kudu","version":"4.18.0","scheme":"kudu","extendsScheme":"","syntax":"kudu:host:port/tableName","async": [...]
+,
+{"component":{"kind":"component","name":"langchain4j-agent","title":"LangChain4j Agent","description":"LangChain4j Agent component","deprecated":false,"firstVersion":"4.14.0","label":"ai","javaType":"org.apache.camel.component.langchain4j.agent.LangChain4jAgentComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-langchain4j-agent","version":"4.18.0","scheme":"langchain4j-agent","extendsScheme":"","syntax":"langchain4j-agent:agentId","async":false,"api":fal [...]
+,
+{"component":{"kind":"component","name":"langchain4j-chat","title":"LangChain4j Chat","description":"LangChain4j Chat component","deprecated":false,"firstVersion":"4.5.0","label":"ai","javaType":"org.apache.camel.component.langchain4j.chat.LangChain4jChatComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-langchain4j-chat","version":"4.18.0","scheme":"langchain4j-chat","extendsScheme":"","syntax":"langchain4j-chat:chatId","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"langchain4j-embeddings","title":"LangChain4j Embeddings","description":"LangChain4j Embeddings","deprecated":false,"firstVersion":"4.5.0","label":"ai","javaType":"org.apache.camel.component.langchain4j.embeddings.LangChain4jEmbeddingsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-langchain4j-embeddings","version":"4.18.0","scheme":"langchain4j-embeddings","extendsScheme":"","syntax":"langchain4j-embeddings:embe [...]
+,
+{"component":{"kind":"component","name":"langchain4j-embeddingstore","title":"LangChain4j Embedding Store","description":"Perform operations on the Langchain4jEmbeddingStores.","deprecated":false,"firstVersion":"4.14.0","label":"database,ai","javaType":"org.apache.camel.component.langchain4j.embeddingstore.LangChain4jEmbeddingStoreComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-langchain4j-embeddingstore","version":"4.18.0","scheme":"langchain4j-embedd [...]
+,
+{"component":{"kind":"component","name":"langchain4j-tools","title":"LangChain4j Tools","description":"LangChain4j Tools and Function Calling Features","deprecated":false,"firstVersion":"4.8.0","label":"ai","javaType":"org.apache.camel.component.langchain4j.tools.LangChain4jToolsComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-langchain4j-tools","version":"4.18.0","scheme":"langchain4j-tools","extendsScheme":"","syntax":"langchain4j-tools:toolId","asyn [...]
+,
+{"component":{"kind":"component","name":"langchain4j-web-search","title":"LangChain4j Web Search","description":"LangChain4j Web Search Engine","deprecated":false,"firstVersion":"4.8.0","label":"ai","javaType":"org.apache.camel.component.langchain4j.web.search.LangChain4jWebSearchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-langchain4j-web-search","version":"4.18.0","scheme":"langchain4j-web-search","extendsScheme":"","syntax":"langchain4j-web-searc [...]
+,
+{"component":{"kind":"component","name":"language","title":"Language","description":"Execute scripts in any of the languages supported by Camel.","deprecated":false,"firstVersion":"2.5.0","label":"core,script","javaType":"org.apache.camel.component.language.LanguageComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-language","version":"4.18.0","scheme":"language","extendsScheme":"","syntax":"language:languageName:resourceUri","async":false,"api":false,"co [...]
+,
+{"component":{"kind":"component","name":"ldap","title":"LDAP","description":"Perform searches on LDAP servers.","deprecated":false,"firstVersion":"1.5.0","label":"database,security","javaType":"org.apache.camel.component.ldap.LdapComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ldap","version":"4.18.0","scheme":"ldap","extendsScheme":"","syntax":"ldap:dirContextName","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties": [...]
+,
+{"component":{"kind":"component","name":"ldif","title":"LDIF","description":"Perform updates on an LDAP server from an LDIF body content.","deprecated":false,"firstVersion":"2.20.0","label":"database,security","javaType":"org.apache.camel.component.ldif.LdifComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ldif","version":"4.18.0","scheme":"ldif","extendsScheme":"","syntax":"ldif:ldapConnectionName","async":false,"api":false,"consumerOnly":false,"produce [...]
+,
+{"component":{"kind":"component","name":"log","title":"Log Data","description":"Prints data form the routed message (such as body and headers) to the logger.","deprecated":false,"firstVersion":"1.1.0","label":"core,monitoring","javaType":"org.apache.camel.component.log.LogComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-log","version":"4.18.0","scheme":"log","extendsScheme":"","syntax":"log:loggerName","async":false,"api":false,"consumerOnly":false,"pro [...]
+,
+{"component":{"kind":"component","name":"lpr","title":"Printer","description":"Send print jobs to printers.","deprecated":false,"firstVersion":"2.1.0","label":"document","javaType":"org.apache.camel.component.printer.PrinterComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-printer","version":"4.18.0","scheme":"lpr","extendsScheme":"","syntax":"lpr:hostname:port/printername","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProper [...]
+,
+{"component":{"kind":"component","name":"lucene","title":"Lucene","description":"Perform inserts or queries against Apache Lucene databases.","deprecated":false,"firstVersion":"2.2.0","label":"database,search","javaType":"org.apache.camel.component.lucene.LuceneComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-lucene","version":"4.18.0","scheme":"lucene","extendsScheme":"","syntax":"lucene:host:operation","async":false,"api":false,"consumerOnly":false,"p [...]
+,
+{"component":{"kind":"component","name":"lumberjack","title":"Lumberjack","description":"Receive logs messages using the Lumberjack protocol.","deprecated":false,"firstVersion":"2.18.0","label":"monitoring","javaType":"org.apache.camel.component.lumberjack.LumberjackComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-lumberjack","version":"4.18.0","scheme":"lumberjack","extendsScheme":"","syntax":"lumberjack:host:port","async":false,"api":false,"consumerOn [...]
+,
+{"component":{"kind":"component","name":"mapstruct","title":"MapStruct","description":"Type Conversion using Mapstruct","deprecated":false,"firstVersion":"3.19.0","label":"transformation","javaType":"org.apache.camel.component.mapstruct.MapstructComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mapstruct","version":"4.18.0","scheme":"mapstruct","extendsScheme":"","syntax":"mapstruct:className","async":false,"api":false,"consumerOnly":false,"producerOnly" [...]
+,
+{"component":{"kind":"component","name":"master","title":"Master","description":"Have only a single consumer in a cluster consuming from a given endpoint; with automatic failover if the JVM dies.","deprecated":false,"firstVersion":"2.20.0","label":"clustering","javaType":"org.apache.camel.component.master.MasterComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-master","version":"4.18.0","scheme":"master","extendsScheme":"","syntax":"master:namespace:dele [...]
+,
+{"component":{"kind":"component","name":"metrics","title":"Metrics","description":"Collect various metrics directly from Camel routes using the DropWizard metrics library.","deprecated":false,"firstVersion":"2.14.0","label":"monitoring","javaType":"org.apache.camel.component.metrics.MetricsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-metrics","version":"4.18.0","scheme":"metrics","extendsScheme":"","syntax":"metrics:metricsType:metricsName","async": [...]
+,
+{"component":{"kind":"component","name":"micrometer","title":"Micrometer","description":"Collect various metrics directly from Camel routes using the Micrometer library.","deprecated":false,"firstVersion":"2.22.0","label":"monitoring","javaType":"org.apache.camel.component.micrometer.MicrometerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-micrometer","version":"4.18.0","scheme":"micrometer","extendsScheme":"","syntax":"micrometer:metricsType:metricsN [...]
+,
+{"component":{"kind":"component","name":"milo-browse","title":"OPC UA Browser","description":"Connect to OPC UA servers using the binary protocol for browsing the node tree.","deprecated":false,"firstVersion":"3.15.0","label":"iot","javaType":"org.apache.camel.component.milo.browse.MiloBrowseComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-milo","version":"4.18.0","scheme":"milo-browse","extendsScheme":"","syntax":"milo-browse:endpointUri","async":false [...]
+,
+{"component":{"kind":"component","name":"milo-client","title":"OPC UA Client","description":"Connect to OPC UA servers using the binary protocol for acquiring telemetry data.","deprecated":false,"firstVersion":"2.19.0","label":"iot","javaType":"org.apache.camel.component.milo.client.MiloClientComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-milo","version":"4.18.0","scheme":"milo-client","extendsScheme":"","syntax":"milo-client:endpointUri","async":fals [...]
+,
+{"component":{"kind":"component","name":"milo-server","title":"OPC UA Server","description":"Make telemetry data available as an OPC UA server.","deprecated":false,"firstVersion":"2.19.0","label":"iot","javaType":"org.apache.camel.component.milo.server.MiloServerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-milo","version":"4.18.0","scheme":"milo-server","extendsScheme":"","syntax":"milo-server:itemId","async":false,"api":false,"consumerOnly":false," [...]
+,
+{"component":{"kind":"component","name":"milvus","title":"Milvus","description":"Perform operations on the Milvus Vector Database.","deprecated":false,"firstVersion":"4.5.0","label":"database,ai","javaType":"org.apache.camel.component.milvus.MilvusComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-milvus","version":"4.18.0","scheme":"milvus","extendsScheme":"","syntax":"milvus:collection","async":false,"api":false,"consumerOnly":false,"producerOnly":true, [...]
+,
+{"component":{"kind":"component","name":"mina","title":"Mina","description":"Socket level networking using TCP or UDP with Apache Mina 2.x.","deprecated":false,"firstVersion":"2.10.0","label":"networking","javaType":"org.apache.camel.component.mina.MinaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mina","version":"4.18.0","scheme":"mina","extendsScheme":"","syntax":"mina:protocol:host:port","async":false,"api":false,"consumerOnly":false,"producerOnly [...]
+,
+{"component":{"kind":"component","name":"mina-sftp","title":"MINA SFTP","description":"Upload and download files to/from SFTP servers using Apache MINA SSHD.","deprecated":false,"firstVersion":"4.18.0","label":"file","javaType":"org.apache.camel.component.file.remote.mina.MinaSftpComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-mina-sftp","version":"4.18.0","scheme":"mina-sftp","extendsScheme":"file","syntax":"mina-sftp:host:port/directoryName","async" [...]
+,
+{"component":{"kind":"component","name":"minio","title":"Minio","description":"Store and retrieve objects from Minio Storage Service using Minio SDK.","deprecated":false,"firstVersion":"3.5.0","label":"cloud,file","javaType":"org.apache.camel.component.minio.MinioComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-minio","version":"4.18.0","scheme":"minio","extendsScheme":"","syntax":"minio:bucketName","async":false,"api":false,"consumerOnly":false,"produc [...]
+,
+{"component":{"kind":"component","name":"mllp","title":"MLLP","description":"Communicate with external systems using the MLLP protocol.","deprecated":false,"firstVersion":"2.17.0","label":"health","javaType":"org.apache.camel.component.mllp.MllpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mllp","version":"4.18.0","scheme":"mllp","extendsScheme":"","syntax":"mllp:hostname:port","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"leni [...]
+,
+{"component":{"kind":"component","name":"mock","title":"Mock","description":"Test routes and mediation rules using mocks.","deprecated":false,"firstVersion":"1.0.0","label":"core,testing","javaType":"org.apache.camel.component.mock.MockComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mock","version":"4.18.0","scheme":"mock","extendsScheme":"","syntax":"mock:name","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":true [...]
+,
+{"component":{"kind":"component","name":"mongodb","title":"MongoDB","description":"Perform operations on MongoDB documents and collections.","deprecated":false,"firstVersion":"2.19.0","label":"database","javaType":"org.apache.camel.component.mongodb.MongoDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mongodb","version":"4.18.0","scheme":"mongodb","extendsScheme":"","syntax":"mongodb:connectionBean","async":false,"api":false,"consumerOnly":false,"pro [...]
+,
+{"component":{"kind":"component","name":"mongodb-gridfs","title":"MongoDB GridFS","description":"Interact with MongoDB GridFS.","deprecated":false,"firstVersion":"2.18.0","label":"database,file","javaType":"org.apache.camel.component.mongodb.gridfs.GridFsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mongodb-gridfs","version":"4.18.0","scheme":"mongodb-gridfs","extendsScheme":"","syntax":"mongodb-gridfs:connectionBean","async":false,"api":false,"consu [...]
+,
+{"component":{"kind":"component","name":"mustache","title":"Mustache","description":"Transform messages using a Mustache template.","deprecated":false,"firstVersion":"2.12.0","label":"transformation","javaType":"org.apache.camel.component.mustache.MustacheComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mustache","version":"4.18.0","scheme":"mustache","extendsScheme":"","syntax":"mustache:resourceUri","async":false,"api":false,"consumerOnly":false,"prod [...]
+,
+{"component":{"kind":"component","name":"mvel","title":"MVEL","description":"Transform messages using an MVEL template.","deprecated":false,"firstVersion":"2.12.0","label":"transformation,script","javaType":"org.apache.camel.component.mvel.MvelComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mvel","version":"4.18.0","scheme":"mvel","extendsScheme":"","syntax":"mvel:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientP [...]
+,
+{"component":{"kind":"component","name":"mybatis","title":"MyBatis","description":"Performs a query, poll, insert, update or delete in a relational database using MyBatis.","deprecated":false,"firstVersion":"2.7.0","label":"database","javaType":"org.apache.camel.component.mybatis.MyBatisComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mybatis","version":"4.18.0","scheme":"mybatis","extendsScheme":"","syntax":"mybatis:statement","async":false,"api":false [...]
+,
+{"component":{"kind":"component","name":"mybatis-bean","title":"MyBatis Bean","description":"Perform queries, inserts, updates or deletes in a relational database using MyBatis.","deprecated":false,"firstVersion":"2.22.0","label":"database","javaType":"org.apache.camel.component.mybatis.MyBatisBeanComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mybatis","version":"4.18.0","scheme":"mybatis-bean","extendsScheme":"","syntax":"mybatis-bean:beanName:method [...]
+,
+{"component":{"kind":"component","name":"nats","title":"Nats","description":"Send and receive messages from NATS messaging system.","deprecated":false,"firstVersion":"2.17.0","label":"messaging","javaType":"org.apache.camel.component.nats.NatsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-nats","version":"4.18.0","scheme":"nats","extendsScheme":"","syntax":"nats:topic","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientPropert [...]
+,
+{"component":{"kind":"component","name":"neo4j","title":"Neo4j","description":"Perform operations on the Neo4j Graph Database","deprecated":false,"firstVersion":"4.10.0","label":"database,ai","javaType":"org.apache.camel.component.neo4j.Neo4jComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-neo4j","version":"4.18.0","scheme":"neo4j","extendsScheme":"","syntax":"neo4j:name","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientPropert [...]
+,
+{"component":{"kind":"component","name":"netty","title":"Netty","description":"Socket level networking using TCP or UDP with Netty 4.x.","deprecated":false,"firstVersion":"2.14.0","label":"networking","javaType":"org.apache.camel.component.netty.NettyComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-netty","version":"4.18.0","scheme":"netty","extendsScheme":"","syntax":"netty:protocol://host:port","async":true,"api":false,"consumerOnly":false,"producerOn [...]
+,
+{"component":{"kind":"component","name":"netty-http","title":"Netty HTTP","description":"Netty HTTP server and client using the Netty 4.x.","deprecated":false,"firstVersion":"2.14.0","label":"networking,http","javaType":"org.apache.camel.component.netty.http.NettyHttpComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-netty-http","version":"4.18.0","scheme":"netty-http","extendsScheme":"netty","syntax":"netty-http:protocol:// [...]
+,
+{"component":{"kind":"component","name":"oaipmh","title":"OAI-PMH","description":"Harvest metadata using OAI-PMH protocol","deprecated":false,"firstVersion":"3.5.0","label":"search","javaType":"org.apache.camel.oaipmh.component.OAIPMHComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-oaipmh","version":"4.18.0","scheme":"oaipmh","extendsScheme":"","syntax":"oaipmh:baseUrl","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperti [...]
+,
+{"component":{"kind":"component","name":"once","title":"Once","description":"Trigger a single message only once at startup (useful for development and testing purposes).","deprecated":false,"firstVersion":"4.17.0","label":"core,scheduling","javaType":"org.apache.camel.component.once.OnceComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-once","version":"4.18.0","scheme":"once","extendsScheme":"","syntax":"once:name","async":false,"api":false,"consumerOnl [...]
+,
+{"component":{"kind":"component","name":"openai","title":"OpenAI","description":"OpenAI endpoint for chat completion and embeddings.","deprecated":false,"firstVersion":"4.17.0","label":"ai","javaType":"org.apache.camel.component.openai.OpenAIComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-openai","version":"4.18.0","scheme":"openai","extendsScheme":"","syntax":"openai:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenie [...]
+,
+{"component":{"kind":"component","name":"opensearch","title":"OpenSearch","description":"Send requests to OpenSearch via Java Client API.","deprecated":false,"firstVersion":"4.0.0","label":"search,monitoring","javaType":"org.apache.camel.component.opensearch.OpensearchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-opensearch","version":"4.18.0","scheme":"opensearch","extendsScheme":"","syntax":"opensearch:clusterName","async":false,"api":false,"consum [...]
+,
+{"component":{"kind":"component","name":"openshift-build-configs","title":"OpenShift Build Config","description":"Perform operations on OpenShift Build Configs.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.openshift.build_configs.OpenshiftBuildConfigsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"openshift-build-configs","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"openshift-builds","title":"OpenShift Builds","description":"Perform operations on OpenShift Builds.","deprecated":false,"firstVersion":"2.17.0","label":"container,cloud","javaType":"org.apache.camel.component.openshift.builds.OpenshiftBuildsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":"4.18.0","scheme":"openshift-builds","extendsScheme":"","syntax":"openshift-builds:masterUrl","async":fa [...]
+,
+{"component":{"kind":"component","name":"openshift-deploymentconfigs","title":"OpenShift Deployment Configs","description":"Perform operations on OpenShift Deployment Configs and get notified on Deployment Config changes.","deprecated":false,"firstVersion":"3.18.0","label":"container,cloud","javaType":"org.apache.camel.component.openshift.deploymentconfigs.OpenshiftDeploymentConfigsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-kubernetes","version":" [...]
+,
+{"component":{"kind":"component","name":"openstack-cinder","title":"OpenStack Cinder","description":"Access data in OpenStack Cinder block storage.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.cinder.CinderComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-cinder","extendsScheme":"","syntax":"openstack-cinder:host","async":false,"api":fals [...]
+,
+{"component":{"kind":"component","name":"openstack-glance","title":"OpenStack Glance","description":"Manage VM images and metadata definitions in OpenStack Glance.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.glance.GlanceComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-glance","extendsScheme":"","syntax":"openstack-glance:host","async": [...]
+,
+{"component":{"kind":"component","name":"openstack-keystone","title":"OpenStack Keystone","description":"Access OpenStack Keystone for API client authentication, service discovery and distributed multi-tenant authorization.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.keystone.KeystoneComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-keys [...]
+,
+{"component":{"kind":"component","name":"openstack-neutron","title":"OpenStack Neutron","description":"Access OpenStack Neutron for network services.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.neutron.NeutronComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-neutron","extendsScheme":"","syntax":"openstack-neutron:host","async":false,"api [...]
+,
+{"component":{"kind":"component","name":"openstack-nova","title":"OpenStack Nova","description":"Access OpenStack to manage compute resources.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.nova.NovaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-nova","extendsScheme":"","syntax":"openstack-nova:host","async":false,"api":false,"consumerOn [...]
+,
+{"component":{"kind":"component","name":"openstack-swift","title":"OpenStack Swift","description":"Access OpenStack Swift object/blob store.","deprecated":false,"firstVersion":"2.19.0","label":"container","javaType":"org.apache.camel.component.openstack.swift.SwiftComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-openstack","version":"4.18.0","scheme":"openstack-swift","extendsScheme":"","syntax":"openstack-swift:host","async":false,"api":false,"consumer [...]
+,
+{"component":{"kind":"component","name":"opentelemetry-metrics","title":"OpenTelemetry Metrics","description":"Camel metrics based on the Camel Telemetry spec","deprecated":false,"firstVersion":"4.17.0","label":"monitoring","javaType":"org.apache.camel.opentelemetry.metrics.OpenTelemetryComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-opentelemetry-metrics","version":"4.18.0","scheme":"opentelemetry-metrics","extendsScheme":"","syntax":"opentelemetry-m [...]
+,
+{"component":{"kind":"component","name":"optaplanner","title":"OptaPlanner","description":"Solve planning problems with OptaPlanner.","deprecated":false,"firstVersion":"2.13.0","label":"workflow","javaType":"org.apache.camel.component.optaplanner.OptaPlannerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-optaplanner","version":"4.18.0","scheme":"optaplanner","extendsScheme":"","syntax":"optaplanner:problemName","async":false,"api":false,"consumerOnly": [...]
+,
+{"component":{"kind":"component","name":"paho","title":"Paho","description":"Communicate with MQTT message brokers using Eclipse Paho MQTT Client.","deprecated":false,"firstVersion":"2.16.0","label":"messaging,iot","javaType":"org.apache.camel.component.paho.PahoComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-paho","version":"4.18.0","scheme":"paho","extendsScheme":"","syntax":"paho:topic","async":false,"api":false,"consumerOnly":false,"producerOnly":f [...]
+,
+{"component":{"kind":"component","name":"paho-mqtt5","title":"Paho MQTT 5","description":"Communicate with MQTT message brokers using Eclipse Paho MQTT v5 Client.","deprecated":false,"firstVersion":"3.8.0","label":"messaging,iot","javaType":"org.apache.camel.component.paho.mqtt5.PahoMqtt5Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-paho-mqtt5","version":"4.18.0","scheme":"paho-mqtt5","extendsScheme":"","syntax":"paho-mqtt5:topic","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"pdf","title":"PDF","description":"Create, modify or extract content from PDF documents.","deprecated":false,"firstVersion":"2.16.0","label":"document,transformation","javaType":"org.apache.camel.component.pdf.PdfComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pdf","version":"4.18.0","scheme":"pdf","extendsScheme":"","syntax":"pdf:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"leni [...]
+,
+{"component":{"kind":"component","name":"pg-replication-slot","title":"PostgresSQL Replication Slot","description":"Poll for PostgreSQL Write-Ahead Log (WAL) records using Streaming Replication Slots.","deprecated":false,"firstVersion":"3.0.0","label":"database","javaType":"org.apache.camel.component.pg.replication.slot.PgReplicationSlotComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pg-replication-slot","version":"4.18.0","scheme":"pg-replication-slot [...]
+,
+{"component":{"kind":"component","name":"pgevent","title":"PostgresSQL Event","description":"Send and receive PostgreSQL events via LISTEN and NOTIFY commands.","deprecated":false,"firstVersion":"2.15.0","label":"database","javaType":"org.apache.camel.component.pgevent.PgEventComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pgevent","version":"4.18.0","scheme":"pgevent","extendsScheme":"","syntax":"pgevent:host:port/database/channel","async":false,"api" [...]
+,
+{"component":{"kind":"component","name":"pinecone","title":"Pinecone","description":"Perform operations on the Pinecone Vector Database.","deprecated":false,"firstVersion":"4.6.0","label":"database,ai","javaType":"org.apache.camel.component.pinecone.PineconeVectorDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pinecone","version":"4.18.0","scheme":"pinecone","extendsScheme":"","syntax":"pinecone:collection","async":false,"api":false,"consumerOnly":fa [...]
+,
+{"component":{"kind":"component","name":"platform-http","title":"Platform HTTP","description":"Expose HTTP endpoints using the HTTP server available in the current platform.","deprecated":false,"firstVersion":"3.0.0","label":"http","javaType":"org.apache.camel.component.platform.http.PlatformHttpComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-platform-http","version":"4.18.0","scheme":"platform-http","extendsScheme":"","s [...]
+,
+{"component":{"kind":"component","name":"plc4x","title":"PLC4X","description":"Read and write to PLC devices","deprecated":false,"firstVersion":"3.20.0","label":"iot","javaType":"org.apache.camel.component.plc4x.Plc4XComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-plc4x","version":"4.18.0","scheme":"plc4x","extendsScheme":"","syntax":"plc4x:driver","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":true,"browsable": [...]
+,
+{"component":{"kind":"component","name":"pop3","title":"POP3","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"pop3","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"pop3:host:port","alternativeSyntax":"p [...]
+,
+{"component":{"kind":"component","name":"pop3s","title":"POP3S","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"pop3s","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"pop3s:host:port","alternativeSyntax [...]
+,
+{"component":{"kind":"component","name":"pqc","title":"PQC Algorithms","description":"Post Quantum Cryptography Signature and Verification component.","deprecated":false,"firstVersion":"4.12.0","label":"security","javaType":"org.apache.camel.component.pqc.PQCComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pqc","version":"4.18.0","scheme":"pqc","extendsScheme":"","syntax":"pqc:label","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"le [...]
+,
+{"component":{"kind":"component","name":"pubnub","title":"PubNub","description":"Send and receive messages to/from PubNub data stream network for connected devices.","deprecated":false,"firstVersion":"2.19.0","label":"cloud,iot,messaging","javaType":"org.apache.camel.component.pubnub.PubNubComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pubnub","version":"4.18.0","scheme":"pubnub","extendsScheme":"","syntax":"pubnub:channel","async":false,"api":false," [...]
+,
+{"component":{"kind":"component","name":"pulsar","title":"Pulsar","description":"Send and receive messages from/to Apache Pulsar messaging system.","deprecated":false,"firstVersion":"2.24.0","label":"messaging","javaType":"org.apache.camel.component.pulsar.PulsarComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-pulsar","version":"4.18.0","scheme":"pulsar","extendsScheme":"","syntax":"pulsar:persistence://tenant/namespace/topic","async":false,"api":false, [...]
+,
+{"component":{"kind":"component","name":"qdrant","title":"Qdrant","description":"Perform operations on the Qdrant Vector Database.","deprecated":false,"firstVersion":"4.5.0","label":"database,ai","javaType":"org.apache.camel.component.qdrant.QdrantComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-qdrant","version":"4.18.0","scheme":"qdrant","extendsScheme":"","syntax":"qdrant:collection","async":false,"api":false,"consumerOnly":false,"producerOnly":true, [...]
+,
+{"component":{"kind":"component","name":"quartz","title":"Quartz","description":"Schedule sending of messages using the Quartz 2.x scheduler.","deprecated":false,"firstVersion":"2.12.0","label":"scheduling","javaType":"org.apache.camel.component.quartz.QuartzComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-quartz","version":"4.18.0","scheme":"quartz","extendsScheme":"","syntax":"quartz:groupName/triggerName","async":false,"api":false,"consumerOnly":true [...]
+,
+{"component":{"kind":"component","name":"quickfix","title":"QuickFix","description":"Open a Financial Interchange (FIX) session using an embedded QuickFix/J engine.","deprecated":false,"firstVersion":"2.1.0","label":"messaging","javaType":"org.apache.camel.component.quickfixj.QuickfixjComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-quickfix","version":"4.18.0","scheme":"quickfix","extendsScheme":"","syntax":"quickfix:configurationName","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"reactive-streams","title":"Reactive Streams","description":"Exchange messages with reactive stream processing libraries compatible with the reactive streams standard.","deprecated":false,"firstVersion":"2.19.0","label":"messaging","javaType":"org.apache.camel.component.reactive.streams.ReactiveStreamsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-reactive-streams","version":"4.18.0","scheme":"reactive-streams", [...]
+,
+{"component":{"kind":"component","name":"ref","title":"Ref","description":"Route messages to an endpoint looked up dynamically by name in the Camel Registry.","deprecated":false,"firstVersion":"1.2.0","label":"core","javaType":"org.apache.camel.component.ref.RefComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ref","version":"4.18.0","scheme":"ref","extendsScheme":"","syntax":"ref:name","async":false,"api":false,"consumerOnly":false,"producerOnly":false, [...]
+,
+{"component":{"kind":"component","name":"rest","title":"REST","description":"Expose REST services or call external REST services.","deprecated":false,"firstVersion":"2.14.0","label":"core,rest","javaType":"org.apache.camel.component.rest.RestComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-rest","version":"4.18.0","scheme":"rest","extendsScheme":"","syntax":"rest:method:path:uriTemplate","async":false,"api":false,"consumer [...]
+,
+{"component":{"kind":"component","name":"rest-api","title":"REST API","description":"Expose OpenAPI Specification of the REST services defined using Camel REST DSL.","deprecated":false,"firstVersion":"2.16.0","label":"core,rest","javaType":"org.apache.camel.component.rest.RestApiComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-rest","version":"4.18.0","scheme":"rest-api","extendsScheme":"","syntax":"rest-api:path","async":false,"api":false,"consumerOnly [...]
+,
+{"component":{"kind":"component","name":"rest-openapi","title":"REST OpenApi","description":"To call REST services using OpenAPI specification as contract.","deprecated":false,"firstVersion":"3.1.0","label":"rest,api","javaType":"org.apache.camel.component.rest.openapi.RestOpenApiComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-rest-openapi","version":"4.18.0","scheme":"rest-openapi","extendsScheme":"","syntax":"rest-openapi:specificationUri#operationId [...]
+,
+{"component":{"kind":"component","name":"robotframework","title":"Robot Framework","description":"Pass camel exchanges to acceptance test written in Robot DSL.","deprecated":false,"firstVersion":"3.0.0","label":"testing","javaType":"org.apache.camel.component.robotframework.RobotFrameworkComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-robotframework","version":"4.18.0","scheme":"robotframework","extendsScheme":"","syntax":"robotframework:resourceUri"," [...]
+,
+{"component":{"kind":"component","name":"rocketmq","title":"RocketMQ","description":"Send and receive messages from RocketMQ cluster.","deprecated":false,"firstVersion":"3.20.0","label":"messaging","javaType":"org.apache.camel.component.rocketmq.RocketMQComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-rocketmq","version":"4.18.0","scheme":"rocketmq","extendsScheme":"","syntax":"rocketmq:topicName","async":true,"api":false,"consumerOnly":false,"producerO [...]
+,
+{"component":{"kind":"component","name":"rss","title":"RSS","description":"Poll RSS feeds.","deprecated":false,"firstVersion":"2.0.0","label":"document","javaType":"org.apache.camel.component.rss.RssComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-rss","version":"4.18.0","scheme":"rss","extendsScheme":"atom","syntax":"rss:feedUri","async":false,"api":false,"consumerOnly":true,"producerOnly":false,"lenientProperties":true,"browsable":false,"remote":true} [...]
+,
+{"component":{"kind":"component","name":"saga","title":"Saga","description":"Execute custom actions within a route using the Saga EIP.","deprecated":false,"firstVersion":"2.21.0","label":"clustering","javaType":"org.apache.camel.component.saga.SagaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-saga","version":"4.18.0","scheme":"saga","extendsScheme":"","syntax":"saga:action","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientPr [...]
+,
+{"component":{"kind":"component","name":"salesforce","title":"Salesforce","description":"Communicate with Salesforce using Java DTOs.","deprecated":false,"firstVersion":"2.12.0","label":"cloud,saas","javaType":"org.apache.camel.component.salesforce.SalesforceComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-salesforce","version":"4.18.0","scheme":"salesforce","extendsScheme":"","syntax":"salesforce:operationName:topicName","async":false,"api":false,"cons [...]
+,
+{"component":{"kind":"component","name":"sap-netweaver","title":"SAP NetWeaver","description":"Send requests to SAP NetWeaver Gateway using HTTP.","deprecated":false,"firstVersion":"2.12.0","label":"saas","javaType":"org.apache.camel.component.sap.netweaver.NetWeaverComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-sap-netweaver","version":"4.18.0","scheme":"sap-netweaver","extendsScheme":"","syntax":"sap-netweaver:url","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"scheduler","title":"Scheduler","description":"Generate messages in specified intervals using java.util.concurrent.ScheduledExecutorService.","deprecated":false,"firstVersion":"2.15.0","label":"core,scheduling","javaType":"org.apache.camel.component.scheduler.SchedulerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-scheduler","version":"4.18.0","scheme":"scheduler","extendsScheme":"","syntax":"scheduler:name","as [...]
+,
+{"component":{"kind":"component","name":"schematron","title":"Schematron","description":"Validate XML payload using the Schematron Library.","deprecated":false,"firstVersion":"2.15.0","label":"validation","javaType":"org.apache.camel.component.schematron.SchematronComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-schematron","version":"4.18.0","scheme":"schematron","extendsScheme":"","syntax":"schematron:path","async":false,"api":false,"consumerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"scp","title":"SCP","description":"Copy files to/from remote hosts using the secure copy protocol (SCP).","deprecated":false,"firstVersion":"2.10.0","label":"file","javaType":"org.apache.camel.component.scp.ScpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-jsch","version":"4.18.0","scheme":"scp","extendsScheme":"ftp","syntax":"scp:host:port/directoryName","async":false,"api":false,"consumerOnly":false,"producerO [...]
+,
+{"component":{"kind":"component","name":"seda","title":"SEDA","description":"Asynchronously call another endpoint from any Camel Context in the same JVM.","deprecated":false,"firstVersion":"1.1.0","label":"core,messaging","javaType":"org.apache.camel.component.seda.SedaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-seda","version":"4.18.0","scheme":"seda","extendsScheme":"","syntax":"seda:name","async":true,"api":false,"consumerOnly":false,"producerOn [...]
+,
+{"component":{"kind":"component","name":"servicenow","title":"ServiceNow","description":"Interact with ServiceNow via its REST API.","deprecated":false,"firstVersion":"2.18.0","label":"api,cloud,management","javaType":"org.apache.camel.component.servicenow.ServiceNowComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-servicenow","version":"4.18.0","scheme":"servicenow","extendsScheme":"","syntax":"servicenow:instanceName","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"servlet","title":"Servlet","description":"Serve HTTP requests by a Servlet.","deprecated":false,"firstVersion":"2.0.0","label":"http","javaType":"org.apache.camel.component.servlet.ServletComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-servlet","version":"4.18.0","scheme":"servlet","extendsScheme":"http","syntax":"servlet:contextPath","async":false,"api":false,"consumerOnly":true," [...]
+,
+{"component":{"kind":"component","name":"sftp","title":"SFTP","description":"Upload and download files to/from SFTP servers.","deprecated":false,"firstVersion":"1.1.0","label":"file","javaType":"org.apache.camel.component.file.remote.SftpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ftp","version":"4.18.0","scheme":"sftp","extendsScheme":"file","syntax":"sftp:host:port/directoryName","async":false,"api":false,"consumerOnly":false,"producerOnly":false [...]
+,
+{"component":{"kind":"component","name":"sjms","title":"Simple JMS","description":"Send and receive messages to/from a JMS Queue or Topic using plain JMS 1.x API.","deprecated":false,"firstVersion":"2.11.0","label":"messaging","javaType":"org.apache.camel.component.sjms.SjmsComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-sjms","version":"4.18.0","scheme":"sjms","extendsScheme":"","syntax":"sjms:destinationType:destinationName","async":true,"api":false, [...]
+,
+{"component":{"kind":"component","name":"sjms2","title":"Simple JMS2","description":"Send and receive messages to/from a JMS Queue or Topic using plain JMS 2.x API.","deprecated":false,"firstVersion":"2.19.0","label":"messaging","javaType":"org.apache.camel.component.sjms2.Sjms2Component","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-sjms2","version":"4.18.0","scheme":"sjms2","extendsScheme":"sjms","syntax":"sjms2:destinationType:destinationName","async":true," [...]
+,
+{"component":{"kind":"component","name":"slack","title":"Slack","description":"Send and receive messages to/from Slack.","deprecated":false,"firstVersion":"2.16.0","label":"social","javaType":"org.apache.camel.component.slack.SlackComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-slack","version":"4.18.0","scheme":"slack","extendsScheme":"","syntax":"slack:channel","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":fa [...]
+,
+{"component":{"kind":"component","name":"smb","title":"SMB","description":"Read and write files to Server Message Block (SMB) file shares.","deprecated":false,"firstVersion":"4.3.0","label":"file","javaType":"org.apache.camel.component.smb.SmbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-smb","version":"4.18.0","scheme":"smb","extendsScheme":"","syntax":"smb:hostname:port/shareName/path","async":false,"api":false,"consumerOnly":false,"producerOnly":f [...]
+,
+{"component":{"kind":"component","name":"smooks","title":"Smooks","description":"Use Smooks to transform, route, and bind both XML and non-XML data, including EDI, CSV, JSON, and YAML.","deprecated":false,"firstVersion":"4.7.0","label":"transformation","javaType":"org.apache.camel.component.smooks.SmooksComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-smooks","version":"4.18.0","scheme":"smooks","extendsScheme":"","syntax":"smooks:smooksConfig","async": [...]
+,
+{"component":{"kind":"component","name":"smpp","title":"SMPP","description":"Send and receive SMS messages using a SMSC (Short Message Service Center).","deprecated":false,"firstVersion":"2.2.0","label":"mobile","javaType":"org.apache.camel.component.smpp.SmppComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-smpp","version":"4.18.0","scheme":"smpp","extendsScheme":"","alternativeSchemes":"smpp,smpps","syntax":"smpp:host:port","async":false,"api":false,"c [...]
+,
+{"component":{"kind":"component","name":"smpps","title":"SMPP (Secure)","description":"Send and receive SMS messages using a SMSC (Short Message Service Center).","deprecated":false,"firstVersion":"2.2.0","label":"mobile","javaType":"org.apache.camel.component.smpp.SmppComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-smpp","version":"4.18.0","scheme":"smpps","extendsScheme":"","alternativeSchemes":"smpp,smpps","syntax":"smpps:host:port","async":false,"a [...]
+,
+{"component":{"kind":"component","name":"smtp","title":"SMTP","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"smtp","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"smtp:host:port","alternativeSyntax":"s [...]
+,
+{"component":{"kind":"component","name":"smtps","title":"SMTPS","description":"Send and receive emails using imap, pop3 and smtp protocols.","deprecated":false,"firstVersion":"1.0.0","label":"mail","javaType":"org.apache.camel.component.mail.MailComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-mail","version":"4.18.0","scheme":"smtps","extendsScheme":"","alternativeSchemes":"imap,imaps,pop3,pop3s,smtp,smtps","syntax":"smtps:host:port","alternativeSyntax [...]
+,
+{"component":{"kind":"component","name":"snmp","title":"SNMP","description":"Receive traps and poll SNMP (Simple Network Management Protocol) capable devices.","deprecated":false,"firstVersion":"2.1.0","label":"monitoring","javaType":"org.apache.camel.component.snmp.SnmpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-snmp","version":"4.18.0","scheme":"snmp","extendsScheme":"","syntax":"snmp:host:port","async":false,"api":false,"consumerOnly":false,"pro [...]
+,
+{"component":{"kind":"component","name":"solr","title":"Solr","description":"Perform operations against Apache Lucene Solr.","deprecated":false,"firstVersion":"4.8.0","label":"search,monitoring","javaType":"org.apache.camel.component.solr.SolrComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-solr","version":"4.18.0","scheme":"solr","extendsScheme":"","syntax":"solr:host:port/basePath","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"le [...]
+,
+{"component":{"kind":"component","name":"splunk","title":"Splunk","description":"Publish or search for events in Splunk.","deprecated":false,"firstVersion":"2.13.0","label":"iot,monitoring","javaType":"org.apache.camel.component.splunk.SplunkComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-splunk","version":"4.18.0","scheme":"splunk","extendsScheme":"","syntax":"splunk:name","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientPro [...]
+,
+{"component":{"kind":"component","name":"splunk-hec","title":"Splunk HEC","description":"The splunk component allows publishing events in Splunk using the HTTP Event Collector.","deprecated":false,"firstVersion":"3.3.0","label":"monitoring","javaType":"org.apache.camel.component.splunkhec.SplunkHECComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-splunk-hec","version":"4.18.0","scheme":"splunk-hec","extendsScheme":"","syntax":"splunk-hec:splunkURL","asyn [...]
+,
+{"component":{"kind":"component","name":"spring-ai-chat","title":"Spring AI Chat","description":"Perform chat operations using Spring AI.","deprecated":false,"firstVersion":"4.17.0","label":"ai","javaType":"org.apache.camel.component.springai.chat.SpringAiChatComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-spring-ai-chat","version":"4.18.0","scheme":"spring-ai-chat","extendsScheme":"","syntax":"spring-ai-chat:chatId","async":false,"api":false,"consume [...]
+,
+{"component":{"kind":"component","name":"spring-ai-embeddings","title":"Spring AI Embeddings","description":"Spring AI Embeddings","deprecated":false,"firstVersion":"4.17.0","label":"ai","javaType":"org.apache.camel.component.springai.embeddings.SpringAiEmbeddingsComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-spring-ai-embeddings","version":"4.18.0","scheme":"spring-ai-embeddings","extendsScheme":"","syntax":"spring-ai-embeddings:embeddingId","async" [...]
+,
+{"component":{"kind":"component","name":"spring-ai-tools","title":"Spring AI Tools","description":"Spring AI Tools and Function Calling Features","deprecated":false,"firstVersion":"4.17.0","label":"ai","javaType":"org.apache.camel.component.springai.tools.SpringAiToolsComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-spring-ai-tools","version":"4.18.0","scheme":"spring-ai-tools","extendsScheme":"","syntax":"spring-ai-tools:toolId","async":false,"api":fa [...]
+,
+{"component":{"kind":"component","name":"spring-ai-vector-store","title":"Spring AI Vector Store","description":"Spring AI Vector Store","deprecated":false,"firstVersion":"4.17.0","label":"ai","javaType":"org.apache.camel.component.springai.vectorstore.SpringAiVectorStoreComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-spring-ai-vector-store","version":"4.18.0","scheme":"spring-ai-vector-store","extendsScheme":"","syntax":"spring-ai-vector-store:storeI [...]
+,
+{"component":{"kind":"component","name":"spring-batch","title":"Spring Batch","description":"Send messages to Spring Batch for further processing.","deprecated":false,"firstVersion":"2.10.0","label":"workflow","javaType":"org.apache.camel.component.spring.batch.SpringBatchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring-batch","version":"4.18.0","scheme":"spring-batch","extendsScheme":"","syntax":"spring-batch:jobName","async":false,"api":false," [...]
+,
+{"component":{"kind":"component","name":"spring-event","title":"Spring Event","description":"Listen for Spring Application Events.","deprecated":false,"firstVersion":"1.4.0","label":"messaging","javaType":"org.apache.camel.component.event.EventComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring","version":"4.18.0","scheme":"spring-event","extendsScheme":"","syntax":"spring-event:name","async":false,"api":false,"consumerOnly":false,"producerOnly":fal [...]
+,
+{"component":{"kind":"component","name":"spring-jdbc","title":"Spring JDBC","description":"Access databases through SQL and JDBC with Spring Transaction support.","deprecated":false,"firstVersion":"3.10.0","label":"database","javaType":"org.apache.camel.component.spring.jdbc.SpringJdbcComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring-jdbc","version":"4.18.0","scheme":"spring-jdbc","extendsScheme":"","syntax":"spring-jdbc:dataSourceName","async":fa [...]
+,
+{"component":{"kind":"component","name":"spring-ldap","title":"Spring LDAP","description":"Perform searches in LDAP servers using filters as the message payload.","deprecated":false,"firstVersion":"2.11.0","label":"security","javaType":"org.apache.camel.component.springldap.SpringLdapComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring-ldap","version":"4.18.0","scheme":"spring-ldap","extendsScheme":"","syntax":"spring-ldap:templateName","async":false [...]
+,
+{"component":{"kind":"component","name":"spring-rabbitmq","title":"Spring RabbitMQ","description":"Send and receive messages from RabbitMQ using the Spring RabbitMQ client.","deprecated":false,"firstVersion":"3.8.0","label":"messaging","javaType":"org.apache.camel.component.springrabbit.SpringRabbitMQComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring-rabbitmq","version":"4.18.0","scheme":"spring-rabbitmq","extendsScheme":"","syntax":"spring-rabbitm [...]
+,
+{"component":{"kind":"component","name":"spring-redis","title":"Spring Redis","description":"Send and receive messages from Redis.","deprecated":false,"firstVersion":"2.11.0","label":"cache","javaType":"org.apache.camel.component.redis.RedisComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-spring-redis","version":"4.18.0","scheme":"spring-redis","extendsScheme":"","syntax":"spring-redis:host:port","async":false,"api":false,"consumerOnly":false,"producerO [...]
+,
+{"component":{"kind":"component","name":"spring-ws","title":"Spring WebService","description":"Access external web services as a client or expose your own web services.","deprecated":false,"firstVersion":"2.6.0","label":"webservice","javaType":"org.apache.camel.component.spring.ws.SpringWebserviceComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-spring-ws","version":"4.18.0","scheme":"spring-ws","extendsScheme":"","syntax": [...]
+,
+{"component":{"kind":"component","name":"sql","title":"SQL","description":"Perform SQL queries using Spring JDBC.","deprecated":false,"firstVersion":"1.4.0","label":"database","javaType":"org.apache.camel.component.sql.SqlComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-sql","version":"4.18.0","scheme":"sql","extendsScheme":"","syntax":"sql:query","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"lenientProperties":false,"browsable":f [...]
+,
+{"component":{"kind":"component","name":"sql-stored","title":"SQL Stored Procedure","description":"Perform SQL queries as a JDBC Stored Procedures using Spring JDBC.","deprecated":false,"firstVersion":"2.17.0","label":"database","javaType":"org.apache.camel.component.sql.stored.SqlStoredComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-sql","version":"4.18.0","scheme":"sql-stored","extendsScheme":"","syntax":"sql-stored:template","async":false,"api":fals [...]
+,
+{"component":{"kind":"component","name":"ssh","title":"SSH","description":"Execute commands on remote hosts using SSH.","deprecated":false,"firstVersion":"2.10.0","label":"file","javaType":"org.apache.camel.component.ssh.SshComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-ssh","version":"4.18.0","scheme":"ssh","extendsScheme":"","syntax":"ssh:host:port","alternativeSyntax":"ssh:username:password@host:port","async":false,"api":false,"consumerOnly":false, [...]
+,
+{"component":{"kind":"component","name":"stax","title":"StAX","description":"Process XML payloads by a SAX ContentHandler.","deprecated":false,"firstVersion":"2.9.0","label":"transformation","javaType":"org.apache.camel.component.stax.StAXComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-stax","version":"4.18.0","scheme":"stax","extendsScheme":"","syntax":"stax:contentHandlerClass","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenie [...]
+,
+{"component":{"kind":"component","name":"stitch","title":"Stitch","description":"Stitch is a cloud ETL service that integrates various data sources into a central data warehouse through various integrations.","deprecated":false,"firstVersion":"3.8.0","label":"cloud,api,saas,bigdata","javaType":"org.apache.camel.component.stitch.StitchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-stitch","version":"4.18.0","scheme":"stitch","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"stream","title":"Stream","description":"Read from system-in and write to system-out and system-err streams.","deprecated":false,"firstVersion":"1.3.0","label":"file,core","javaType":"org.apache.camel.component.stream.StreamComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-stream","version":"4.18.0","scheme":"stream","extendsScheme":"","syntax":"stream:kind","async":false,"api":false,"consumerOnly":false,"producerO [...]
+,
+{"component":{"kind":"component","name":"string-template","title":"String Template","description":"Transform messages using StringTemplate engine.","deprecated":false,"firstVersion":"1.2.0","label":"transformation,script","javaType":"org.apache.camel.component.stringtemplate.StringTemplateComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-stringtemplate","version":"4.18.0","scheme":"string-template","extendsScheme":"","syntax":"string-template:resourceUri [...]
+,
+{"component":{"kind":"component","name":"stripe","title":"Stripe","description":"Interact with the Stripe payment platform.","deprecated":false,"firstVersion":"4.17.0","label":"saas,finance","javaType":"org.apache.camel.component.stripe.StripeComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-stripe","version":"4.18.0","scheme":"stripe","extendsScheme":"","syntax":"stripe:operation","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"leni [...]
+,
+{"component":{"kind":"component","name":"stub","title":"Stub","description":"Stub out any physical endpoints while in development or testing.","deprecated":false,"firstVersion":"2.10.0","label":"core,testing","javaType":"org.apache.camel.component.stub.StubComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-stub","version":"4.18.0","scheme":"stub","extendsScheme":"","syntax":"stub:name","async":true,"api":false,"consumerOnly":false,"producerOnly":false,"le [...]
+,
+{"component":{"kind":"component","name":"tahu-edge","title":"Tahu Edge Node / Device","description":"Sparkplug B Edge Node and Device support over MQTT using Eclipse Tahu","deprecated":false,"firstVersion":"4.8.0","label":"messaging,iot,monitoring","javaType":"org.apache.camel.component.tahu.TahuEdgeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-tahu","version":"4.18.0","scheme":"tahu-edge","extendsScheme":"","syntax":"tahu-edge:groupId/edgeNode","alt [...]
+,
+{"component":{"kind":"component","name":"tahu-host","title":"Tahu Host Application","description":"Sparkplug B Host Application support over MQTT using Eclipse Tahu","deprecated":false,"firstVersion":"4.8.0","label":"messaging,iot,monitoring","javaType":"org.apache.camel.component.tahu.TahuHostComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-tahu","version":"4.18.0","scheme":"tahu-host","extendsScheme":"","syntax":"tahu-host:hostId","async":false,"api": [...]
+,
+{"component":{"kind":"component","name":"telegram","title":"Telegram","description":"Send and receive messages using the Telegram Bot API.","deprecated":false,"firstVersion":"2.18.0","label":"cloud,api,chat","javaType":"org.apache.camel.component.telegram.TelegramComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-telegram","version":"4.18.0","scheme":"telegram","extendsScheme":"","syntax":"telegram:type","async":false,"api":false,"consumerOnly":false,"pro [...]
+,
+{"component":{"kind":"component","name":"tensorflow-serving","title":"TensorFlow Serving","description":"Provide access to TensorFlow Serving model servers to run inference with TensorFlow saved models remotely","deprecated":false,"firstVersion":"4.10.0","label":"ai","javaType":"org.apache.camel.component.tensorflow.serving.TensorFlowServingComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-tensorflow-serving","version":"4.18.0","scheme":"tensorflow-servi [...]
+,
+{"component":{"kind":"component","name":"thrift","title":"Thrift","description":"Call and expose remote procedures (RPC) with Apache Thrift data format and serialization mechanism.","deprecated":false,"firstVersion":"2.20.0","label":"rpc,transformation","javaType":"org.apache.camel.component.thrift.ThriftComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-thrift","version":"4.18.0","scheme":"thrift","extendsScheme":"","syntax":"thrift:host:port/service","a [...]
+,
+{"component":{"kind":"component","name":"thymeleaf","title":"Thymeleaf","description":"Transform messages using a Thymeleaf template.","deprecated":false,"firstVersion":"4.1.0","label":"transformation","javaType":"org.apache.camel.component.thymeleaf.ThymeleafComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-thymeleaf","version":"4.18.0","scheme":"thymeleaf","extendsScheme":"","syntax":"thymeleaf:resourceUri","async":false,"api":false,"consumerOnly":fals [...]
+,
+{"component":{"kind":"component","name":"tika","title":"Tika","description":"Parse documents and extract metadata and text using Apache Tika.","deprecated":false,"firstVersion":"2.19.0","label":"document,transformation","javaType":"org.apache.camel.component.tika.TikaComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-tika","version":"4.18.0","scheme":"tika","extendsScheme":"","syntax":"tika:operation","async":false,"api":false,"consumerOnly":false,"produc [...]
+,
+{"component":{"kind":"component","name":"timer","title":"Timer","description":"Generate messages in specified intervals using java.util.Timer.","deprecated":false,"firstVersion":"1.0.0","label":"core,scheduling","javaType":"org.apache.camel.component.timer.TimerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-timer","version":"4.18.0","scheme":"timer","extendsScheme":"","syntax":"timer:timerName","async":false,"api":false,"consumerOnly":true,"producerOn [...]
+,
+{"component":{"kind":"component","name":"twilio","title":"Twilio","description":"Interact with Twilio REST APIs using Twilio Java SDK.","deprecated":false,"firstVersion":"2.20.0","label":"api,messaging,cloud","javaType":"org.apache.camel.component.twilio.TwilioComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-twilio","version":"4.18.0","scheme":"twilio","extendsScheme":"","syntax":"twilio:apiName/methodName","async":false,"api":true,"apiSyntax":"apiName/ [...]
+,
+{"component":{"kind":"component","name":"twitter-directmessage","title":"Twitter Direct Message","description":"Send and receive Twitter direct messages.","deprecated":false,"firstVersion":"2.10.0","label":"saas,social","javaType":"org.apache.camel.component.twitter.directmessage.TwitterDirectMessageComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-twitter","version":"4.18.0","scheme":"twitter-directmessage","extendsScheme":"","syntax":"twitter-directmes [...]
+,
+{"component":{"kind":"component","name":"twitter-search","title":"Twitter Search","description":"Access Twitter Search.","deprecated":false,"firstVersion":"2.10.0","label":"saas,social","javaType":"org.apache.camel.component.twitter.search.TwitterSearchComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-twitter","version":"4.18.0","scheme":"twitter-search","extendsScheme":"","syntax":"twitter-search:keywords","async":false,"api":false,"consumerOnly":false, [...]
+,
+{"component":{"kind":"component","name":"twitter-timeline","title":"Twitter Timeline","description":"Send tweets and receive tweets from user's timeline.","deprecated":false,"firstVersion":"2.10.0","label":"saas,social","javaType":"org.apache.camel.component.twitter.timeline.TwitterTimelineComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-twitter","version":"4.18.0","scheme":"twitter-timeline","extendsScheme":"","syntax":"twitter-timeline:timelineType"," [...]
+,
+{"component":{"kind":"component","name":"undertow","title":"Undertow","description":"Expose HTTP and WebSocket endpoints and access external HTTP/WebSocket servers.","deprecated":false,"firstVersion":"2.16.0","label":"http,networking","javaType":"org.apache.camel.component.undertow.UndertowComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-undertow","version":"4.18.0","scheme":"undertow","extendsScheme":"","syntax":"undertow:httpURI","async":true,"api":fa [...]
+,
+{"component":{"kind":"component","name":"validator","title":"Validator","description":"Validate the payload using XML Schema and JAXP Validation.","deprecated":false,"firstVersion":"1.1.0","label":"core,validation","javaType":"org.apache.camel.component.validator.ValidatorComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-validator","version":"4.18.0","scheme":"validator","extendsScheme":"","syntax":"validator:resourceUri","async":false,"api":false,"consu [...]
+,
+{"component":{"kind":"component","name":"velocity","title":"Velocity","description":"Transform messages using a Velocity template.","deprecated":false,"firstVersion":"1.2.0","label":"transformation","javaType":"org.apache.camel.component.velocity.VelocityComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-velocity","version":"4.18.0","scheme":"velocity","extendsScheme":"","syntax":"velocity:resourceUri","async":false,"api":false,"consumerOnly":false,"produ [...]
+,
+{"component":{"kind":"component","name":"vertx","title":"Vert.x","description":"Send and receive messages to/from Vert.x Event Bus.","deprecated":false,"firstVersion":"2.12.0","label":"messaging","javaType":"org.apache.camel.component.vertx.VertxComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-vertx","version":"4.18.0","scheme":"vertx","extendsScheme":"","syntax":"vertx:address","async":true,"api":false,"consumerOnly":false,"producerOnly":false,"lenient [...]
+,
+{"component":{"kind":"component","name":"vertx-http","title":"Vert.x HTTP Client","description":"Send requests to external HTTP servers using Vert.x","deprecated":false,"firstVersion":"3.5.0","label":"http","javaType":"org.apache.camel.component.vertx.http.VertxHttpComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-vertx-http","version":"4.18.0","scheme":"vertx-http","extendsScheme":"","syntax":"vertx-http:httpUri","async":false,"api":false,"consumerOnly" [...]
+,
+{"component":{"kind":"component","name":"vertx-websocket","title":"Vert.x WebSocket","description":"Expose WebSocket endpoints and connect to remote WebSocket servers using Vert.x","deprecated":false,"firstVersion":"3.5.0","label":"http,networking","javaType":"org.apache.camel.component.vertx.websocket.VertxWebsocketComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-vertx-websocket","version":"4.18.0","scheme":"vertx-websocket","extendsScheme":"","syntax" [...]
+,
+{"component":{"kind":"component","name":"wasm","title":"Wasm","description":"Invoke Wasm functions.","deprecated":false,"firstVersion":"4.4.0","label":"core,script","javaType":"org.apache.camel.component.wasm.WasmComponent","supportLevel":"Experimental","groupId":"org.apache.camel","artifactId":"camel-wasm","version":"4.18.0","scheme":"wasm","extendsScheme":"","syntax":"wasm:functionName","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":false,"browsa [...]
+,
+{"component":{"kind":"component","name":"weather","title":"Weather","description":"Poll the weather information from Open Weather Map.","deprecated":false,"firstVersion":"2.12.0","label":"api","javaType":"org.apache.camel.component.weather.WeatherComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-weather","version":"4.18.0","scheme":"weather","extendsScheme":"","syntax":"weather:name","async":false,"api":false,"consumerOnly":false,"producerOnly":false,"le [...]
+,
+{"component":{"kind":"component","name":"weaviate","title":"weaviate","description":"Perform operations on the Weaviate Vector Database.","deprecated":false,"firstVersion":"4.12.0","label":"database,ai","javaType":"org.apache.camel.component.weaviate.WeaviateVectorDbComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-weaviate","version":"4.18.0","scheme":"weaviate","extendsScheme":"","syntax":"weaviate:collection","async":false,"api":false,"consumerOnly":f [...]
+,
+{"component":{"kind":"component","name":"web3j","title":"Web3j Ethereum Blockchain","description":"Interact with Ethereum nodes using web3j client API.","deprecated":false,"firstVersion":"2.22.0","label":"blockchain","javaType":"org.apache.camel.component.web3j.Web3jComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-web3j","version":"4.18.0","scheme":"web3j","extendsScheme":"","syntax":"web3j:nodeAddress","async":false,"api":false,"consumerOnly":false,"pr [...]
+,
+{"component":{"kind":"component","name":"webhook","title":"Webhook","description":"Expose webhook endpoints to receive push notifications for other Camel components.","deprecated":false,"firstVersion":"3.0.0","label":"cloud","javaType":"org.apache.camel.component.webhook.WebhookComponent","supportLevel":"Stable","metadata":{"protocol":"http"},"groupId":"org.apache.camel","artifactId":"camel-webhook","version":"4.18.0","scheme":"webhook","extendsScheme":"","syntax":"webhook:endpointUri"," [...]
+,
+{"component":{"kind":"component","name":"whatsapp","title":"WhatsApp","description":"Send messages to WhatsApp.","deprecated":false,"firstVersion":"3.19.0","label":"cloud,api,chat","javaType":"org.apache.camel.component.whatsapp.WhatsAppComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-whatsapp","version":"4.18.0","scheme":"whatsapp","extendsScheme":"","syntax":"whatsapp:phoneNumberId","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"l [...]
+,
+{"component":{"kind":"component","name":"wordpress","title":"WordPress","description":"Manage posts and users using the WordPress API.","deprecated":false,"firstVersion":"2.21.0","label":"cloud,api,cms","javaType":"org.apache.camel.component.wordpress.WordpressComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-wordpress","version":"4.18.0","scheme":"wordpress","extendsScheme":"","syntax":"wordpress:operation","async":false,"api":false,"consumerOnly":false [...]
+,
+{"component":{"kind":"component","name":"workday","title":"Workday","description":"Detect and parse documents using Workday.","deprecated":false,"firstVersion":"3.1.0","label":"cloud,api,saas","javaType":"org.apache.camel.component.workday.WorkdayComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-workday","version":"4.18.0","scheme":"workday","extendsScheme":"","syntax":"workday:entity:path","async":false,"api":false,"consumerOnly":false,"producerOnly":tr [...]
+,
+{"component":{"kind":"component","name":"xchange","title":"XChange","description":"Access market data and trade on Bitcoin and Altcoin exchanges.","deprecated":false,"firstVersion":"2.21.0","label":"blockchain","javaType":"org.apache.camel.component.xchange.XChangeComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xchange","version":"4.18.0","scheme":"xchange","extendsScheme":"","syntax":"xchange:name","async":false,"api":false,"consumerOnly":false,"produ [...]
+,
+{"component":{"kind":"component","name":"xj","title":"XJ","description":"Transform JSON and XML message using a XSLT.","deprecated":false,"firstVersion":"3.0.0","label":"transformation","javaType":"org.apache.camel.component.xj.XJComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xj","version":"4.18.0","scheme":"xj","extendsScheme":"","syntax":"xj:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenientProperties":false,"br [...]
+,
+{"component":{"kind":"component","name":"xmlsecurity-sign","title":"XML Security Sign","description":"Sign XML payloads using the XML signature specification.","deprecated":false,"firstVersion":"2.12.0","label":"security,transformation","javaType":"org.apache.camel.component.xmlsecurity.XmlSignerComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xmlsecurity","version":"4.18.0","scheme":"xmlsecurity-sign","extendsScheme":"","syntax":"xmlsecurity-sign:name" [...]
+,
+{"component":{"kind":"component","name":"xmlsecurity-verify","title":"XML Security Verify","description":"Verify XML payloads using the XML signature specification.","deprecated":false,"firstVersion":"2.12.0","label":"security,transformation","javaType":"org.apache.camel.component.xmlsecurity.XmlVerifierComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xmlsecurity","version":"4.18.0","scheme":"xmlsecurity-verify","extendsScheme":"","syntax":"xmlsecurity- [...]
+,
+{"component":{"kind":"component","name":"xmpp","title":"XMPP","description":"Send and receive messages to/from an XMPP chat server.","deprecated":false,"firstVersion":"1.0","label":"chat,messaging","javaType":"org.apache.camel.component.xmpp.XmppComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xmpp","version":"4.18.0","scheme":"xmpp","extendsScheme":"","syntax":"xmpp:host:port/participant","alternativeSyntax":"xmpp:user:password@host:port/participant"," [...]
+,
+{"component":{"kind":"component","name":"xquery","title":"XQuery","description":"Query and/or transform XML payloads using XQuery and Saxon.","deprecated":false,"firstVersion":"1.0.0","label":"transformation","javaType":"org.apache.camel.component.xquery.XQueryComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-saxon","version":"4.18.0","scheme":"xquery","extendsScheme":"","syntax":"xquery:resourceUri","async":false,"api":false,"consumerOnly":false,"produc [...]
+,
+{"component":{"kind":"component","name":"xslt","title":"XSLT","description":"Transforms XML payload using an XSLT template.","deprecated":false,"firstVersion":"1.3.0","label":"core,transformation","javaType":"org.apache.camel.component.xslt.XsltComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xslt","version":"4.18.0","scheme":"xslt","extendsScheme":"","syntax":"xslt:resourceUri","async":false,"api":false,"consumerOnly":false,"producerOnly":true,"lenient [...]
+,
+{"component":{"kind":"component","name":"xslt-saxon","title":"XSLT Saxon","description":"Transform XML payloads using an XSLT template using Saxon.","deprecated":false,"firstVersion":"3.0.0","label":"core,transformation","javaType":"org.apache.camel.component.xslt.saxon.XsltSaxonComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-xslt-saxon","version":"4.18.0","scheme":"xslt-saxon","extendsScheme":"","syntax":"xslt-saxon:resourceUri","async":false,"api":fa [...]
+,
+{"component":{"kind":"component","name":"zeebe","title":"Zeebe","description":"Zeebe component which integrates with Camunda Zeebe to interact with the API.","deprecated":false,"firstVersion":"3.21.0","label":"workflow,saas","javaType":"org.apache.camel.component.zeebe.ZeebeComponent","supportLevel":"Preview","groupId":"org.apache.camel","artifactId":"camel-zeebe","version":"4.18.0","scheme":"zeebe","extendsScheme":"","syntax":"zeebe:operationName","async":false,"api":false,"consumerOnly [...]
+,
+{"component":{"kind":"component","name":"zendesk","title":"Zendesk","description":"Manage Zendesk tickets, users, organizations, etc.","deprecated":false,"firstVersion":"2.19.0","label":"cloud,api,saas","javaType":"org.apache.camel.component.zendesk.ZendeskComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-zendesk","version":"4.18.0","scheme":"zendesk","extendsScheme":"","syntax":"zendesk:methodName","async":false,"api":true,"apiSyntax":"methodName","cons [...]
+,
+{"component":{"kind":"component","name":"zookeeper","title":"ZooKeeper","description":"Manage ZooKeeper clusters.","deprecated":false,"firstVersion":"2.9.0","label":"clustering,management,bigdata","javaType":"org.apache.camel.component.zookeeper.ZooKeeperComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-zookeeper","version":"4.18.0","scheme":"zookeeper","extendsScheme":"","syntax":"zookeeper:serverUrls/path","async":false,"api":false,"consumerOnly":false [...]
+,
+{"component":{"kind":"component","name":"zookeeper-master","title":"ZooKeeper Master","description":"Have only a single consumer in a cluster consuming from a given endpoint; with automatic failover if the JVM dies.","deprecated":false,"firstVersion":"2.19.0","label":"clustering,management,bigdata","javaType":"org.apache.camel.component.zookeepermaster.MasterComponent","supportLevel":"Stable","groupId":"org.apache.camel","artifactId":"camel-zookeeper-master","version":"4.18.0","scheme":" [...]
+]
\ No newline at end of file
diff --git a/karavan-app/src/main/resources/metadata/kamelets.yaml b/karavan-app/src/main/resources/metadata/kamelets.yaml
new file mode 100644
index 00000000..14673930
--- /dev/null
+++ b/karavan-app/src/main/resources/metadata/kamelets.yaml
@@ -0,0 +1,22588 @@
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: avro-deserialize-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Avro Deserialize Action"
+ description: "Deserialize payload to Avro."
+ type: object
+ properties:
+ schema:
+ title: Schema
+ description: The Avro schema to use during serialization (as single-line, using JSON format)
+ type: string
+ example: '{"type": "record", "namespace": "com.example", "name": "FullName", "fields": [{"name": "first", "type": "string"},{"name": "last", "type": "string"}]}'
+ validate:
+ title: Validate
+ description: Indicates if the content must be validated against the schema
+ type: boolean
+ default: true
+ dependencies:
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jackson-avro"
+ template:
+ beans:
+ - name: schemaResolver
+ type: "#class:org.apache.camel.component.jackson.avro.transform.AvroSchemaResolver"
+ properties:
+ validate: "{{validate}}"
+ schema: "{{schema:}}"
+ from:
+ uri: kamelet:source
+ steps:
+ - unmarshal:
+ avro:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ schemaResolver: "#bean:{{schemaResolver}}"
+ - removeHeader:
+ name: "Content-Type"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: avro-serialize-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Avro Serialize Action"
+ description: "Serialize payload to Avro."
+ type: object
+ properties:
+ schema:
+ title: Schema
+ description: The Avro schema to use during serialization (as single-line, using JSON format)
+ type: string
+ example: '{"type": "record", "namespace": "com.example", "name": "FullName", "fields": [{"name": "first", "type": "string"},{"name": "last", "type": "string"}]}'
+ validate:
+ title: Validate
+ description: Indicates if the content must be validated against the schema
+ type: boolean
+ default: true
+ dependencies:
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jackson-avro"
+ template:
+ beans:
+ - name: schemaResolver
+ type: "#class:org.apache.camel.component.jackson.avro.transform.AvroSchemaResolver"
+ properties:
+ validate: "{{validate}}"
+ schema: "{{schema:}}"
+ from:
+ uri: kamelet:source
+ steps:
+ - marshal:
+ avro:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ schemaResolver: "#bean:{{schemaResolver}}"
+ - setHeader:
+ name: "Content-Type"
+ constant: "application/avro"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-bedrock-agent-runtime-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQzMC40MiwxOTYuMzJjOC0xMS4zOSwyMS4xNS0zOC4zMywwLTcyLjEzYTUyLjc5LDUyLjc5LDAsMCwwLTE3LjA2LTE3LjMxYy0xLjUzLTgtNy41NC0yNy4yNi0zMS40Mi00My45MUMzNTksNDcsMzI1LjUyLDQ5LjUzLDMxOS40NCw1MC4xNmE2NC4yNyw2NC4yNywwLDAsMC0xNi4wNy0yLjk0Yy0xNy4xNy0uODEtMzAuMzcsMy44OS0zOS43OCwxNC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Bedrock"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Bedrock Agent Runtime Sink"
+ description: Send data for invoking a knowledge base from AWS Bedrock.
+ required:
+ - modelId
+ - knowledgeBaseId
+ - region
+ type: object
+ properties:
+ modelId:
+ title: Model Id
+ description: The model Id to be used to generate responses.
+ type: string
+ enum: ["anthropic.claude-instant-v1", "anthropic.claude-v2", "anthropic.claude-v2:1", "anthropic.claude-3-sonnet-20240229-v1:0"]
+ knowledgeBaseId:
+ title: Knowledge Base Id
+ description: The Knowledge Base Id to be used to retrieve and generate responses.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["us-east-1", "us-west-1"]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Bedrock client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Bedrock client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Bedrock client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Bedrock.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws-bedrock"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "aws-bedrock-agent-runtime:bedrock-knowledge"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ modelId: "{{modelId}}"
+ knowledgeBaseId: "{{knowledgeBaseId}}"
+ operation: retrieveAndGenerate
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-bedrock-text-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQzMC40MiwxOTYuMzJjOC0xMS4zOSwyMS4xNS0zOC4zMywwLTcyLjEzYTUyLjc5LDUyLjc5LDAsMCwwLTE3LjA2LTE3LjMxYy0xLjUzLTgtNy41NC0yNy4yNi0zMS40Mi00My45MUMzNTksNDcsMzI1LjUyLDQ5LjUzLDMxOS40NCw1MC4xNmE2NC4yNyw2NC4yNywwLDAsMC0xNi4wNy0yLjk0Yy0xNy4xNy0uODEtMzAuMzcsMy44OS0zOS43OCwxNC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Bedrock"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Bedrock Text Sink"
+ description: Send data for invoking a text model of Amazon Bedrock.
+ required:
+ - modelId
+ - region
+ type: object
+ properties:
+ modelId:
+ title: Model Id
+ description: The model Id to be used.
+ type: string
+ enum: ["amazon.titan-text-express-v1", "amazon.titan-text-lite-v1", "ai21.j2-ultra-v1", "ai21.j2-mid-v1", "anthropic.claude-instant-v1", "anthropic.claude-v2", "anthropic.claude-v2:1", "anthropic.claude-3-sonnet-20240229-v1:0"]
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["us-east-1", "us-west-1", "ap-southeast-1", "ap-northeast-1", "eu-central-1"]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Bedrock client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Bedrock client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Bedrock client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Bedrock.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws-bedrock"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - setHeader:
+ name: "CamelAwsBedrockContentType"
+ constant: "application/json"
+ - setHeader:
+ name: "CamelAwsBedrockAcceptContentType"
+ constant: "application/json"
+ - to:
+ uri: "aws-bedrock:bedrock-text"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ modelId: "{{modelId}}"
+ operation: invokeTextModel
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-cloudtrail-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzQuMzc1IDg1IiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48dXNlIHhsaW5rOmhyZWY9IiNBIiB4PSIyLjE4OCIgeT0iMi41Ii8+PHN5bWJvbCBpZD0iQSIgb3ZlcmZsb3c9InZpc2libGUiPjxnIHN0cm9rZT0ibm9uZSI+PHBhdGggZD0iTTkuOTY2IDM1LjQ5M2wtMi4yODguMT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Cloudtrail"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS Cloudtrail Source"
+ description: Receive data from an AWS Cloudtrail.
+ required:
+ - region
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Cloudtrail client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Cloudtrail client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the CloudTrail client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in CloudTrail.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ maxResults:
+ title: Max Results
+ description: Maximum number of records that are fetched in each poll.
+ type: integer
+ default: 1
+ eventSource:
+ title: Event Source
+ description: Specify an event source to select events.
+ type: string
+ example: secretsmanager.amazonaws.com
+ dataTypes:
+ out:
+ default: text
+ headers:
+ CamelAwsCloudTrailEventId:
+ title: Cloudtrail Event Id
+ description: The event ID of the cloud trail event consumed
+ type: string
+ CamelAwsCloudTrailEventName:
+ title: Cloudtrail Event Name
+ description: The event Name of the cloud trail event consumed
+ type: string
+ CamelAwsCloudTrailEventSource:
+ title: Cloudtrail Event Source
+ description: The event Source of the cloud trail event consumed
+ type: string
+ CamelAwsCloudTrailEventUsername:
+ title: Cloudtrail Event Username
+ description: The associated username of the event of the cloud trail event consumed
+ type: string
+ types:
+ text:
+ format: "text-plain"
+ description: Default text representation of the Cloudtrail Event
+ mediaType: text/plain
+ cloudevents:
+ format: "aws-cloudtrail:application-cloudevents"
+ description: Data type transformer converts AWS Cloudtrail lookup events response to CloudEvent v1_0 data format. The data type sets Camel specific CloudEvent headers with values extracted from AWS Cloudtrail lookup events response.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.aws.cloudtrail.lookupEvents"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the Cloudtrail event source name with prefix "aws.cloudtrail.event.source.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. The Cloudtrail Event Id.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:aws-cloudtrail"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "aws-cloudtrail:cloudtrail"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ eventSource: "{{?eventSource}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ maxResults: "{{maxResults}}"
+ steps:
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-cloudwatch-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIwNyIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI5MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTI1NiAxOTkuMzA1bC0xMjcuOTU3LTE4Ljc5N0wwIDE5OS4zMjlsMTI4LjAxIDQ3LjQzOUwyNTYgMTk5LjMwNSIgZmlsbD0iI0I3Q0E5RCIvPjxwYXRoIGQ9Ik0yNS42MjEgMTk3LjExM2wyMS42MyA2Ljc2MSAxLjk3MS0yLjIzOFY1MC4yODRsLTEuOTcxLTIuNTg1LTIxLjYzIDguMjc0djE0MS4xNCIgZmlsbD0iIzRCNjEyQyIvPjxwYXRoIG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Cloudwatch"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS CloudWatch Metrics Sink"
+ description: Send data to Amazon CloudWatch metrics.
+ required:
+ - cwNamespace
+ - region
+ type: object
+ properties:
+ cwNamespace:
+ title: Cloud Watch Namespace
+ description: The CloudWatch metric namespace.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Cloudwatch client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Cloudwatch client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Cloudwatch client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Cloudwatch.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-cw"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[metric-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricName
+ simple: "${header[metric-name]}"
+ - simple: "${header[ce-metricname]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricName
+ simple: "${header[ce-metricname]}"
+ - choice:
+ when:
+ - simple: "${header[metric-value]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricValue
+ simple: "${header[metric-value]}"
+ - simple: "${header[ce-metricvalue]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricValue
+ simple: "${header[ce-metricvalue]}"
+ - choice:
+ when:
+ - simple: "${header[metric-unit]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricUnit
+ simple: "${header[metric-unit]}"
+ - simple: "${header[ce-metricunit]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricUnit
+ simple: "${header[ce-metricunit]}"
+ - choice:
+ when:
+ - simple: "${header[metric-timestamp]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricTimestamp
+ simple: "${header[metric-timestamp]}"
+ - simple: "${header[ce-metrictimestamp]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricTimestamp
+ simple: "${header[ce-metrictimestamp]}"
+ - choice:
+ when:
+ - simple: "${header[metric-dimension-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricDimensionName
+ simple: "${header[metric-dimension-name]}"
+ - simple: "${header[ce-metricdimensionname]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricDimensionName
+ simple: "${header[ce-metricdimensionname]}"
+ - choice:
+ when:
+ - simple: "${header[metric-dimension-value]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricDimensionValue
+ simple: "${header[metric-dimension-value]}"
+ - simple: "${header[ce-metricdimensionvalue]}"
+ steps:
+ - setHeader:
+ name: CamelAwsCwMetricDimensionValue
+ simple: "${header[ce-metricdimensionvalue]}"
+ - to:
+ uri: "aws2-cw:{{cwNamespace}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-comprehend-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQzMC40MiwxOTYuMzJjOC0xMS4zOSwyMS4xNS0zOC4zMywwLTcyLjEzYTUyLjc5LDUyLjc5LDAsMCwwLTE3LjA2LTE3LjMxYy0xLjUzLTgtNy41NC0yNy4yNi0zMS40Mi00My45MUMzNTksNDcsMzI1LjUyLDQ5LjUzLDMxOS40NCw1MC4xNmE2NC4yNyw2NC4yNywwLDAsMC0xNi4wNy0yLjk0Yy0xNy4xNy0uODEtMzAuMzcsMy44OS0zOS43OCwxNC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Comprehend"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Comprehend Sink"
+ description: Send data to AWS Comprehend for natural language processing.
+ required:
+ - region
+ type: object
+ properties:
+ operation:
+ title: Operation
+ description: The operation to perform on the input text.
+ type: string
+ default: detectDominantLanguage
+ enum: ["detectDominantLanguage", "detectEntities", "detectKeyPhrases", "detectSentiment", "detectSyntax", "detectPiiEntities", "detectToxicContent", "classifyDocument", "containsPiiEntities"]
+ languageCode:
+ title: Language Code
+ description: The language code of the input text. Required for all operations except detectDominantLanguage. Use a 2-letter ISO 639-1 code (e.g., 'en' for English, 'es' for Spanish).
+ type: string
+ endpointArn:
+ title: Endpoint ARN
+ description: The Amazon Resource Name (ARN) of the endpoint to use for document classification. Required for classifyDocument operation.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Comprehend client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Comprehend client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Comprehend client should expect to use Session Credentials. This is useful in a situation in which the user needs to assume an IAM role for doing operations in Comprehend.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume an IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-comprehend"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "aws2-comprehend:comprehend"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ operation: "{{operation}}"
+ languageCode: "{{?languageCode}}"
+ endpointArn: "{{?endpointArn}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-ddb-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEwMCIgd2lkdGg9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMkQ3MkI4IiBkPSJNNzQuMTc0IDMxLjgwN2w3LjQzNyA1LjM2N3YtNy42MDJsLTcuNDgtOC43NjV2MTAuOTU3bC4wNDMuMDE1eiIvPjxwYXRoIGZpbGw9IiM1Mjk0Q0YiIGQ9Ik01OS44MzggODUuNjY2bDE0LjI5My03LjE0NlYyMC43OTFsLTE0LjMwMy03LjEyNHoiLz48cGF0aCBmaWxsPSIjMjA1Qjk4IiBkPSJNMzkuNDk2IDg1LjY2NkwyNS4yMDMgNzguNTJWMjAuNzkxbDE0LjMwMy03LjEyNHoiLz48cGF0aCBmaWxsPSIjMkQ3Mk [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS DynamoDB Streams"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS DynamoDB Sink"
+ description: Send data to Amazon DynamoDB. The sent data inserts, updates, or deletes an item on the specified AWS DynamoDB table.
+ required:
+ - table
+ - region
+ type: object
+ properties:
+ table:
+ title: Table
+ description: The name of the DynamoDB table.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ operation:
+ title: Operation
+ description: "The operation to perform."
+ type: string
+ enum: ["PutItem", "UpdateItem", "DeleteItem"]
+ default: PutItem
+ example: PutItem
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the DynamoDB client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the DynamoDB client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the DynamoDB client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in DynamoDB.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dataTypes:
+ in:
+ default: json
+ types:
+ json:
+ format: "aws2-ddb:application-json"
+ description: Json representation of a DDB operation. The input type supports the operations PutItem, UpdateItem, DeleteItem. For PutItem operation the Json body defines all item attributes. For DeleteItem operation the Json body defines only the primary key attributes that identify the item to delete. For UpdateItem operation the Json body defines both key attributes to identify the item to be updated and all item attributes that get updated on the item.
+ headers:
+ CamelAwsDdbOperation:
+ title: Operation
+ description: "The operation to perform. Overwrites the operation given in the Json body. One of PutItem, UpdateItem, DeleteItem."
+ default: PutItem
+ type: string
+ CamelAwsDdbReturnValues:
+ title: Return Values
+ description: Use this parameter if you want to get the attribute name-value pairs before or after they are modified. Possible values are NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW.
+ type: string
+ mediaType: application/json
+ schema:
+ type: object
+ required: [ "key" ]
+ properties:
+ operation:
+ type: string
+ description: The operator to perform. One of PutItem, UpdateItem, DeleteItem
+ key:
+ type: object
+ description: The primary key specifies the selection criteria for the query.
+ item:
+ type: object
+ description: Attribute value map specifies all attributes to change with the given operation.
+ dependencies:
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:aws2-ddb"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - setProperty:
+ name: operation
+ constant: "{{operation}}"
+ - transform:
+ toType: "aws2-ddb:application-json"
+ - to:
+ uri: "aws2-ddb:{{table}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ operation: "{{operation}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-ddb-streams-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEwMCIgd2lkdGg9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjMkQ3MkI4IiBkPSJNNzQuMTc0IDMxLjgwN2w3LjQzNyA1LjM2N3YtNy42MDJsLTcuNDgtOC43NjV2MTAuOTU3bC4wNDMuMDE1eiIvPjxwYXRoIGZpbGw9IiM1Mjk0Q0YiIGQ9Ik01OS44MzggODUuNjY2bDE0LjI5My03LjE0NlYyMC43OTFsLTE0LjMwMy03LjEyNHoiLz48cGF0aCBmaWxsPSIjMjA1Qjk4IiBkPSJNMzkuNDk2IDg1LjY2NkwyNS4yMDMgNzguNTJWMjAuNzkxbDE0LjMwMy03LjEyNHoiLz48cGF0aCBmaWxsPSIjMkQ3Mk [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS DynamoDB Streams"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS DynamoDB Streams Source"
+ description: Receive events from Amazon DynamoDB Streams.
+ required:
+ - table
+ - region
+ type: object
+ properties:
+ table:
+ title: Table
+ description: The name of the DynamoDB table.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ streamIteratorType:
+ title: Stream Iterator Type
+ description: Defines where in the DynamoDB stream to start getting records. There are two enums and the value can be one of FROM_LATEST and FROM_START. Note that using FROM_START can cause a significant delay before the stream has caught up to real-time.
+ type: string
+ default: FROM_LATEST
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If `true`, the DynamoDB client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the DynamoDB client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the DynamoDB client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in DynamoDB.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll from the database.
+ type: integer
+ default: 500
+ dataTypes:
+ out:
+ default: json
+ headers:
+ CamelAwsDdbStreamEventSource:
+ title: The DDB Stream Event Source
+ description: The Amazon Web Services service from which the stream record originated. For DynamoDB Streams, this is aws:dynamodb.
+ type: string
+ CamelAwsDdbStreamEventId:
+ title: The DDB Stream Event Id
+ description: A globally unique identifier for the event that was recorded in this stream record.
+ type: string
+ types:
+ json:
+ format: "application-json"
+ description: Default Json representation of a DDB Stream Event.
+ mediaType: application/json
+ cloudevents:
+ format: "aws2-ddbstream:application-cloudevents"
+ description: Data type transformer converts AWS Dynamo DB Streams get records response to CloudEvent v1_0 data format. The data type sets Camel specific CloudEvent headers with values extracted from AWS Dynamo DB Streams get records.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id.
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type.
+ default: "org.apache.camel.event.aws.ddbstream.getRecords"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the DDB Stream Event source receipt handle with prefix "aws.ddbstream.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. The DDB Stream Event Id.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:gson"
+ - "camel:aws2-ddb"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "aws2-ddbstream:{{table}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ streamIteratorType: "{{streamIteratorType}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ delay: "{{delay}}"
+ steps:
+ - transform:
+ toType: "aws2-ddb:application-x-struct"
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-ec2-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjA2NSIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDMxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTQyLjc1NCAyNDQuNDk1bC0yOS45MTggNi44MjZWNTcuNTY1bDI5LjkxOCA2LjgzOXYxODAuMDkxIiBmaWxsPSIjRjY4NTM2Ii8+PHBhdGggZD0iTTgwLjA4MiAyNTUuOTMxbC0zNy4zMjggMTAuNjA4VjQyLjYxMmwzNy4zMjggMTAuNTk1djIwMi43MjRNMTI3Ljk2NiAyNjcuNjgxbC00Ny44ODQgMTcuNTI0VjIzLjk0Nmw0Ny44ODQgMTcuNT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS EC2"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS EC2 Sink"
+ description: Check the status of EC2 instances
+ required:
+ - region
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the EC2 client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the EC2 client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the EC2 client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in EC2.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-ec2"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[instanceIds]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEC2InstancesIds
+ simple: "${header[instanceIds]}"
+ - simple: "${header[ce-instanceids]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEC2InstancesIds
+ simple: "${header[ce-instanceids]}"
+ - to:
+ uri: "aws2-ec2:ec2-route"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ operation: "describeInstancesStatus"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-eventbridge-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMWVtIiBoZWlnaHQ9IjFlbSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIgdmlld0JveD0iMCAwIDI1NiAyNTYiIHN0eWxlPSItbXMtdHJhbnNmb3JtOiByb3RhdGUoMzYwZGVnKTsgLXdlYmtpdC10cmFuc2Zvcm06IHJvdGF0ZSgzNjBkZWcpOyB0cmFuc2Zvcm06IHJvdGF0ZSgzNjBkZWcpOyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJJY29uaWZ5SWQtMTgyM2Y2NTU1NjktYWYxZGQ1LT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Eventbridge"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Eventbridge Sink"
+ description: Send events to an Amazon Eventbridge Eventbus.
+
+ In the headers, you can set the `resources-arn` / `ce-resources-arn` property to specify the ARN of resources related to the event.
+
+ In the headers, you can set the `detail-type` / `ce-detail-type` property to specify the detail type related to the event.
+
+ In the headers, you can set the `event-source` / `ce-event-source` property to specify the event source related to the event.
+
+ If you do not set the property in the header, the Kamelet uses the given Kamelet properties as a default.
+ required:
+ - eventbusNameOrArn
+ - region
+ type: object
+ properties:
+ eventbusNameOrArn:
+ title: Eventbus Name
+ description: The Eventbridge Eventbus name or Amazon Resource Name (ARN).
+ type: string
+ resourcesArn:
+ title: Event Resource ARN
+ description: The ARN of resources related to the AWS event (e.g. `arn:aws:s3:eu-east-1:000000000001:test`).
+ type: string
+ eventSourcePrefix:
+ title: Event Source Prefix
+ description: The event source prefix set for all events sent to the eventbus.
+ type: string
+ default: ""
+ eventSource:
+ title: Event Source
+ description: The event source related to the AWS event (e.g. `aws.s3`).
+ type: string
+ detailType:
+ title: Event Detail Type
+ description: The event detail type related to the AWS event.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Eventbridge client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Eventbridge client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Eventbridge client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Eventbridge.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-eventbridge"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[resources-arn]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeResourcesArn
+ simple: "${header[resources-arn]}"
+ - simple: "${header[ce-resources-arn]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeResourcesArn
+ simple: "${header[ce-resources-arn]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeResourcesArn
+ simple: "{{?resourcesArn}}"
+ - choice:
+ when:
+ - simple: "${header[detail-type]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeDetailType
+ simple: "${header[detail-type]}"
+ - simple: "${header[ce-detail-type]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeDetailType
+ simple: "${header[ce-detail-type]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeDetailType
+ simple: "{{?detailType}}"
+ - choice:
+ when:
+ - simple: "${header[event-source]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeSource
+ simple: "{{?eventSourcePrefix}}${header[event-source]}"
+ - simple: "${header[ce-event-source]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeSource
+ simple: "{{?eventSourcePrefix}}${header[ce-event-source]}"
+ - simple: "${header[ce-source]}"
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeSource
+ simple: "{{?eventSourcePrefix}}${header[ce-source]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsEventbridgeSource
+ simple: "{{?eventSourcePrefix}}{{?eventSource}}"
+ - to:
+ uri: "aws2-eventbridge:{{eventbusNameOrArn}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ operation: "putEvent"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-kinesis-firehose-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgODUgODUiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9IjIuNSIgeT0iMi41Ii8+PHN5bWJvbCBpZD0iQSIgb3ZlcmZsb3c9InZpc2libGUiPjxnIHN0cm9rZT0ibm9uZSI+PHBhdGggZD0iTTEzLjc2NiAzLjEyaDUyLjQ2OGMzLjY1MSAwID [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Kinesis Firehose"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Kinesis Firehose Sink"
+ description: Send message to an AWS Kinesis Firehose Stream.
+ required:
+ - streamName
+ - region
+ type: object
+ properties:
+ streamName:
+ title: Stream Name
+ description: The name of the stream we want to send to data to.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the Kinesis Firehose client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Kinesis Firehose client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Kinesis Firehose client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Kinesis Firehose.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-kinesis"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to:
+ uri: "aws2-kinesis-firehose:{{streamName}}"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-kinesis-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTYgMzA4LjIzNDAxIj48dGl0bGU+YXdzLWtpbmVzaXM8L3RpdGxlPjxwYXRoIGQ9Ik0wLDE3Mi4wODdsMTI3Ljc1NCw1OC44MSwxMjcuNzUyLTU4LjgxLTEyNy43NTItNS4yOTNaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuMDAwMDUpIiBmaWxsPSIjZmNiZjkyIi8+PHBhdGggZD0iTTEyOC4xNDcsMCwuMDU5LDYzLjg4MXY5MC4xMzZIMTUzLjY0OFYxMi43NTFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuMD [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Kinesis"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Kinesis Sink"
+ description: Send data to AWS Kinesis.
+ required:
+ - stream
+ - region
+ type: object
+ properties:
+ stream:
+ title: Stream Name
+ description: The Kinesis stream that you want to access. The Kinesis stream that you specify must already exist.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Kinesis client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Kinesis client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Kinesis client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Kinesis.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ types:
+ in:
+ mediaType: application/octet-stream
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-kinesis"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[partition]}"
+ steps:
+ - setHeader:
+ name: CamelAwsKinesisPartitionKey
+ simple: "${header[partition]}"
+ - simple: "${header[ce-partition]}"
+ steps:
+ - setHeader:
+ name: CamelAwsKinesisPartitionKey
+ simple: "${header[ce-partition]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsKinesisPartitionKey
+ simple: "${exchangeId}"
+ - choice:
+ when:
+ - simple: "${header[sequence-number]}"
+ steps:
+ - setHeader:
+ name: CamelAwsKinesisSequenceNumber
+ simple: "${header[sequence-number]}"
+ - simple: "${header[ce-sequencenumber]}"
+ steps:
+ - setHeader:
+ name: CamelAwsKinesisSequenceNumber
+ simple: "${header[ce-sequencenumber]}"
+ - to:
+ uri: "aws2-kinesis:{{stream}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-kinesis-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTYgMzA4LjIzNDAxIj48dGl0bGU+YXdzLWtpbmVzaXM8L3RpdGxlPjxwYXRoIGQ9Ik0wLDE3Mi4wODdsMTI3Ljc1NCw1OC44MSwxMjcuNzUyLTU4LjgxLTEyNy43NTItNS4yOTNaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuMDAwMDUpIiBmaWxsPSIjZmNiZjkyIi8+PHBhdGggZD0iTTEyOC4xNDcsMCwuMDU5LDYzLjg4MXY5MC4xMzZIMTUzLjY0OFYxMi43NTFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuMD [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Kinesis"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS Kinesis Source"
+ description: Receive data from AWS Kinesis.
+ required:
+ - stream
+ - region
+ type: object
+ properties:
+ stream:
+ title: Stream Name
+ description: The Kinesis stream that you want to access. The Kinesis stream that you specify must already exist.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Kinesis client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Kinesis client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Kinesis client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Kinesis.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected stream.
+ type: integer
+ default: 500
+ asyncClient:
+ title: Async Client
+ description: If we want a KinesisAsyncClient instance set it to true.
+ type: boolean
+ default: false
+ useKclConsumers:
+ title: KCL Consumer
+ description: If we want to a KCL Consumer set it to true
+ type: boolean
+ default: false
+ kclDisableCloudwatchMetricsExport:
+ title: KCL Disable Cloudwatch Metrics Export
+ description: Define if we want to use a KCL Consumer and disable the CloudWatch Metrics Export
+ type: boolean
+ default: false
+ types:
+ out:
+ mediaType: application/octet-stream
+ dependencies:
+ - "camel:aws2-kinesis"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: aws2-kinesis:{{stream}}
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ delay: "{{delay}}"
+ useKclConsumers: "{{useKclConsumers}}"
+ asyncClient: "{{asyncClient}}"
+ kclDisableCloudwatchMetricsExport: "{{kclDisableCloudwatchMetricsExport}}"
+ steps:
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-lambda-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjA2NSIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDMxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTAgMjQ1LjI2MmwxNi4zMjIgOC4xNjFMMTkgMjQ4LjY2OFY1OS4zMzNsLTIuNjc4LTMuNDk0TDAgNjR2MTgxLjI2MiIgZmlsbD0iIzlENTAyNSIvPjxwYXRoIGQ9Ik00Ny42NzggNjMuNTdsLTMxLjM1Ni03LjczMXYxOTcuNTg0bDMxLjM1Ni03LjMwMlY2My41NyIgZmlsbD0iI0Y2ODUzNiIvPjxwYXRoIGQ9Ik0xNDMuODkzIDc4LjYwNGwyMi [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Lambda"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Lambda Sink"
+ description: Send a payload to an AWS Lambda function.
+ required:
+ - function
+ - region
+ type: object
+ properties:
+ function:
+ title: Function Name
+ description: The Lambda Function name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Lambda client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Lambda client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Lambda client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Lambda.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:aws2-lambda"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to:
+ uri: "aws2-lambda:{{function}}"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-polly-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiBpZD0iTGF5ZXJfMSIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQzMC40MiwxOTYuMzJjOC0xMS4zOSwyMS4xNS0zOC4zMywwLTcyLjEzYTUyLjc5LDUyLjc5LDAsMCwwLTE3LjA2LTE3LjMxYy0xLjUzLTgtNy41NC0yNy4yNi0zMS40Mi00My45MUMzNTksNDcsMzI1LjUyLDQ5LjUzLDMxOS40NCw1MC4xNmE2NC4yNyw2NC4yNywwLDAsMC0xNi4wNy0yLjk0Yy0xNy4xNy0uODEtMzAuMzcsMy44OS0zOS43OCwxNC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Polly"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Polly Sink"
+ description: Synthesize speech from text using AWS Polly.
+ required:
+ - region
+ type: object
+ properties:
+ voiceId:
+ title: Voice Id
+ description: The voice ID to use for speech synthesis (e.g., Joanna, Matthew, Amy, Brian).
+ type: string
+ outputFormat:
+ title: Output Format
+ description: The audio format in which the resulting stream will be encoded.
+ type: string
+ default: MP3
+ enum: ["MP3", "OggVorbis", "Pcm", "Json"]
+ textType:
+ title: Text Type
+ description: Specifies whether the input text is plain text or SSML.
+ type: string
+ default: TEXT
+ enum: ["TEXT", "SSML"]
+ engine:
+ title: Engine
+ description: Specifies the engine (standard, neural, long-form, generative) for Amazon Polly to use when processing input text for speech synthesis.
+ type: string
+ enum: ["standard", "neural", "long-form", "generative"]
+ sampleRate:
+ title: Sample Rate
+ description: The audio frequency in Hz.
+ type: string
+ languageCode:
+ title: Language Code
+ description: Optional language code for voice synthesis. This is only necessary if using a bilingual voice.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the Polly client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Polly client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Polly client should expect to use Session Credentials. This is useful in a situation in which the user needs to assume an IAM role for doing operations in Polly.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume an IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-polly"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "aws2-polly:polly"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ operation: synthesizeSpeech
+ voiceId: "{{?voiceId}}"
+ outputFormat: "{{outputFormat}}"
+ textType: "{{textType}}"
+ engine: "{{?engine}}"
+ sampleRate: "{{?sampleRate}}"
+ languageCode: "{{?languageCode}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-redshift-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxNjE1IDE3ODMuNyIgdmlld0JveD0iMCAwIDE2MTUgMTc4My43IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im04MDcuNSAxMzYzLjggNjc4LjMgMTYxLjV2LTEyNzAuNWwtNjc4LjMgMTYxLjV6IiBmaWxsPSIjMjA1Yjk3Ii8+PHBhdGggZD0ibTE0ODUuOCAyNTQuOCAxMjkuMiA2NC42djExNDEuM2wtMTI5LjIgNjQuNnptLTY3OC4zIDExMDktNjc4LjMgMTYxLjV2LTEyNzAuNWw2NzguMyAxNjEuNXoiIGZpbGw9IiM1MTkzY2UiLz48cGF0aCBkPSJtMTI5LjIgMjU0LjgtMTI5Lj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Redshift"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Redshift Sink"
+ description: Send data to an AWS Redshift Database. This Kamelet expects a JSON-formatted body. Use key:value pairs to map the JSON fields and parameters.
+ required:
+ - serverName
+ - username
+ - password
+ - query
+ - databaseName
+ type: object
+ properties:
+ serverName:
+ title: Server Name
+ description: The server name for the data source.
+ type: string
+ example: localhost
+ serverPort:
+ title: Server Port
+ description: The server port for the AWS RedShi data source.
+ type: string
+ default: 5439
+ username:
+ title: Username
+ description: The username to access a secured AWS Redshift Database.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password to access a secured AWS Redshift Database.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ query:
+ title: Query
+ description: The query to execute against the AWS Redshift Database.
+ type: string
+ example: 'INSERT INTO accounts (username,city) VALUES (:#username,:#city)'
+ databaseName:
+ title: Database Name
+ description: The name of the AWS RedShift Database.
+ type: string
+ types:
+ in:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:sql"
+ - "mvn:com.amazon.redshift:redshift-jdbc42:2.2.4"
+ - "mvn:org.apache.commons:commons-dbcp2:2.14.0"
+ template:
+ beans:
+ - name: local-sql-redshift-sink
+ type: "#class:org.apache.camel.component.sql.SqlComponent"
+ properties:
+ autowiredEnabled: "false"
+ - name: dsBean
+ type: "#class:org.apache.commons.dbcp2.BasicDataSource"
+ properties:
+ username: '{{username}}'
+ password: '{{password}}'
+ url: 'jdbc:redshift://{{serverName}}:{{serverPort}}/{{databaseName}}'
+ driverClassName: 'com.amazon.redshift.jdbc.Driver'
+ from:
+ uri: "kamelet:source"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - to:
+ uri: "{{local-sql-redshift-sink}}:{{query}}"
+ parameters:
+ dataSource: "#bean:{{dsBean}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-redshift-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxNjE1IDE3ODMuNyIgdmlld0JveD0iMCAwIDE2MTUgMTc4My43IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im04MDcuNSAxMzYzLjggNjc4LjMgMTYxLjV2LTEyNzAuNWwtNjc4LjMgMTYxLjV6IiBmaWxsPSIjMjA1Yjk3Ii8+PHBhdGggZD0ibTE0ODUuOCAyNTQuOCAxMjkuMiA2NC42djExNDEuM2wtMTI5LjIgNjQuNnptLTY3OC4zIDExMDktNjc4LjMgMTYxLjV2LTEyNzAuNWw2NzguMyAxNjEuNXoiIGZpbGw9IiM1MTkzY2UiLz48cGF0aCBkPSJtMTI5LjIgMjU0LjgtMTI5Lj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Redshift"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS Redshift Source"
+ description: Query data from an AWS RedShift Database.
+ required:
+ - serverName
+ - username
+ - password
+ - query
+ - databaseName
+ type: object
+ properties:
+ serverName:
+ title: Server Name
+ description: The server name for the data source.
+ type: string
+ example: localhost
+ serverPort:
+ title: Server Port
+ description: The server port for the data source.
+ type: string
+ default: 5439
+ username:
+ title: Username
+ description: The username to access a secured AWS RedShift Database.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password to access a secured AWS RedShift Database.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ query:
+ title: Query
+ description: The query to execute against the AWS RedShift Database.
+ type: string
+ example: 'INSERT INTO accounts (username,city) VALUES (:#username,:#city)'
+ databaseName:
+ title: Database Name
+ description: The name of the AWS RedShift Database.
+ type: string
+ consumedQuery:
+ title: Consumed Query
+ description: A query to run on a tuple consumed.
+ type: string
+ example: 'DELETE FROM accounts where user_id = :#user_id'
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll from the AWS RedShift database.
+ type: integer
+ default: 500
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:sql"
+ - "mvn:com.amazon.redshift:redshift-jdbc42:2.2.4"
+ - "mvn:org.apache.commons:commons-dbcp2:2.14.0"
+ template:
+ beans:
+ - name: local-sql-redshift-source
+ type: "#class:org.apache.camel.component.sql.SqlComponent"
+ properties:
+ autowiredEnabled: "false"
+ - name: dsBean
+ type: "#class:org.apache.commons.dbcp2.BasicDataSource"
+ properties:
+ username: '{{username}}'
+ password: '{{password}}'
+ url: 'jdbc:redshift://{{serverName}}:{{serverPort}}/{{databaseName}}'
+ driverClassName: 'com.amazon.redshift.jdbc.Driver'
+ from:
+ uri: "{{local-sql-redshift-source}}:{{query}}"
+ parameters:
+ dataSource: "#bean:{{dsBean}}"
+ onConsume: "{{?consumedQuery}}"
+ delay: "{{delay}}"
+ steps:
+ - marshal:
+ json:
+ library: Jackson
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-s3-event-based-source
+ annotations:
+ camel.apache.org/kamelet.support.level: Preview
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: >-
+ data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFRE [...]
+ camel.apache.org/provider: Apache Software Foundation
+ camel.apache.org/kamelet.group: AWS S3 Event-Based
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS S3 Event Based Source"
+ description: Receive data from AWS SQS subscribed to Eventbridge Bus reporting events related to an S3 bucket or multiple buckets.
+ required:
+ - accessKey
+ - secretKey
+ - queueNameOrArn
+ - region
+ type: object
+ properties:
+ queueNameOrArn:
+ title: Queue Name
+ description: The SQS Queue Name or ARN
+ type: string
+ deleteAfterRead:
+ title: Auto-delete Messages
+ description: Delete messages after consuming them
+ type: boolean
+ default: true
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - 'urn:camel:group:credentials'
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - 'urn:camel:group:credentials'
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum:
+ - ap-south-1
+ - eu-south-1
+ - us-gov-east-1
+ - me-central-1
+ - ca-central-1
+ - eu-central-1
+ - us-iso-west-1
+ - us-west-1
+ - us-west-2
+ - af-south-1
+ - eu-north-1
+ - eu-west-3
+ - eu-west-2
+ - eu-west-1
+ - ap-northeast-3
+ - ap-northeast-2
+ - ap-northeast-1
+ - me-south-1
+ - sa-east-1
+ - ap-east-1
+ - cn-north-1
+ - us-gov-west-1
+ - ap-southeast-1
+ - ap-southeast-2
+ - us-iso-east-1
+ - ap-southeast-3
+ - us-east-1
+ - us-east-2
+ - cn-northwest-1
+ - us-isob-east-1
+ - aws-global
+ - aws-cn-global
+ - aws-us-gov-global
+ - aws-iso-global
+ - aws-iso-b-global
+ autoCreateQueue:
+ title: Autocreate Queue
+ description: Setting the autocreation of the SQS queue.
+ type: boolean
+ default: false
+ amazonAWSHost:
+ title: AWS Host
+ description: The hostname of the Amazon AWS cloud.
+ type: string
+ default: amazonaws.com
+ protocol:
+ title: Protocol
+ description: The underlying protocol used to communicate with SQS
+ type: string
+ example: http or https
+ default: https
+ queueURL:
+ title: Queue URL
+ description: The full SQS Queue URL
+ type: string
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: >-
+ The overriding endpoint URI. To use this option, you must also select
+ the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: >-
+ Select this option to override the endpoint URI. To use this option,
+ you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected stream
+ type: integer
+ default: 500
+ greedy:
+ title: Greedy Scheduler
+ description: >-
+ If greedy is enabled, then the polling will happen immediately again,
+ if the previous run polled 1 or more messages.
+ type: boolean
+ default: false
+ getObject:
+ title: Greedy Object in Bucket
+ description: >-
+ If `getObject` is enabled, then the file created in the bucket is
+ retrieved and returned as body. If not, only the event will returned as body.
+ type: boolean
+ default: false
+ dependencies:
+ - 'camel:core'
+ - 'camel:aws2-sqs'
+ - 'camel:aws2-s3'
+ - 'camel:jsonpath'
+ - 'camel:kamelet'
+ - 'camel:jackson'
+ template:
+ from:
+ uri: 'aws2-sqs:{{queueNameOrArn}}'
+ parameters:
+ autoCreateQueue: '{{autoCreateQueue}}'
+ secretKey: '{{?secretKey}}'
+ accessKey: '{{?accessKey}}'
+ region: '{{region}}'
+ deleteAfterRead: '{{deleteAfterRead}}'
+ amazonAWSHost: '{{?amazonAWSHost}}'
+ protocol: '{{?protocol}}'
+ uriEndpointOverride: '{{?uriEndpointOverride}}'
+ overrideEndpoint: '{{overrideEndpoint}}'
+ delay: '{{delay}}'
+ greedy: '{{greedy}}'
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: '${properties:getObject:true}'
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - setProperty:
+ name: s3-event-name
+ jsonpath: $.detail.reason
+ - choice:
+ when:
+ - simple: '${exchangeProperty.s3-event-name} == "PutObject"'
+ steps:
+ - setProperty:
+ name: aws-s3-name
+ jsonpath: $.detail.object.key
+ - setProperty:
+ name: aws-s3-bucket
+ jsonpath: $.detail.bucket.name
+ - toD: >-
+ aws2-s3:${exchangeProperty.aws-s3-bucket}?accessKey={{accessKey}}&secretKey={{secretKey}}®ion={{region}}&operation=getObject&keyName=${exchangeProperty.aws-s3-name}
+ - to: 'kamelet:sink'
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-s3-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAyNDguMiAzMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZT4uc3QyOHtmaWxsOiM4YzMxMjN9LnN0Mjl7ZmlsbDojZTA1MjQzfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MjgiIGQ9Ik0yMCA1Mi4xTDAgNjJ2MTc1LjVsMjAgOS45LjEtLjFWNTIuMmwtLjEtLjEiLz48cGF0aCBjbGFzcz0ic3QyOSIgZD0iTTEyNyAyMjJMMjAgMjQ3LjVWNTIuMUwxMjcgNzd2MTQ1Ii8+PHBhdGggY2xhc3M9InN0MjgiIG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS S3"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS S3 Sink"
+ description: Upload data to an Amazon S3 Bucket.
+ required:
+ - bucketNameOrArn
+ - region
+ type: object
+ properties:
+ bucketNameOrArn:
+ title: Bucket Name
+ description: The S3 Bucket name or Amazon Resource Name (ARN).
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateBucket:
+ title: Autocreate Bucket
+ description: Specifies to automatically create the S3 bucket.
+ type: boolean
+ default: false
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the S3 client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the S3 client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the S3 client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in S3.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ forcePathStyle:
+ title: Force Path Style
+ description: Forces path style when accessing AWS S3 buckets.
+ type: boolean
+ default: false
+ keyName:
+ title: Key Name
+ description: The key name for saving an element in the bucket.
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-s3"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: '${propertiesExist:!keyName}'
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${header[ce-file]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${exchangeId}"
+ - to:
+ uri: "aws2-s3:{{bucketNameOrArn}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ autoCreateBucket: "{{autoCreateBucket}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ forcePathStyle: "{{forcePathStyle}}"
+ keyName: "{{?keyName}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-s3-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAyNDguMiAzMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZT4uc3QyOHtmaWxsOiM4YzMxMjN9LnN0Mjl7ZmlsbDojZTA1MjQzfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MjgiIGQ9Ik0yMCA1Mi4xTDAgNjJ2MTc1LjVsMjAgOS45LjEtLjFWNTIuMmwtLjEtLjEiLz48cGF0aCBjbGFzcz0ic3QyOSIgZD0iTTEyNyAyMjJMMjAgMjQ3LjVWNTIuMUwxMjcgNzd2MTQ1Ii8+PHBhdGggY2xhc3M9InN0MjgiIG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS S3"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS S3 Source"
+ description: Receive data from an Amazon S3 Bucket.
+ required:
+ - bucketNameOrArn
+ - region
+ type: object
+ properties:
+ bucketNameOrArn:
+ title: Bucket Name
+ description: The S3 Bucket name or Amazon Resource Name (ARN).
+ type: string
+ deleteAfterRead:
+ title: Auto-delete Objects
+ description: Specifies to delete objects after consuming them.
+ type: boolean
+ default: true
+ moveAfterRead:
+ title: Move Objects After Delete
+ description: Move objects from S3 bucket to a different bucket after they have been retrieved.
+ type: boolean
+ default: false
+ destinationBucket:
+ title: Destination Bucket
+ description: Define the destination bucket where an object must be moved when moveAfterRead is set to true.
+ type: string
+ destinationBucketPrefix:
+ title: Destination Bucket Prefix
+ description: Define the destination bucket prefix to use when an object must be moved, and moveAfterRead is set to true.
+ type: string
+ destinationBucketSuffix:
+ title: Destination Bucket Suffix
+ description: Define the destination bucket suffix to use when an object must be moved, and moveAfterRead is set to true.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateBucket:
+ title: Autocreate Bucket
+ description: Specifies to automatically create the S3 bucket.
+ type: boolean
+ default: false
+ prefix:
+ title: Prefix
+ description: The AWS S3 bucket prefix to consider while searching.
+ type: string
+ example: 'folder/'
+ ignoreBody:
+ title: Ignore Body
+ description: If true, the S3 Object body is ignored. Setting this to true overrides any behavior defined by the `includeBody` option. If false, the S3 object is put in the body.
+ type: boolean
+ default: false
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the S3 client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the S3 client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the S3 client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in S3.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ forcePathStyle:
+ title: Force Path Style
+ description: Forces path style when accessing AWS S3 buckets.
+ type: boolean
+ default: false
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected bucket.
+ type: integer
+ default: 500
+ maxMessagesPerPoll:
+ title: Max Messages Per Poll
+ description: Gets the maximum number of messages as a limit to poll at each polling. Gets the maximum number of messages as a limit to poll at each polling. The default value is 10. Use 0 or a negative number to set it as unlimited.
+ type: integer
+ default: 10
+ dataTypes:
+ out:
+ default: binary
+ headers:
+ CamelAwsS3BucketName:
+ title: S3 Bucket Name
+ description: The bucket name which has been used to retrieve objects
+ type: string
+ CamelAwsS3Key:
+ title: S3 Key
+ description: The key under which the retrieved object is stored.
+ type: string
+ CamelAwsS3ContentType:
+ title: Content Type
+ description: The content type of the retrieved object.
+ default: application/octet-stream
+ type: string
+ CamelAwsS3ETag:
+ title: ETag Value
+ description: The hex encoded 128-bit MD5 digest of the associated object according to RFC 1864.
+ type: string
+ types:
+ binary:
+ format: "application-octet-stream"
+ description: Default binary representation of the S3 object retrieved from the bucket.
+ mediaType: application/octet-stream
+ cloudevents:
+ format: "aws2-s3:application-cloudevents"
+ description: Output data type represents AWS S3 get object response as CloudEvent V1. The data type sets Camel specific CloudEvent headers on the exchange with respective data from the S3 bucket and its derived object.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.aws.s3.getObject"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the S3 bucket name with prefix "aws.s3.bucket.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. Usually the S3 key.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-s3"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "aws2-s3:{{bucketNameOrArn}}"
+ parameters:
+ autoCreateBucket: "{{autoCreateBucket}}"
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ ignoreBody: "{{ignoreBody}}"
+ deleteAfterRead: "{{deleteAfterRead}}"
+ moveAfterRead: "{{moveAfterRead}}"
+ destinationBucket: "{{?destinationBucket}}"
+ destinationBucketPrefix: "{{?destinationBucketPrefix}}"
+ destinationBucketSuffix: "{{?destinationBucketSuffix}}"
+ prefix: "{{?prefix}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ forcePathStyle: "{{forcePathStyle}}"
+ delay: "{{delay}}"
+ maxMessagesPerPoll: "{{maxMessagesPerPoll}}"
+ steps:
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-s3-streaming-upload-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAyNDguMiAzMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZT4uc3QyOHtmaWxsOiM4YzMxMjN9LnN0Mjl7ZmlsbDojZTA1MjQzfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MjgiIGQ9Ik0yMCA1Mi4xTDAgNjJ2MTc1LjVsMjAgOS45LjEtLjFWNTIuMmwtLjEtLjEiLz48cGF0aCBjbGFzcz0ic3QyOSIgZD0iTTEyNyAyMjJMMjAgMjQ3LjVWNTIuMUwxMjcgNzd2MTQ1Ii8+PHBhdGggY2xhc3M9InN0MjgiIG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS S3"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS S3 Streaming upload Sink"
+ description: Upload data to AWS S3 in streaming upload mode.
+ required:
+ - bucketNameOrArn
+ - region
+ - keyName
+ type: object
+ properties:
+ bucketNameOrArn:
+ title: Bucket Name
+ description: The S3 Bucket name or Amazon Resource Name (ARN).
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateBucket:
+ title: Autocreate Bucket
+ description: Setting the autocreation of the S3 bucket bucketName.
+ type: boolean
+ default: false
+ restartingPolicy:
+ title: Restarting Policy
+ description: The restarting policy to use in streaming upload mode. There are 2 enums and the value can be one of `override`, `lastPart`.
+ type: string
+ default: "lastPart"
+ batchMessageNumber:
+ title: Batch Message Number
+ description: The number of messages composing a batch in streaming upload mode.
+ type: integer
+ default: 10
+ batchSize:
+ title: Batch Size
+ description: The batch size (in bytes) in streaming upload mode.
+ type: integer
+ default: 1000000
+ streamingUploadTimeout:
+ title: Streaming Upload Timeout
+ description: While streaming upload mode is true, this option set the timeout to complete upload.
+ type: integer
+ namingStrategy:
+ title: Naming Strategy
+ description: The naming strategy to use in streaming upload mode. There are 2 enums and the value can be one of progressive, random.
+ type: string
+ default: "progressive"
+ keyName:
+ title: Key Name
+ description: Setting the key name for an element in the bucket through endpoint parameter. In Streaming Upload, with the default configuration, this is the base for the progressive creation of files.
+ type: string
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the S3 client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the S3 client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the S3 client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in S3.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ forcePathStyle:
+ title: Force Path Style
+ description: Forces path style when accessing AWS S3 buckets.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-s3"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "aws2-s3:{{bucketNameOrArn}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ autoCreateBucket: "{{autoCreateBucket}}"
+ streamingUploadMode: "true"
+ restartingPolicy: "{{restartingPolicy}}"
+ batchMessageNumber: "{{batchMessageNumber}}"
+ batchSize: "{{batchSize}}"
+ namingStrategy: "{{namingStrategy}}"
+ keyName: "{{keyName}}"
+ streamingUploadTimeout: "{{?streamingUploadTimeout}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ forcePathStyle: "{{forcePathStyle}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-secrets-manager-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzUgNzUiIHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6dXJsKCNSZWRHcmFkaWVudCk7fS5jbHMtMntmaWxsOiNmZmY7fTwvc3R5bGU+PGxpbmVhckdyYWRpZW50IGlkPSJSZWRHcmFkaWVudCIgeDE9Ii0yMDQyLjU0IiB5MT0iMTk4NS40NyIgeDI9Ii0xOTM2LjQ3IiB5Mj0iMjA5MS41NCIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwMSAtMT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Secrets Manager"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Secrets Manager Sink"
+ description: Create a secret in AWS Secrets Manager.
+ required:
+ - region
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the Secrets Manager client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Secrets Manager client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Secrets Manager client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Secrets Manager.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:core"
+ - "camel:aws-secrets-manager"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[secret-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSecretsManagerSecretName
+ simple: "${header[secret-name]}"
+ - simple: "${header[ce-secret-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSecretsManagerSecretName
+ simple: "${header[ce-secret-name]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsSecretsManagerSecretName
+ simple: "${exchangeId}"
+ - to:
+ uri: "aws-secrets-manager:kamelet"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ operation: "createSecret"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-ses-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI1NnB4IiBoZWlnaHQ9IjI5OXB4IiB2aWV3Qm94PSIwIDAgMjU2IDI5OSIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+Cgk8Zz4KCQk8cGF0aCBkPSJNNjAuNTU2LDQ3LjYwMiBMMCwxNDQuMDEgTDYwLjU1NiwyNDAuNDM0IEw2MS42MTIsMjM5LjY4MSBMNjAuODM3LDQ3LjggTD [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SES"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SES Sink"
+ description: Send email through the Amazon Simple Email Service (SES).
+ required:
+ - from
+ - region
+ type: object
+ properties:
+ from:
+ title: From
+ description: From address
+ type: string
+ example: user@example.com
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the SES client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SES client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SES client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SES.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-ses"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesSubject
+ simple: "${header[subject]}"
+ - simple: "${header[ce-subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesSubject
+ simple: "${header[ce-subject]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAwsSesSubject
+ simple: "${exchangeId}"
+ - choice:
+ when:
+ - simple: "${header[to]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesTo
+ simple: "${header[to]}"
+ - simple: "${header[ce-to]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesTo
+ simple: "${header[ce-to]}"
+ - choice:
+ when:
+ - simple: "${header[reply-to-addresses]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesReplyToAddresses
+ simple: "${header[reply-to-addresses]}"
+ - simple: "${header[ce-reply-to-addresses]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSesReplyToAddresses
+ simple: "${header[ce-reply-to-addresses]}"
+ - to:
+ uri: "aws2-ses://{{from}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sns-fifo-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnICAgdmlld0JveD0iMCAwIDI1NiAyNTciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPg0KCTxnPg0KCQk8cGF0aCBkPSJNOTguODc1LDIzMi4wMzMgTDcyLjQ0MiwyMjQuNjI1IEw0Ny40NDEsMTk2LjExNyBMNzguNzEzLDE5NS4yNTQgTDk4Ljg3NSwyMzIuMDMzIiBmaWxsPSIjOTk1QjgwIj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SNS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SNS FIFO Sink"
+ description: Send message to an AWS SNS FIFO Topic.
+ required:
+ - topicNameOrArn
+ - region
+ type: object
+ properties:
+ topicNameOrArn:
+ title: Topic Name
+ description: The SNS Topic name or ARN.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ contentBasedDeduplication:
+ title: Content-Based Deduplication
+ description: Use content-based deduplication (should be enabled in the SQS FIFO queue first).
+ type: boolean
+ default: false
+ autoCreateTopic:
+ title: Autocreate Topic
+ description: Setting the autocreation of the SNS topic.
+ type: boolean
+ default: false
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the SNS client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SNS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SNS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SNS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-sns"
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSnsSubject
+ simple: "${header[subject]}"
+ - simple: "${header[ce-subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSnsSubject
+ simple: "${header[ce-subject]}"
+ - setProperty:
+ name: contentBasedDeduplication
+ constant: "{{contentBasedDeduplication}}"
+ - choice:
+ when:
+ - simple: "${header[group]}"
+ steps:
+ - setProperty:
+ name: CamelAwsSnsMessageGroupId
+ simple: "${header[group]}"
+ - simple: "${header[ce-group]}"
+ steps:
+ - setProperty:
+ name: CamelAwsSnsMessageGroupId
+ simple: "${header[ce-group]}"
+ otherwise:
+ steps:
+ - setProperty:
+ name: CamelAwsSnsMessageGroupId
+ simple: "${exchangeId}"
+ - choice:
+ when:
+ - simple: "${exchangeProperty.contentBasedDeduplication} == 'true'"
+ steps:
+ - to:
+ uri: "aws2-sns:{{topicNameOrArn}}"
+ parameters:
+ autoCreateTopic: "{{autoCreateTopic}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ messageGroupIdStrategy: "usePropertyValue"
+ messageDeduplicationIdStrategy: "useContentBasedDeduplication"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ otherwise:
+ steps:
+ - to:
+ uri: "aws2-sns:{{topicNameOrArn}}"
+ parameters:
+ autoCreateTopic: "{{autoCreateTopic}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ messageGroupIdStrategy: "usePropertyValue"
+ messageDeduplicationIdStrategy: "useExchangeId"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sns-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnICAgdmlld0JveD0iMCAwIDI1NiAyNTciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPg0KCTxnPg0KCQk8cGF0aCBkPSJNOTguODc1LDIzMi4wMzMgTDcyLjQ0MiwyMjQuNjI1IEw0Ny40NDEsMTk2LjExNyBMNzguNzEzLDE5NS4yNTQgTDk4Ljg3NSwyMzIuMDMzIiBmaWxsPSIjOTk1QjgwIj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SNS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SNS Sink"
+ description: Send message to an Amazon Simple Notification Service (SNS) topic.
+ required:
+ - topicNameOrArn
+ - region
+ type: object
+ properties:
+ topicNameOrArn:
+ title: Topic Name
+ description: The SNS topic name name or Amazon Resource Name (ARN).
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateTopic:
+ title: Autocreate Topic
+ description: Setting the autocreation of the SNS topic.
+ type: boolean
+ default: false
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the SNS client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SNS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SNS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SNS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-sns"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSnsSubject
+ simple: "${header[subject]}"
+ - simple: "${header[ce-subject]}"
+ steps:
+ - setHeader:
+ name: CamelAwsSnsSubject
+ simple: "${header[ce-subject]}"
+ - to:
+ uri: "aws2-sns:{{topicNameOrArn}}"
+ parameters:
+ autoCreateTopic: "{{autoCreateTopic}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sqs-batch-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SQS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SQS Batch Sink"
+ description: Send Batch message to an AWS SQS Queue.
+ required:
+ - queueNameOrArn
+ - region
+ - batchSeparator
+ type: object
+ properties:
+ queueNameOrArn:
+ title: Queue Name
+ description: The SQS Queue name or ARN
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateQueue:
+ title: Autocreate Queue
+ description: Setting the autocreation of the SQS queue.
+ type: boolean
+ default: false
+ batchSeparator:
+ title: Batch Separator
+ description: The batch separator string
+ type: string
+ example: ","
+ amazonAWSHost:
+ title: AWS Host
+ description: The hostname of the Amazon AWS cloud.
+ type: string
+ default: amazonaws.com
+ protocol:
+ title: Protocol
+ description: The underlying protocol used to communicate with SQS
+ type: string
+ example: http or https
+ default: https
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SQS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SQS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-sqs"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to:
+ uri: "aws2-sqs:{{queueNameOrArn}}"
+ parameters:
+ autoCreateQueue: "{{autoCreateQueue}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ batchSeparator: "{{batchSeparator}}"
+ operation: "sendBatchMessage"
+ amazonAWSHost: "{{?amazonAWSHost}}"
+ protocol: "{{?protocol}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sqs-fifo-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SQS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SQS FIFO Sink"
+ description: Send message to an AWS SQS FIFO Queue.
+ required:
+ - queueNameOrArn
+ - region
+ type: object
+ properties:
+ queueNameOrArn:
+ title: Queue Name
+ description: The SQS Queue name or ARN
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ contentBasedDeduplication:
+ title: Content-Based Deduplication
+ description: Use content-based deduplication (should be enabled in the SQS FIFO queue first)
+ type: boolean
+ default: false
+ autoCreateQueue:
+ title: Autocreate Queue
+ description: Setting the autocreation of the SQS queue.
+ type: boolean
+ default: false
+ amazonAWSHost:
+ title: AWS Host
+ description: The hostname of the Amazon AWS cloud.
+ type: string
+ default: amazonaws.com
+ protocol:
+ title: Protocol
+ description: The underlying protocol used to communicate with SQS
+ type: string
+ example: http or https
+ default: https
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SQS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SQS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-sqs"
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - setProperty:
+ name: contentBasedDeduplication
+ constant: "{{contentBasedDeduplication}}"
+ - choice:
+ when:
+ - simple: "${header[group]}"
+ steps:
+ - setProperty:
+ name: CamelAwsMessageGroupId
+ simple: "${header[group]}"
+ - simple: "${header[ce-group]}"
+ steps:
+ - setProperty:
+ name: CamelAwsMessageGroupId
+ simple: "${header[ce-group]}"
+ otherwise:
+ steps:
+ - setProperty:
+ name: CamelAwsMessageGroupId
+ simple: "${exchangeId}"
+ - choice:
+ when:
+ - simple: "${exchangeProperty.contentBasedDeduplication} == 'true'"
+ steps:
+ - to:
+ uri: "aws2-sqs:{{queueNameOrArn}}"
+ parameters:
+ autoCreateQueue: "{{autoCreateQueue}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ messageGroupIdStrategy: "usePropertyValue"
+ messageDeduplicationIdStrategy: "useContentBasedDeduplication"
+ amazonAWSHost: "{{?amazonAWSHost}}"
+ protocol: "{{?protocol}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ otherwise:
+ steps:
+ - to:
+ uri: "aws2-sqs:{{queueNameOrArn}}"
+ parameters:
+ autoCreateQueue: "{{autoCreateQueue}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ messageGroupIdStrategy: "usePropertyValue"
+ messageDeduplicationIdStrategy: "useExchangeId"
+ amazonAWSHost: "{{?amazonAWSHost}}"
+ protocol: "{{?protocol}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sqs-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SQS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS SQS Sink"
+ description: Send messages to an Amazon Simple Queue Service (SQS) queue.
+ required:
+ - queueNameOrArn
+ - region
+ type: object
+ properties:
+ queueNameOrArn:
+ title: Queue Name
+ description: The SQS Queue name or or Amazon Resource Name (ARN).
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateQueue:
+ title: Autocreate Queue
+ description: Automatically create the SQS queue.
+ type: boolean
+ default: false
+ amazonAWSHost:
+ title: AWS Host
+ description: The hostname of the Amazon AWS cloud.
+ type: string
+ default: amazonaws.com
+ protocol:
+ title: Protocol
+ description: The underlying protocol used to communicate with SQS.
+ type: string
+ example: http or https
+ default: https
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the SQS client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SQS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SQS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:aws2-sqs"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to:
+ uri: "aws2-sqs:{{queueNameOrArn}}"
+ parameters:
+ autoCreateQueue: "{{autoCreateQueue}}"
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ amazonAWSHost: "{{?amazonAWSHost}}"
+ protocol: "{{?protocol}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sqs-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS SQS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "AWS SQS Source"
+ description: Receive data from AWS SQS.
+ required:
+ - queueNameOrArn
+ - region
+ type: object
+ properties:
+ queueNameOrArn:
+ title: Queue Name
+ description: The SQS Queue Name or ARN.
+ type: string
+ deleteAfterRead:
+ title: Auto-delete Messages
+ description: Delete messages after consuming them.
+ type: boolean
+ default: true
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ autoCreateQueue:
+ title: Autocreate Queue
+ description: Setting the autocreation of the SQS queue.
+ type: boolean
+ default: false
+ amazonAWSHost:
+ title: AWS Host
+ description: The hostname of the Amazon AWS cloud.
+ type: string
+ default: amazonaws.com
+ protocol:
+ title: Protocol
+ description: The underlying protocol used to communicate with SQS.
+ type: string
+ example: http or https
+ default: https
+ queueURL:
+ title: Queue URL
+ description: The full SQS Queue URL.
+ type: string
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the SQS client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the SQS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the SQS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in SQS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected stream.
+ type: integer
+ default: 500
+ greedy:
+ title: Greedy Scheduler
+ description: If greedy is enabled, then the polling will happen immediately again, if the previous run polled 1 or more messages.
+ type: boolean
+ default: false
+ maxMessagesPerPoll:
+ title: Max Messages Per Poll
+ description: The maximum number of messages to return. Amazon SQS never returns more messages than this value (however, fewer messages might be returned). Valid values 1 to 10. Default 1.
+ type: integer
+ minimum: "1"
+ maximum: "10"
+ default: 1
+ waitTimeSeconds:
+ title: Wait Time Seconds
+ description: The duration (in seconds) for which the call waits for a message to arrive in the queue before returning. If a message is available, the call returns sooner than WaitTimeSeconds. If no messages are available and the wait time expires, the call does not return a message list.
+ type: integer
+ minimum: "0"
+ visibilityTimeout:
+ title: Visibility Timeout
+ description: The duration (in seconds) that the received messages are hidden from subsequent retrieve requests after being retrieved by a ReceiveMessage request.
+ type: integer
+ minimum: "0"
+ dataTypes:
+ out:
+ default: text
+ headers:
+ CamelAwsSqsMessageId:
+ title: The SQS Message Id
+ description: The Amazon SQS message ID.
+ type: string
+ CamelAwsSqsReceiptHandle:
+ title: The SQS Message Receipt Handle
+ description: The Amazon SQS message receipt handle.
+ type: string
+ CamelAwsSqsMD5OfBody:
+ title: The SQS Message MD5 Checksum
+ description: The content type of the retrieved object.
+ default: application/octet-stream
+ type: string
+ CamelAwsSqsAttributes:
+ title: The SQS Message System Attributes
+ description: A map of the attributes requested in ReceiveMessage to their respective values, the Map type is Map<MessageSystemAttributeName, String>
+ type: object
+ CamelAwsSqsMessageAttributes:
+ title: The SQS Message Attributes
+ description: The Amazon SQS message attributes, the Map type is Map<String, MessageAttributeValue>
+ type: object
+ types:
+ text:
+ format: "text-plain"
+ description: Default String representation of the SQS message received from the queue.
+ mediaType: text/plain
+ cloudevents:
+ format: "aws2-sqs:application-cloudevents"
+ description: Output data type represents AWS SQS receive message response as CloudEvent V1. The data type sets Camel specific CloudEvent headers on the exchange with respective data from the SQS message and its derived object.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id.
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type.
+ default: "org.apache.camel.event.aws.sqs.receiveMessage"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the SQS Received message receipt handle with prefix "aws.sqs.queue.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. The SQS message ID.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-sqs"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "aws2-sqs:{{queueNameOrArn}}"
+ parameters:
+ autoCreateQueue: "{{autoCreateQueue}}"
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ deleteAfterRead: "{{deleteAfterRead}}"
+ amazonAWSHost: "{{?amazonAWSHost}}"
+ protocol: "{{?protocol}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+ delay: "{{delay}}"
+ greedy: "{{greedy}}"
+ maxMessagesPerPoll: "{{maxMessagesPerPoll}}"
+ waitTimeSeconds: "{{?waitTimeSeconds}}"
+ visibilityTimeout: "{{?visibilityTimeout}}"
+ steps:
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-sts-assume-role-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQ5MCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiIHZpZXdCb3g9IjAgMCAyNTYgNDkwIiB3aWR0aD0iMjU2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxnIGZpbGw9IiMzYzQ5MjkiPjxwYXRoIGQ9Im0yMSAxNjUuNzUtMjEgNi44NTYgMjEuNzUgMi41MTl6Ii8+PHBhdGggZD0ibTE5Ljk1NSAyMDYuODA2IDEwOC4wNDUgNi45MDggMTA4LjA0NS02LjkwOC0xMDguMDQ1LTIxLjA1NnoiLz48cGF0aCBkPSJtMjM0LjUgMTc1LjEyNSAyMS41LTIuNTE5LTIxLjUtNS43MzF6Ii8+PC9nPjxwYXRoIGQ9Im0xNTcuMzg3ID [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS STS"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "AWS STS Assume Role Action"
+ description: Assume a role through STS
+ required:
+ - region
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the STS client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the STS client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the STS client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in STS.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:aws2-sts"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[role-arn]}"
+ steps:
+ - setHeader:
+ name: CamelAwsStsRoleArn
+ simple: "${header[role-arn]}"
+ - simple: "${header[ce-role-arn]}"
+ steps:
+ - setHeader:
+ name: CamelAwsStsRoleArn
+ simple: "${header[ce-role-arn]}"
+ - choice:
+ when:
+ - simple: "${header[role-session-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsStsRoleSessionName
+ simple: "${header[role-session-name]}"
+ - simple: "${header[ce-role-session-name]}"
+ steps:
+ - setHeader:
+ name: CamelAwsStsRoleSessionName
+ simple: "${header[ce-role-session-name]}"
+ - to:
+ uri: "aws2-sts://default"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ operation: "assumeRole"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-timestream-query-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICAgIDx0aXRsZT5BV1MgVGltZXN0cmVhbTwvdGl0bGU+CiAgICA8ZGVmcz4KICAgICAgICA8bGluZWFyR3JhZGllbnQgeDE9IjAlIiB5MT0iMTAwJSIgeDI9IjEwMCUiIHkyPSIwJS [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Timestream"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "AWS Timestream Query Sink"
+ description: Query an AWS Timestream Database
+ required:
+ - region
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: If true, the CloudWatch client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Timestream client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Timestream client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Timestream.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ uriEndpointOverride:
+ title: Overwrite Endpoint URI
+ description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+ type: string
+ overrideEndpoint:
+ title: Endpoint Overwrite
+ description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+ type: boolean
+ default: false
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-timestream"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[query]}"
+ steps:
+ - setHeader:
+ name: CamelAwsTimestreamQueryString
+ simple: "${header[query]}"
+ - simple: "${header[ce-query]}"
+ steps:
+ - setHeader:
+ name: CamelAwsTimestreamQueryString
+ simple: "${header[ce-query]}"
+ - to:
+ uri: "aws2-timestream:query"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ secretKey: "{{?secretKey}}"
+ region: "{{region}}"
+ operation: "query"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ uriEndpointOverride: "{{?uriEndpointOverride}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+ overrideEndpoint: "{{overrideEndpoint}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: aws-translate-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIyLjg4IDg0LjgxIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMjIuODggODQuODEiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZD [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "AWS Translate"
+ camel.apache.org/kamelet.namespace: "AWS"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "AWS Translate Action"
+ description: Translate a text in a specific language.
+ required:
+ - region
+ - sourceLanguage
+ - targetLanguage
+ type: object
+ properties:
+ accessKey:
+ title: Access Key
+ description: The access key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key obtained from AWS.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ region:
+ title: AWS Region
+ description: The AWS region to access.
+ type: string
+ enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+ sourceLanguage:
+ title: Source Language
+ description: The source language of the translating text.
+ type: string
+ example: it
+ enum: ["ar", "zh", "zh-TW", "cs", "da", "nl", "en", "fi", "fr", "de", "he", "hi", "id", "it", "ja", "ko", "ms", "no", "fa", "pl", "pt", "ru", "es", "sv", "tr"]
+ targetLanguage:
+ title: Target Language
+ description: The target language of the translating text.
+ type: string
+ example: it
+ enum: ["ar", "zh", "zh-TW", "cs", "da", "nl", "en", "fi", "fr", "de", "he", "hi", "id", "it", "ja", "ko", "ms", "no", "fa", "pl", "pt", "ru", "es", "sv", "tr"]
+ useDefaultCredentialsProvider:
+ title: Default Credentials Provider
+ description: Set whether the Translate client should expect to load credentials through a default credentials provider or to expect static credentials to be passed in.
+ type: boolean
+ default: false
+ useProfileCredentialsProvider:
+ title: Profile Credentials Provider
+ description: Set whether the Translate client should expect to load credentials through a profile credentials provider.
+ type: boolean
+ default: false
+ useSessionCredentials:
+ title: Session Credentials
+ description: Set whether the Translate client should expect to use Session Credentials. This is useful in situation in which the user needs to assume a IAM role for doing operations in Translate.
+ type: boolean
+ default: false
+ profileCredentialsName:
+ title: Profile Credentials Name
+ description: If using a profile credentials provider this parameter sets the profile name.
+ type: string
+ sessionToken:
+ title: Session Token
+ description: Amazon AWS Session Token used when the user needs to assume a IAM role.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:dns"
+ - "camel:kamelet"
+ - "camel:aws2-translate"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "aws2-translate://translate"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{region}}"
+ sourceLanguage: "{{sourceLanguage}}"
+ targetLanguage: "{{targetLanguage}}"
+ useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+ useProfileCredentialsProvider: "{{useProfileCredentialsProvider}}"
+ useSessionCredentials: "{{useSessionCredentials}}"
+ profileCredentialsName: "{{?profileCredentialsName}}"
+ sessionToken: "{{?sessionToken}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-cosmosdb-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCI+PGRlZnM+PHJhZGlhbEdyYWRpZW50IGlkPSJhIiBjeD0iLTEwNS4wMDYiIGN5PSItMTAuNDA5IiByPSI1Ljk1NCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAzNiAwIDAgMS4wMjcgMTE3LjczOSAxOS42NDQpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuMTgzIiBzdG9wLWNvbG9yPSIjNWVhMGVmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA3OGQ0Ii8+PC9yYWRpYWxHcmFkaWVudD48Y2xpcFBhdG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure CosmosDB"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure CosmosDB Sink"
+ description: Send Data to an Azure CosmosDB instance
+ required:
+ - databaseName
+ - containerName
+ - databaseEndpoint
+ type: object
+ properties:
+ databaseName:
+ title: Database Name
+ description: The Azure Cosmos database name.
+ type: string
+ containerName:
+ title: Container Name
+ description: The Azure Cosmos container name.
+ type: string
+ accountKey:
+ title: Account Key
+ description: The Azure Cosmos account Key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ databaseEndpoint:
+ title: Database Endpoint
+ description: Sets the Azure Cosmos database endpoint the component will connect to.
+ type: string
+ itemPartitionKey:
+ title: Item Partition Key
+ description: Represents a partition key value in the Azure Cosmos DB database service. A partition key identifies the partition where the item is stored in.
+ type: string
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY"]
+ default: "SHARED_ACCOUNT_KEY"
+ types:
+ in:
+ mediaType: application/json
+ dependencies:
+ - "camel:azure-cosmosdb"
+ - "camel:kamelet"
+ - "camel:jackson"
+ - "camel:core"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: '${propertiesExist:!itemPartitionKey}'
+ steps:
+ - choice:
+ when:
+ - simple: "${header[itemPartitionKey]}"
+ steps:
+ - setHeader:
+ name: CamelAzureCosmosDbItemPartitionKey
+ simple: "${header[itemPartitionKey]}"
+ - simple: "${header[ce-itemPartitionKey]}"
+ steps:
+ - setHeader:
+ name: CamelAzureCosmosDbItemPartitionKey
+ simple: "${header[ce-itemPartitionKey]}"
+ - unmarshal:
+ json:
+ library: Jackson
+ - to:
+ uri: "azure-cosmosdb:{{databaseName}}/{{containerName}}"
+ parameters:
+ accountKey: "{{?accountKey}}"
+ databaseEndpoint: "{{databaseEndpoint}}"
+ itemPartitionKey: "{{?itemPartitionKey}}"
+ operation: createItem
+ credentialType: "{{credentialType}}"
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-cosmosdb-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCI+PGRlZnM+PHJhZGlhbEdyYWRpZW50IGlkPSJhIiBjeD0iLTEwNS4wMDYiIGN5PSItMTAuNDA5IiByPSI1Ljk1NCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAzNiAwIDAgMS4wMjcgMTE3LjczOSAxOS42NDQpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIuMTgzIiBzdG9wLWNvbG9yPSIjNWVhMGVmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA3OGQ0Ii8+PC9yYWRpYWxHcmFkaWVudD48Y2xpcFBhdG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure CosmosDB"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure CosmosDB Source"
+ description: Consume Changes from a CosmosDB instance.
+ required:
+ - databaseName
+ - containerName
+ - databaseEndpoint
+ type: object
+ properties:
+ databaseName:
+ title: Database Name
+ description: The Azure Cosmos database name.
+ type: string
+ containerName:
+ title: Container Name
+ description: The Azure Cosmos container name.
+ type: string
+ accountKey:
+ title: Account Key
+ description: The Azure Cosmos account Key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ leaseDatabaseName:
+ title: Lease Database Name
+ description: Sets the lease container which acts as a state storage and coordinates processing the change feed across multiple workers.
+ type: string
+ leaseContainerName:
+ title: Lease Container Name
+ description: Sets the lease database where the `leaseContainerName` is stored.
+ type: string
+ createLeaseDatabaseIfNotExists:
+ title: Autocreate Lease Database
+ description: Sets if the component should create Cosmos lease database for the consumer automatically in case it doesn’t exist in Cosmos account.
+ type: boolean
+ default: false
+ createLeaseContainerIfNotExists:
+ title: Autocreate Lease Container
+ description: Sets if the component should create Cosmos lease container for the consumer automatically in case it doesn’t exist in Cosmos database.
+ type: boolean
+ default: false
+ databaseEndpoint:
+ title: Database Endpoint
+ description: Sets the Azure Cosmos database endpoint the component will connect to.
+ type: string
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY"]
+ default: "SHARED_ACCOUNT_KEY"
+ dataTypes:
+ out:
+ default: json
+ headers:
+ types:
+ json:
+ format: "application-json"
+ description: Json mapping of Change Feed records
+ mediaType: application/json
+ cloudevents:
+ format: "azure-cosmosdb:application-cloudevents"
+ description: Data type transformer converts Azure CosmosDB Change Feed processor response to CloudEvent v1_0 data format. The data type sets Camel specific CloudEvent headers with values extracted from Azure CosmosDB Change Feed processor response.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.azure.cosmosdb.changes"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source.
+ type: string
+ default: "org.apache.camel.event.azure.cosmosdb.changefeed"
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject.
+ type: string
+ default: "org.apache.camel.event.azure.cosmosdb.changefeed"
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-cosmosdb"
+ - "camel:kamelet"
+ - "camel:jackson"
+ template:
+ from:
+ uri: "azure-cosmosdb:{{databaseName}}/{{containerName}}"
+ parameters:
+ leaseDatabaseName: "{{?leaseDatabaseName}}"
+ leaseContainerName: "{{?leaseContainerName}}"
+ accountKey: "{{?accountKey}}"
+ createLeaseDatabaseIfNotExists: "{{createLeaseDatabaseIfNotExists}}"
+ createLeaseContainerIfNotExists: "{{createLeaseContainerIfNotExists}}"
+ databaseEndpoint: "{{databaseEndpoint}}"
+ credentialType: "{{credentialType}}"
+ steps:
+ - marshal:
+ json: {}
+ - to: "kamelet:sink"
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-eventhubs-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9Ii0uMDc1IC0uMTc0IDE1OC40IDE2My4xMDEiIHdpZHRoPSIyNDM5IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxnIGZpbGw9IiMwMDZmZDQiPjxwYXRoIGQ9Im02LjIyNS4wMjZoMTQ2LjZjMS4zIDAgMy0uMiA0LjEuNS45LjYuOCAxLjUuOCAyLjR2MzEuOGMwIC45LS4xIDEuOC0uOCAyLjQtLjguOC0xLjcuOC0yLjguOGgtMTQuMWMtMS4yIDAtMi40LS4xLTMuMi0xLS43LS44LS43LTEuOS0uNy0yLjl2LTEyLjVoLTExNHYxMi44YzAgMS0uMSAyLS44IDIuOC0uOC44LTEuOC44LTIuOC44aC0xNC44Yy [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Eventhubs"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Eventhubs Sink"
+ description: Send events to Azure Event Hubs.
+ required:
+ - namespaceName
+ - eventhubName
+ type: object
+ properties:
+ namespaceName:
+ title: Eventhubs Namespace
+ description: The Event Hubs namespace.
+ type: string
+ eventhubName:
+ title: Eventhubs Name
+ description: The Event Hub name.
+ type: string
+ sharedAccessName:
+ title: Share Access Name
+ description: The Event Hubs SAS key name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ sharedAccessKey:
+ title: Share Access Key
+ description: The key for the Event Hubs SAS key name.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["CONNECTION_STRING", "AZURE_IDENTITY"]
+ default: "CONNECTION_STRING"
+ dependencies:
+ - "camel:core"
+ - "camel:azure-eventhubs"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[partition-id]}"
+ steps:
+ - setHeader:
+ name: CamelAzureEventHubsPartitionId
+ simple: "${header[partition-id]}"
+ - simple: "${header[ce-partition-id]}"
+ steps:
+ - setHeader:
+ name: CamelAzureEventHubsPartitionId
+ simple: "${header[ce-partition-id]}"
+ - to:
+ uri: "azure-eventhubs://{{namespaceName}}/{{eventhubName}}"
+ parameters:
+ sharedAccessName: "{{?sharedAccessName}}"
+ sharedAccessKey: "{{?sharedAccessKey}}"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-eventhubs-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9Ii0uMDc1IC0uMTc0IDE1OC40IDE2My4xMDEiIHdpZHRoPSIyNDM5IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxnIGZpbGw9IiMwMDZmZDQiPjxwYXRoIGQ9Im02LjIyNS4wMjZoMTQ2LjZjMS4zIDAgMy0uMiA0LjEuNS45LjYuOCAxLjUuOCAyLjR2MzEuOGMwIC45LS4xIDEuOC0uOCAyLjQtLjguOC0xLjcuOC0yLjguOGgtMTQuMWMtMS4yIDAtMi40LS4xLTMuMi0xLS43LS44LS43LTEuOS0uNy0yLjl2LTEyLjVoLTExNHYxMi44YzAgMS0uMSAyLS44IDIuOC0uOC44LTEuOC44LTIuOC44aC0xNC44Yy [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Eventhubs"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Eventhubs Source"
+ description: Receive events from Azure Event Hubs.
+ required:
+ - namespaceName
+ - eventhubName
+ - blobAccountName
+ - blobAccessKey
+ - blobContainerName
+ type: object
+ properties:
+ namespaceName:
+ title: Eventhubs Namespace
+ description: The Event Hubs namespace.
+ type: string
+ eventhubName:
+ title: Eventhubs Name
+ description: The Event Hub name.
+ type: string
+ sharedAccessName:
+ title: Share Access Name
+ description: The Event Hubs SAS key name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ sharedAccessKey:
+ title: Share Access Key
+ description: The key for the Event Hubs SAS key name.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ blobAccountName:
+ title: Azure Storage Blob Account Name
+ description: The name of the Storage Blob account.
+ type: string
+ blobContainerName:
+ title: Azure Storage Blob Container Name
+ description: The name of the Storage Blob container.
+ type: string
+ blobAccessKey:
+ title: Azure Storage Blob Access Key
+ description: The key for the Azure Storage Blob service that is associated with the Storage Blob account name.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["CONNECTION_STRING", "AZURE_IDENTITY"]
+ default: "CONNECTION_STRING"
+ dataTypes:
+ out:
+ default: binary
+ headers:
+ CamelAzureEventHubsPartitionId:
+ title: Azure Storage Event Hubs Partiton Id
+ description: It sets the partition id of the Event Hub.
+ type: string
+ CamelAzureEventHubsOffset :
+ title: Azure Storage Event Hubs Event Offset
+ description: It sets the offset of the event when it was received from the associated Event Hub partition. This is only present on a received EventData.
+ type: string
+ CamelAzureEventHubsEnqueuedTime:
+ title: Azure Event Hubs Event Enqueued Time
+ description: It sets the instant, in UTC, of when the event was enqueued in the Event Hub partition. This is only present on a received EventData.
+ type: java.time.Instant
+ CamelAzureEventHubsSequenceNumber:
+ title: Azure Event Hubs Event Sequence Number
+ description: It sets the sequence number assigned to the event when it was enqueued in the associated Event Hub partition. This is unique for every message received in the Event Hub partition. This is only present on a received EventData.
+ type: long
+ CamelAzureEventHubsMetadata:
+ title: Azure Event Hubs Event Metadata
+ description: The set of free-form event properties which may be used for passing metadata associated with the event with the event body during Event Hubs operations.
+ type: object
+ CamelMessageTimestamp:
+ title: Azure Event Hubs Message Timestamp
+ description: The timestamp of the message.
+ type: long
+ CamelAzureEventHubsCheckpointUpdatedBy:
+ title: Azure Event Hubs Checkpoint Updated By
+ description: It sets the reason for the checkpoint to have been updated. This is only present on a received EventData.
+ type: string
+ types:
+ binary:
+ format: "application-octet-stream"
+ description: Default binary representation of the Azure Event Hubs Event retrieved.
+ mediaType: application/octet-stream
+ cloudevents:
+ format: "azure-eventhubs:application-cloudevents"
+ description: Data type transformer converts Azure Eventhubs consumer response to CloudEvent v1_0 data format. The data type sets
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.azure.eventhubs.consume"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the Partition Id with prefix "azure.eventhubs.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. The Azure Event Hubs Event Sequence Number.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-eventhubs"
+ - "camel:kamelet"
+ - "camel:jackson"
+ template:
+ from:
+ uri: 'azure-eventhubs://{{namespaceName}}/{{eventhubName}}'
+ parameters:
+ sharedAccessName: "{{?sharedAccessName}}"
+ sharedAccessKey: "{{?sharedAccessKey}}"
+ blobAccountName: "{{blobAccountName}}"
+ blobAccessKey: "{{blobAccessKey}}"
+ blobContainerName: "{{blobContainerName}}"
+ credentialType: "{{credentialType}}"
+ steps:
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-functions-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjE4LjI0IDIxLjQ2IDY0IDY0IiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPjxwYXRoIGQ9Ik04MS44MzcgNTMuODVjLjU4NS0uNTg1LjQ4Ny0xLjcgMC0yLjMwN2wtMy4wODctMy4wODctMTMuOC0xMy4zODZjLS41ODUtLjU4NS0xLjQ5NS0uNTg1LTIuMiAwLS41ODUuNTg1LS44MTIgMS43IDAgMi4zMDdsMTQuNSAxNC4xOThjLjU4NS41ODUuNTg1IDEuNyAwIDIuMzA3TDYyLjQ0IDY4LjU2OGMtLjU4NS41ODUtLjU4NSAxLjcgMCAyLjMwNy41ODUuNTg1IDEuNy40ODcgMi4yIDBsMTMuOC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Functions"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Function Sink"
+ description: Forward data to an Azure Function.
+ required:
+ - url
+ type: object
+ properties:
+ url:
+ title: URL
+ description: The Azure Functions URL you want to send the data to.
+ type: string
+ example: "https://azure-function-demo-12234.azurewebsites.net/api/httpexample"
+ pattern: "^(https)://.*"
+ method:
+ title: Method
+ description: The HTTP method to use.
+ type: string
+ default: POST
+ enum: ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "TRACE", "PATCH"]
+ key:
+ title: Key
+ description: A function-specific API key is required, if the authLevel of the function is FUNCTION or master key if the authLevel is ADMIN.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:vertx-http"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - removeHeader:
+ name: CamelHttpUri
+ - setHeader:
+ name: CamelHttpMethod
+ constant: "{{method}}"
+ - to: "vertx-http:{{url}}?code={{?key}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-servicebus-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgODEgODIiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMS4zMzMgMEMuNTMzIDAgMCAuNTMzIDAgMS4zMzN2MTZjMCAuOC41MzMgMS4zMz [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Servicebus"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Servicebus Sink"
+ description: Send Messages to Azure Servicebus.
+ required:
+ - topicOrQueueName
+ - connectionString
+ type: object
+ properties:
+ topicOrQueueName:
+ title: Topic Or Queue Name
+ description: Topic Or Queue Name for the Azure Servicebus instance
+ type: string
+ connectionString:
+ title: Connection String
+ description: Connection String for Azure Servicebus instance
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ serviceBusType:
+ title: Servicebus Type
+ description: The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model.
+ type: string
+ default: queue
+ enum: ["queue", "topic"]
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL"]
+ default: "CONNECTION_STRING"
+ types:
+ in:
+ mediaType: application/octet-stream
+ dependencies:
+ - "camel:azure-servicebus"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - to:
+ uri: "azure-servicebus:{{topicOrQueueName}}"
+ parameters:
+ connectionString: "{{connectionString}}"
+ serviceBusType: "{{serviceBusType}}"
+ producerOperation: "sendMessages"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-servicebus-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgODEgODIiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMS4zMzMgMEMuNTMzIDAgMCAuNTMzIDAgMS4zMzN2MTZjMCAuOC41MzMgMS4zMz [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Servicebus"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Servicebus Source"
+ description: Consume Messages from Azure Servicebus.
+ required:
+ - topicOrQueueName
+ - connectionString
+ type: object
+ properties:
+ topicOrQueueName:
+ title: Topic Or Queue Name
+ description: Topic Or Queue Name for the Azure Servicebus instance
+ type: string
+ connectionString:
+ title: Connection String
+ description: Connection String for Azure Servicebus instance
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ serviceBusReceiveMode:
+ title: Servicebus Receive Mode
+ description: Sets the receive mode for the receiver
+ type: string
+ default: PEEK_LOCK
+ enum: ["PEEK_LOCK", "RECEIVE_AND_DELETE"]
+ subscriptionName:
+ title: Subscription Name
+ description: Sets the name of the subscription in the topic to listen to. This parameter is mandatory in case of topic.
+ type: string
+ serviceBusType:
+ title: Servicebus Type
+ description: The service bus type of connection to execute. Queue is for typical queue option and topic for subscription based model.
+ type: string
+ default: queue
+ enum: ["queue", "topic"]
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["AZURE_IDENTITY", "CONNECTION_STRING", "TOKEN_CREDENTIAL"]
+ default: "CONNECTION_STRING"
+ types:
+ out:
+ mediaType: application/octet-stream
+ dependencies:
+ - "camel:azure-servicebus"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: "azure-servicebus:{{topicOrQueueName}}"
+ parameters:
+ connectionString: "{{connectionString}}"
+ serviceBusReceiveMode: "{{serviceBusReceiveMode}}"
+ subscriptionName: "{{?subscriptionName}}"
+ serviceBusType: "{{serviceBusType}}"
+ credentialType: "{{credentialType}}"
+ steps:
+ - setBody:
+ simple: "${body.toBytes()}"
+ - to: "kamelet:sink"
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-blob-append-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Storage Blob Append Sink"
+ description: Upload data in append mode to Azure Storage Blob.
+ required:
+ - accountName
+ - containerName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ containerName:
+ title: Container Name
+ description: The Azure Storage Blob container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "CLIENT_SECRET"]
+ default: "SHARED_ACCOUNT_KEY"
+ dependencies:
+ - "camel:core"
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${header[ce-file]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${exchangeId}"
+ - to:
+ uri: "azure-storage-blob://{{accountName}}/{{containerName}}"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ azureClientId: "{{?clientId}}"
+ azureClientSecret: "{{?clientSecret}}"
+ azureTenantId: "{{?tenantId}}"
+ operation: "commitAppendBlob"
+ blobType: "appendBlob"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-blob-changefeed-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob Changefeed"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage Blob Changefeed Source"
+ description: Consume events from an Azure Storage Blob change feed.
+ required:
+ - period
+ - accountName
+ type: object
+ properties:
+ period:
+ title: Period between Polls
+ description: The interval (in milliseconds) between fetches to the Azure Storage change feed.
+ type: integer
+ default: 10000
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Blob access Key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "CLIENT_SECRET"]
+ default: "SHARED_ACCOUNT_KEY"
+ dependencies:
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:jsonpath"
+ - "camel:timer"
+ template:
+ from:
+ uri: "timer:azure-storage-blob-stream"
+ parameters:
+ period: "{{period}}"
+ steps:
+ - to:
+ uri: "azure-storage-blob:{{accountName}}"
+ parameters:
+ operation: "getChangeFeed"
+ accessKey: "{{?accessKey}}"
+ azureClientId: "{{?clientId}}"
+ azureClientSecret: "{{?clientSecret}}"
+ azureTenantId: "{{?tenantId}}"
+ credentialType: "{{credentialType}}"
+ - split:
+ expression:
+ simple: "${body}"
+ - marshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - setHeader:
+ name: "azure-storage-blob-changefeed-topic"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.topic
+ - setHeader:
+ name: "azure-storage-blob-changefeed-subject"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.subject
+ - setHeader:
+ name: "azure-storage-blob-changefeed-eventType"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.eventType
+ - setHeader:
+ name: "azure-storage-blob-changefeed-eventTime"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.eventTime
+ - setHeader:
+ name: "azure-storage-blob-changefeed-id"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.id
+ - setHeader:
+ name: "azure-storage-blob-changefeed-dataVersion"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.dataVersion
+ - setHeader:
+ name: "azure-storage-blob-changefeed-metadataVersion"
+ jsonpath:
+ suppressExceptions: true
+ expression: $.metadataVersion
+ - setBody:
+ jsonpath:
+ expression: $.data
+ - marshal:
+ json:
+ library: Jackson
+ module-class-names: com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-blob-event-based-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgODEgODIiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMS4zMzMgMEMuNTMzIDAgMCAuNTMzIDAgMS4zMzN2MTZjMCAuOC41MzMgMS4zMz [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob Event Based"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage Blob Event-based Source"
+ description: Receive data from Azure Service Bus subscribed to Azure Eventgrid reporting events related to a Azure Storage Blob account.
+ required:
+ - topicOrQueueName
+ - connectionString
+ - accountName
+ - containerName
+ type: object
+ properties:
+ topicOrQueueName:
+ title: Topic Or Queue Name
+ description: Topic Or Queue Name for the Azure Servicebus instance
+ type: string
+ connectionString:
+ title: Connection String
+ description: Connection String for Azure Servicebus instance
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ serviceBusReceiveMode:
+ title: Servicebus Receive Mode
+ description: Sets the receive mode for the receiver.
+ type: string
+ default: RECEIVE_AND_DELETE
+ enum: ["RECEIVE_AND_DELETE", "PEEK_LOCK"]
+ subscriptionName:
+ title: Subscription Name
+ description: Sets the name of the subscription in the topic to listen to. This parameter is mandatory in case of topic.
+ type: string
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ containerName:
+ title: Container Name
+ description: The Azure Storage Blob container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ default: SHARED_ACCOUNT_KEY
+ enum: ["SHARED_ACCOUNT_KEY", "SHARED_KEY_CREDENTIAL", "AZURE_IDENTITY", "CLIENT_SECRET"]
+ getBlob:
+ title: Get Object in Container
+ description: >-
+ If `getBlob` is enabled, then the file created in the container is
+ retrieved and returned as body. If not only the event is returned as body.
+ type: boolean
+ default: false
+ types:
+ out:
+ mediaType: application/octet-stream
+ dependencies:
+ - "camel:azure-servicebus"
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ - "camel:core"
+ - 'camel:jsonpath'
+ - 'camel:jackson'
+ template:
+ from:
+ uri: "azure-servicebus:{{topicOrQueueName}}"
+ parameters:
+ connectionString: "{{connectionString}}"
+ serviceBusReceiveMode: "{{serviceBusReceiveMode}}"
+ subscriptionName: "{{?subscriptionName}}"
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: '${properties:getBlob:true}'
+ steps:
+ - setBody:
+ simple: ${body.toString()}
+ - unmarshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - setProperty:
+ name: azure-storage-blob-event-type
+ jsonpath: $.eventType
+ - setProperty:
+ name: azure-storage-blob-subject
+ jsonpath: $.subject
+ - setProperty:
+ name: azure-storage-blob-blob-name
+ simple: '${exchangeProperty.azure-storage-blob-subject.substring(${exchangeProperty.azure-storage-blob-subject.lastIndexOf("/")}++)}'
+ - log: "${exchangeProperty.azure-storage-blob-event-type} - ${exchangeProperty.azure-storage-blob-subject} - ${exchangeProperty.azure-storage-blob-blob-name}"
+ - choice:
+ when:
+ - simple: '${exchangeProperty.azure-storage-blob-event-type} == "Microsoft.Storage.BlobCreated" && ${exchangeProperty.azure-storage-blob-subject} contains "{{containerName}}"'
+ steps:
+ - toD: >-
+ azure-storage-blob:{{accountName}}/{{containerName}}?accessKey=RAW({{?accessKey}})&azureClientId=RAW({{?clientId}})&azureClientSecret=RAW({{?clientSecret}})&azureTenantId=RAW({{?tenantId}})&operation=getBlob&blobName=${exchangeProperty.azure-storage-blob-blob-name}&credentialType={{credentialType}}
+ - to: 'kamelet:sink'
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-blob-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Storage Blob Sink"
+ description: Upload data to Azure Storage Blob.
+ required:
+ - accountName
+ - containerName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ containerName:
+ title: Container Name
+ description: The Azure Storage Blob container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "CLIENT_SECRET"]
+ default: "SHARED_ACCOUNT_KEY"
+ dependencies:
+ - "camel:core"
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${header[ce-file]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAzureStorageBlobBlobName
+ simple: "${exchangeId}"
+ - to:
+ uri: "azure-storage-blob://{{accountName}}/{{containerName}}"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ azureClientId: "{{?clientId}}"
+ azureClientSecret: "{{?clientSecret}}"
+ azureTenantId: "{{?tenantId}}"
+ operation: "uploadBlockBlob"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-blob-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage Blob Source"
+ description: Consume files from Azure Storage Blob.
+ required:
+ - accountName
+ - containerName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ containerName:
+ title: Container Name
+ description: The Azure Storage Blob container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected blob.
+ type: integer
+ default: 500
+ deleteAfterRead:
+ title: Auto-delete Blob
+ description: Specifies to delete blobs after consuming them
+ type: boolean
+ default: false
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "CLIENT_SECRET"]
+ default: "SHARED_ACCOUNT_KEY"
+ dataTypes:
+ out:
+ default: binary
+ headers:
+ CamelAzureStorageBlobBlobName:
+ title: Azure Storage Blob Name
+ description: The name of the blob retrieved
+ type: string
+ CamelAzureStorageBlobBlobType:
+ title: The Azure Storage Blob Type
+ description: The Blob type, one of blockblob, appendblob or pageblob
+ type: string
+ CamelAzureStorageBlobContentType:
+ title: Content Type
+ description: The content type of the retrieved object.
+ default: application/octet-stream
+ type: string
+ CamelAzureStorageBlobETag:
+ title: ETag Value
+ description: The E tag of the blob
+ type: string
+ CamelAzureStorageBlobCreationTime:
+ title: Creation time
+ description: The Creation time of the blob
+ type: string
+ CamelAzureStorageBlobLastModified:
+ title: Last modification time
+ description: The Last modification time of the blob
+ type: string
+ CamelAzureStorageBlobLeaseStatus:
+ title: Lease status
+ description: Status of the lease on the blob, one of locked or unlocked
+ type: string
+ CamelAzureStorageBlobMetadata:
+ title: Blob Metadata
+ description: Additional Metadata of the blob of type Map<String,Object>
+ type: object
+ types:
+ binary:
+ format: "application-octet-stream"
+ description: Default binary representation of the Blob object retrieved from the container.
+ mediaType: application/octet-stream
+ cloudevents:
+ format: "azure-storage-blob:application-cloudevents"
+ description: Output data type represents Azure Storage Blob get blob response as CloudEvent V1. The data type sets Camel specific CloudEvent headers on the exchange with respective data from the Azure container and its derived object.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.azure.storage.blob.getBlob"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the E Tag name of the blob with prefix "azure.storage.blob.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. Usually the Azure Storage Blob name.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jsonpath"
+ - "camel:timer"
+ template:
+ from:
+ uri: "azure-storage-blob:{{accountName}}/{{containerName}}"
+ parameters:
+ accessKey: "{{?accessKey}}"
+ azureClientId: "{{?clientId}}"
+ azureClientSecret: "{{?clientSecret}}"
+ azureTenantId: "{{?tenantId}}"
+ credentialType: "{{credentialType}}"
+ delay: "{{delay}}"
+ steps:
+ - to: "kamelet:sink"
+ - choice:
+ precondition: true
+ when:
+ - simple: '${properties:deleteAfterRead:true}'
+ steps:
+ - to:
+ uri: "azure-storage-blob:{{accountName}}/{{containerName}}"
+ parameters:
+ operation: "deleteBlob"
+ accessKey: "{{?accessKey}}"
+ azureClientId: "{{?clientId}}"
+ azureClientSecret: "{{?clientSecret}}"
+ azureTenantId: "{{?tenantId}}"
+ credentialType: "{{credentialType}}"
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-datalake-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyNi4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4wIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxMTU4LjIgODYwLjQiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob Data Lake"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Storage Blob Data Lake Sink"
+ description: Send data to Azure Storage Blob Data Lake.
+ required:
+ - accountName
+ - clientId
+ - clientSecret
+ - tenantId
+ - fileSystemName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob Data lake account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob Data lake client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob Data lake client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob Data lake tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ fileSystemName:
+ title: File System Name
+ description: The Azure Storage Blob Data lake File system name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["CLIENT_SECRET", "SHARED_KEY_CREDENTIAL", "AZURE_IDENTITY", "AZURE_SAS", "SERVICE_CLIENT_INSTANCE"]
+ default: "CLIENT_SECRET"
+ dependencies:
+ - "camel:azure-storage-datalake"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:timer"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageDataLakeFileName
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageDataLakeFileName
+ simple: "${header[ce-file]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelAzureStorageDataLakeFileName
+ simple: "${exchangeId}"
+ - to:
+ uri: "azure-storage-datalake:{{accountName}}/{{fileSystemName}}"
+ parameters:
+ clientId: "{{clientId}}"
+ clientSecret: "{{clientSecret}}"
+ tenantId: "{{tenantId}}"
+ operation: "upload"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-datalake-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyNi4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4wIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAxMTU4LjIgODYwLjQiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob Data Lake"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage Blob Data Lake Source"
+ description: Consume files from Azure Storage Blob Data Lake.
+ required:
+ - accountName
+ - clientId
+ - clientSecret
+ - tenantId
+ - fileSystemName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob Data lake account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientId:
+ title: Client Id
+ description: The Azure Storage Blob Data lake client Id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientSecret:
+ title: Client Secret
+ description: The Azure Storage Blob Data lake client secret.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ tenantId:
+ title: Tenant Id
+ description: The Azure Storage Blob Data lake tenant id.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ fileSystemName:
+ title: File System Name
+ description: The Azure Storage Blob Data lake File system name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected blob.
+ type: integer
+ default: 500
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["CLIENT_SECRET", "SHARED_KEY_CREDENTIAL", "AZURE_IDENTITY", "AZURE_SAS", "SERVICE_CLIENT_INSTANCE"]
+ default: "CLIENT_SECRET"
+ dataTypes:
+ out:
+ default: binary
+ headers:
+ CamelAzureStorageDataLakeFileName:
+ title: Azure Storage Datalake File Name
+ description: The name of the file retrieved
+ type: string
+ CamelAzureStorageDataLakeRawHttpHeaders:
+ title: Azure Storage Data Lake Raw Http Headers
+ description: Non parsed http headers that can be used by the user.
+ type: object
+ CamelAzureStorageDataLakeAccessTier:
+ title: Azure Storage Data Lake File Access Tier
+ description: Access tier of file.
+ type: object
+ CamelAzureStorageDataLakeAccessTierChangeTime:
+ title: Azure Storage Data Lake Access Tier Change Time.
+ description: Datetime when the access tier of the blob last changed.
+ type: object
+ CamelAzureStorageDataLakeArchiveStatus:
+ title: Azure Storage Data Lake Archive Status
+ description: Archive status of file
+ type: object
+ CamelAzureStorageDataLakeCacheControl:
+ title: Azure Storage Data Lake File Cache Control
+ description: Cache control specified for the file.
+ type: string
+ CamelAzureStorageDataLakeContentDisposition:
+ title: Azure Storage Data Lake File Content Disposition
+ description: Content disposition specified for the file.
+ type: string
+ CamelAzureStorageDataLakeContentEncoding:
+ title: Azure Storage Data Lake File Content Encoding
+ description: Content encoding specified for the file.
+ type: string
+ CamelAzureStorageDataLakeContentLanguage:
+ title: Azure Storage Data Lake File Content Language
+ description: Content language specified for the file.
+ type: string
+ CamelAzureStorageDataLakeContentType:
+ title: Azure Storage Data Lake File Content Type
+ description: Content Type specified for the file.
+ type: string
+ CamelAzureStorageDataLakeCopyCompletionTime:
+ title: Azure Storage Data Lake File Copy Completion time
+ description: Conclusion time of the last attempted Copy Blob operation where this file was the destination file.
+ type: object
+ CamelAzureStorageDataLakeCopyId:
+ title: Azure Storage Data Lake File Copy Id
+ description: String identifier for this copy operation.
+ type: string
+ amelAzureStorageDataLakeCopyProgress:
+ title: Azure Storage Data Lake File Copy Progress
+ description: Contains the number of bytes copied and the total bytes in the source in the last attempted Copy Blob operation where this file was the destination file.
+ type: string
+ CamelAzureStorageDataLakeCopySource:
+ title: Azure Storage Data Lake File Copy Source
+ description: URL up to 2 KB in length that specifies the source file or file used in the last attempted Copy Blob operation where this file was the destination file.
+ type: string
+ CamelAzureStorageDataLakeCopyStatus:
+ title: Azure Storage Data Lake File Copy Status
+ description: Status of the last copy operation performed on the file.
+ type: object
+ CamelAzureStorageDataLakeCopyStatusDescription:
+ title: Azure Storage Data Lake File Copy Status Description
+ description: The description of the copy’s status.
+ type: string
+ CamelAzureStorageDataLakeCreationTime:
+ title: Azure Storage Data Lake File Creation Time.
+ description: Creation time of the file.
+ type: object
+ CamelAzureStorageDataLakeEncryptionKeySha256:
+ title: Azure Storage Data Lake File SHA-256 Hash
+ description: The SHA-256 hash of the encryption key used to encrypt the file.
+ type: string
+ CamelAzureStorageDataLakeETag:
+ title: Azure Storage Data Lake File E Tag
+ description: The E Tag of the file.
+ type: string
+ CamelAzureStorageDataLakeFileSize:
+ title: Azure Storage Data Lake File Size
+ description: The File Size
+ type: long
+ CamelAzureStorageDataLakeLastModified:
+ title: Azure Storage Data Lake File Last Modified Date
+ description: Datetime when the file was last modified.
+ type: object
+ CamelAzureStorageDataLakeLeaseDuration:
+ title: Azure Storage Data Lake File Lease Duration
+ description: Type of lease on the file.
+ type: object
+ CamelAzureStorageDataLakeLeaseState:
+ title: Azure Storage Data Lake File Lease State
+ description: State of the lease on the file.
+ type: object
+ CamelAzureStorageDataLakeLeaseStatus:
+ title: Azure Storage Data Lake File Lease Status
+ description: Status of the lease on the file.
+ type: object
+ CamelAzureStorageDataLakeServerEncrypted:
+ title: Azure Storage Data Lake File Content Encrypted
+ description: Flag indicating if the file’s content is encrypted on the server.
+ type: boolean
+ CamelAzureStorageDataLakeDownloadLink:
+ title: Azure Storage Data Lake File Download Link
+ description: The link that can be used to download the file from data lake.
+ type: string
+ types:
+ binary:
+ format: "application-octet-stream"
+ description: Default binary representation of the object retrieved from the Azure Data Lake.
+ mediaType: application/octet-stream
+ cloudevents:
+ format: "azure-storage-datalake:application-cloudevents"
+ description: Data type transformer converts Azure Data Lake consumer response to CloudEvent v1_0 data format. The data type sets Camel specific CloudEvent headers with values extracted from Azure Data Lake consumer response.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.azure.storage.datalake.consume"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the Archive Status of the file with prefix "azure.storage.datalake.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. Usually the Azure Storage Datalake E Tag of file.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-storage-datalake"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:timer"
+ template:
+ from:
+ uri: "azure-storage-datalake:{{accountName}}/{{fileSystemName}}"
+ parameters:
+ clientId: "{{clientId}}"
+ clientSecret: "{{clientSecret}}"
+ tenantId: "{{tenantId}}"
+ delay: "{{delay}}"
+ credentialType: "{{credentialType}}"
+ steps:
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-files-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Storage Files Sink"
+ description: Upload data to Azure Storage Files Share.
+ required:
+ - accountName
+ - shareName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Blob account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ shareName:
+ title: Share Name
+ description: The Azure Storage File Share share name.
+ type: string
+ sharedKey:
+ title: Shared Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "SHARED_KEY_CREDENTIAL", "AZURE_SAS"]
+ default: "SHARED_ACCOUNT_KEY"
+ directoryName:
+ title: Directory Name
+ description: The directory from where the producer will upload the file.
+ type: string
+ default: "."
+ dependencies:
+ - "camel:core"
+ - "camel:azure-storage-blob"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelFileName
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelFileName
+ simple: "${header[ce-file]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelFileName
+ simple: "${exchangeId}"
+ - to:
+ uri: "azure-files://{{accountName}}/{{shareName}}/{{directoryName}}"
+ parameters:
+ sharedKey: "{{?sharedKey}}"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-files-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNjcuNTU4IDBIMjIuNDQxTDAgNDBsMjIuNDQxIDQwaDQ1LjExN0w5MCA0MCA2Ny [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Blob"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage File Source"
+ description: Consume files from Azure Storage File Shares.
+ required:
+ - accountName
+ - shareName
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage File Share account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ shareName:
+ title: Share Name
+ description: The Azure Storage File Share share name.
+ type: string
+ sharedKey:
+ title: Shared Access Key
+ description: The Azure Storage Blob access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected blob.
+ type: integer
+ default: 500
+ deleteAfterRead:
+ title: Auto-delete Blob
+ description: Specifies to delete blobs after consuming them
+ type: boolean
+ default: false
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "AZURE_IDENTITY", "SHARED_KEY_CREDENTIAL", "AZURE_SAS"]
+ default: "SHARED_ACCOUNT_KEY"
+ directoryName:
+ title: Directory Name
+ description: The directory from where the consumer will start reading files.
+ type: string
+ default: "."
+ recursive:
+ title: Recursive Mode
+ description: If a directory, the consumer will look for files in all the sub-directories as well.
+ type: boolean
+ default: false
+ dataTypes:
+ out:
+ default: binary
+ headers:
+ CamelFileLength:
+ title: Azure Storage Files File Length
+ description: A long value containing the file size
+ type: long
+ CamelFileLastModified:
+ title: Azure Storage Files File Last Modified Date
+ description: A Long value containing the last modified timestamp of the file.
+ type: long
+ CamelFileNameOnly:
+ title: Azure Storage Files File Name Only
+ description: Only the file name (the name with no leading paths).
+ type: string
+ CamelFileName:
+ title: Azure Storage Files File Name
+ description: Name of the consumed file as a relative file path with offset from the starting directory configured on the endpoint.
+ type: string
+ CamelFileNameConsumed:
+ title: Azure Storage Files Consumed File Name
+ description: The name of the file that has been consumed.
+ type: string
+ CamelFileAbsolute:
+ title: Azure Storage Files Consumed Absolute Format
+ description: A boolean option specifying whether the consumed file denotes an absolute path or not.
+ type: boolean
+ CamelFileAbsolutePath:
+ title: Azure Storage Files Consumed Absolute Path
+ description: The absolute path to the file. For relative files this path holds the relative path instead.
+ type: string
+ CamelFileExtendedAttributes:
+ title: Azure Storage Files Extended Attributes
+ description: Additional Metadata of the file of type Map<String,Object>
+ type: object
+ CamelFileContentType:
+ title: Content Type
+ description: The content type of the retrieved object.
+ default: application/octet-stream
+ type: string
+ CamelFilePath:
+ title: Azure Storage Files File Path
+ description: The file path. For relative files this is the starting directory the relative filename. For absolute files this is the absolute path.
+ type: string
+ CamelFileRelativePath:
+ title: Azure Storage Files File Relative Path
+ description: The relative path.
+ type: string
+ CamelFileParent:
+ title: Azure Storage Files File Relative Path
+ description: The parent path.
+ type: string
+ types:
+ binary:
+ format: "application-octet-stream"
+ description: Default binary representation of the File retrieved from Azure Storage Files.
+ mediaType: application/octet-stream
+ cloudevents:
+ format: "azure-files:application-cloudevents"
+ description: Data type transformer converts Azure Storage Files poll response to CloudEvent v1_0 data format. The data type sets Camel specific CloudEvent headers with values extracted from Azure Storage Files poll response.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type
+ default: "org.apache.camel.event.azure.storage.files.poll"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the Host name of the share with prefix "azure.storage.files.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. Usually the Azure Storage Files file name.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-files"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:timer"
+ template:
+ from:
+ uri: "azure-files:{{accountName}}/{{shareName}}/{{directoryName}}"
+ parameters:
+ sharedKey: "{{?sharedKey}}"
+ credentialType: "{{credentialType}}"
+ delay: "{{delay}}"
+ delete: "{{deleteAfterRead}}"
+ recursive: "{{recursive}}"
+ steps:
+ - to: "kamelet:sink"
+
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-queue-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNzAuMDUzIDM0LjYzNEg1MC41OGw5LjczNiA3LjgwNXptLTM5LjQyIDEwLjQ4OG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Queue"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Azure Storage Queue Sink"
+ description: Send events to Azure Storage queues.
+ required:
+ - accountName
+ - queueName
+ - accessKey
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Queue account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ queueName:
+ title: Queue Name
+ description: The Azure Storage Queue container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Queue access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "SHARED_KEY_CREDENTIAL", "AZURE_IDENTITY"]
+ default: "SHARED_ACCOUNT_KEY"
+ dependencies:
+ - "camel:core"
+ - "camel:azure-storage-queue"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[expiration]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageQueueTimeToLive
+ simple: "${header[expiration]}"
+ - simple: "${header[ce-expiration]}"
+ steps:
+ - setHeader:
+ name: CamelAzureStorageQueueTimeToLive
+ simple: "${header[ce-expiration]}"
+ - to:
+ uri: "azure-storage-queue://{{accountName}}/{{queueName}}"
+ parameters:
+ accessKey: "{{accessKey}}"
+ credentialType: "{{credentialType}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: azure-storage-queue-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgOTEgODEiIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjx1c2UgeGxpbms6aHJlZj0iI0EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9IkEiIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNNzAuMDUzIDM0LjYzNEg1MC41OGw5LjczNiA3LjgwNXptLTM5LjQyIDEwLjQ4OG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Azure Storage Queue"
+ camel.apache.org/kamelet.namespace: "Azure"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Azure Storage Queue Source"
+ description: Receive events from Azure Storage queues.
+ required:
+ - accountName
+ - queueName
+ - accessKey
+ type: object
+ properties:
+ accountName:
+ title: Account Name
+ description: The Azure Storage Queue account name.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ queueName:
+ title: Queue Name
+ description: The Azure Storage Queue container name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The Azure Storage Queue access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ maxMessages:
+ title: Maximum Messages
+ description: The maximum number of messages to get. You can specify a value between 1 and 32. The default is 1 (one message). If there are fewer than the maximum number of messages in the queue, then all the messages are returned.
+ type: integer
+ default: 1
+ credentialType:
+ title: Credential Type
+ description: Determines the credential strategy to adopt.
+ type: string
+ enum: ["SHARED_ACCOUNT_KEY", "SHARED_KEY_CREDENTIAL", "AZURE_IDENTITY"]
+ default: "SHARED_ACCOUNT_KEY"
+ dataTypes:
+ out:
+ default: text
+ headers:
+ CamelAzureStorageQueueMessageId:
+ title: Azure Storage Queue Message Id
+ description: The id of the message.
+ type: string
+ CamelAzureStorageQueueInsertionTime:
+ title: Azure Storage Queue Message Insertion Time
+ description: The time the Message was inserted into the Queue.
+ type: OffsetDateTime
+ CamelAzureStorageQueueExpirationTime:
+ title: Azure Storage Queue Message Expiration Time
+ description: The time that the Message will expire and be automatically deleted.
+ type: OffsetDateTime
+ CamelAzureStorageQueuePopReceipt:
+ title: Pop Receipt
+ description: Unique identifier that must match for the message to be deleted or updated. If deletion fails using this pop receipt then the message has been dequeued by another client.
+ type: string
+ CamelAzureStorageQueueTimeNextVisible:
+ title: Azure Storage Queue Message Time Next Visible
+ description: The time that the message will again become visible in the Queue.
+ type: OffsetDateTime
+ CamelAzureStorageQueueDequeueCount:
+ title: Dequeue Count
+ description: The number of times the message has been dequeued.
+ type: long
+ types:
+ text:
+ format: "text-plain"
+ description: Default text representation of the Message dequeued from the queue.
+ mediaType: text/plain
+ cloudevents:
+ format: "azure-storage-queue:application-cloudevents"
+ description: Output data type represents Azure Storage Queue receive messages operation as CloudEvent V1. The data type sets Camel specific CloudEvent headers on the exchange.
+ headers:
+ CamelCloudEventID:
+ title: CloudEvent ID
+ description: The Camel exchange id set as event id.
+ type: string
+ CamelCloudEventType:
+ title: CloudEvent Type
+ description: The event type.
+ default: "org.apache.camel.event.azure.storage.queue.receiveMessages"
+ type: string
+ CamelCloudEventSource:
+ title: CloudEvent Source
+ description: The event source. By default, the Message Id of the message received with prefix "azure.storage.queue.".
+ type: string
+ CamelCloudEventSubject:
+ title: CloudEvent Subject
+ description: The event subject. Usually the Pop receipt of the message dequeued.
+ type: string
+ CamelCloudEventTime:
+ title: CloudEvent Time
+ description: The exchange creation timestamp as event time.
+ type: string
+ dependencies:
+ - "camel:azure-storage-queue"
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ from:
+ uri: "azure-storage-queue://{{accountName}}/{{queueName}}"
+ parameters:
+ accessKey: "{{accessKey}}"
+ maxMessages: "{{maxMessages}}"
+ credentialType: "{{credentialType}}"
+ steps:
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: bitcoin-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PCEtLSBDcmVhdGVkIHdpdGggSW5rc2NhcGUgKGh0dHA6Ly93d3cuaW5rc2NhcGUub3JnLykgLS0+CjxzdmcgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNjQiIHdpZHRoPSI2NCIgdmVyc2lvbj0iMS4xIiB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iPgo8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjAwNjMwODc2LC0wLjAwMzAxOT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Bitcoin"
+ camel.apache.org/kamelet.namespace: "Bitcoin"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Bitcoin Source"
+ description: Provides a feed of the value of the Bitcoin compared to USDT using the Binance service.
+ type: object
+ properties:
+ period:
+ title: Period between Updates
+ description: The interval between updates in milliseconds.
+ type: integer
+ default: 10000
+ types:
+ out:
+ mediaType: application/json
+ schema:
+ type: object
+ properties:
+ currencyPair:
+ type: string
+ open:
+ type: number
+ last:
+ type: number
+ bid:
+ type: number
+ ask:
+ type: number
+ high:
+ type: number
+ low:
+ type: number
+ vwap:
+ type: number
+ volume:
+ type: number
+ quoteVolume:
+ type: number
+ bidSize:
+ type: number
+ askSize:
+ type: number
+ dependencies:
+ - "camel:xchange"
+ - "camel:kamelet"
+ - "camel:jackson"
+ - "camel:timer"
+ template:
+ from:
+ uri: "timer:update"
+ parameters:
+ period: "{{period}}"
+ steps:
+ - to: "xchange:binance?service=marketdata&method=ticker¤cyPair=BTC/USDT"
+ - marshal:
+ json: {}
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: caffeine-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIxLjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9ItCh0LvQvtC5XzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyODEuOCAyNzMuOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwID [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Caffeine"
+ camel.apache.org/kamelet.namespace: "Cache"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Caffeine Action"
+ description: Perform operations on a caffeine cache
+ required:
+ - cacheName
+ type: object
+ properties:
+ cacheName:
+ title: Cache name
+ description: The name of the cache we want to use
+ type: string
+ default: caffeine-cache
+ dependencies:
+ - "camel:core"
+ - "camel:caffeine"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[caffeine-key]}"
+ steps:
+ - setHeader:
+ name: CamelCaffeineKey
+ simple: "${header[caffeine-key]}"
+ - simple: "${header[ce-caffeinekey]}"
+ steps:
+ - setHeader:
+ name: CamelCaffeineKey
+ simple: "${header[ce-caffeinekey]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelCaffeineKey
+ simple: "${body}"
+ - choice:
+ when:
+ - simple: "${header[caffeine-operation]}"
+ steps:
+ - setHeader:
+ name: CamelCaffeineAction
+ simple: "${header[caffeine-operation]}"
+ - simple: "${header[ce-caffeineoperation]}"
+ steps:
+ - setHeader:
+ name: CamelCaffeineAction
+ simple: "${header[ce-caffeineoperation]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: CamelCaffeineAction
+ constant: "GET"
+ - to:
+ uri: "caffeine-cache:{{cacheName}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: cassandra-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIyLjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzMiAzMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzIgMzI7Ii [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Cassandra"
+ camel.apache.org/kamelet.namespace: "Nosql"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Cassandra Sink"
+ description: Send data to an Apache Cassandra cluster.
+ required:
+ - connectionHost
+ - connectionPort
+ - keyspace
+ - query
+ type: object
+ properties:
+ connectionHost:
+ title: Connection Host
+ description: The hostname(s) for the Cassandra server(s). Use a comma to separate multiple hostnames.
+ type: string
+ example: localhost
+ connectionPort:
+ title: Connection Port
+ description: The port number(s) of the cassandra server(s). Use a comma to separate multiple port numbers.
+ type: string
+ example: 9042
+ keyspace:
+ title: Keyspace
+ description: The keyspace to use.
+ type: string
+ example: customers
+ username:
+ title: Username
+ description: The username for accessing a secured Cassandra cluster.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password for accessing a secured Cassandra cluster.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ consistencyLevel:
+ title: Consistency Level
+ description: The consistency level to use.
+ type: string
+ default: ANY
+ enum: ["ANY", "ONE", "TWO", "THREE", "QUORUM", "ALL", "LOCAL_QUORUM", "EACH_QUORUM", "LOCAL_ONE"]
+ prepareStatements:
+ title: Prepare Statements
+ description: If true, specifies to use PreparedStatements as the query. If false, specifies to use regular Statements as the query.
+ type: boolean
+ default: true
+ query:
+ title: Query
+ description: The query to execute against the Cassandra cluster table.
+ type: string
+ extraTypeCodecs:
+ title: Extra Type Codecs
+ description: To use a specific comma separated list of Extra Type codecs.
+ type: string
+ enum: ["BLOB_TO_ARRAY", "BOOLEAN_LIST_TO_ARRAY", "BYTE_LIST_TO_ARRAY", "SHORT_LIST_TO_ARRAY", "INT_LIST_TO_ARRAY", "LONG_LIST_TO_ARRAY", "FLOAT_LIST_TO_ARRAY", "DOUBLE_LIST_TO_ARRAY", "TIMESTAMP_UTC", "TIMESTAMP_MILLIS_SYSTEM", "TIMESTAMP_MILLIS_UTC", "ZONED_TIMESTAMP_SYSTEM", "ZONED_TIMESTAMP_UTC", "ZONED_TIMESTAMP_PERSISTED", "LOCAL_TIMESTAMP_SYSTEM", "LOCAL_TIMESTAMP_UTC"]
+ jsonPayload:
+ title: JSON Payload
+ description: If we want to transform the payload in json or not
+ type: boolean
+ default: true
+ types:
+ in:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:cassandraql"
+ - "camel:core"
+ template:
+ beans:
+ - name: local-sql-cassandraql-sink
+ type: "#class:org.apache.camel.component.cassandra.CassandraComponent"
+ properties:
+ autowiredEnabled: "false"
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: '${properties:jsonPayload:true}'
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ useList: true
+ - to:
+ uri: "{{local-sql-cassandraql-sink}}://{{connectionHost}}:{{connectionPort}}/{{keyspace}}"
+ parameters:
+ username: "{{?username}}"
+ password: "{{?password}}"
+ prepareStatements: "{{prepareStatements}}"
+ consistencyLevel: "{{consistencyLevel}}"
+ cql: "{{query}}"
+ extraTypeCodecs: "{{?extraTypeCodecs}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: cassandra-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIyLjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzMiAzMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzIgMzI7Ii [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Cassandra"
+ camel.apache.org/kamelet.namespace: "Nosql"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Cassandra Source"
+ description: Send a query to an Apache Cassandra cluster table.
+ required:
+ - connectionHost
+ - connectionPort
+ - keyspace
+ - query
+ type: object
+ properties:
+ connectionHost:
+ title: Connection Host
+ description: The hostname(s) for the Cassandra server(s). Use a comma to separate multiple hostnames.
+ type: string
+ example: localhost
+ connectionPort:
+ title: Connection Port
+ description: The port number(s) of the cassandra server(s). Use a comma to separate multiple port numbers.
+ type: string
+ example: 9042
+ keyspace:
+ title: Keyspace
+ description: The keyspace to use.
+ type: string
+ example: customers
+ username:
+ title: Username
+ description: The username for accessing a secured Cassandra cluster.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password for accessing a secured Cassandra cluster.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ resultStrategy:
+ title: Result Strategy
+ description: The strategy to convert the result set of the query.
+ type: string
+ default: ALL
+ enum: ["ALL", "ONE", "LIMIT_10", "LIMIT_100"]
+ consistencyLevel:
+ title: Consistency Level
+ description: The consistency level to use.
+ type: string
+ default: QUORUM
+ enum: ["ONE", "TWO", "THREE", "QUORUM", "ALL", "LOCAL_QUORUM", "EACH_QUORUM", "SERIAL", "LOCAL_SERIAL", "LOCAL_ONE"]
+ query:
+ title: Query
+ description: The query to execute against the Cassandra cluster table.
+ type: string
+ extraTypeCodecs:
+ title: Extra Type Codecs
+ description: To use a specific comma separated list of Extra Type codecs.
+ type: string
+ enum: ["BLOB_TO_ARRAY", "BOOLEAN_LIST_TO_ARRAY", "BYTE_LIST_TO_ARRAY", "SHORT_LIST_TO_ARRAY", "INT_LIST_TO_ARRAY", "LONG_LIST_TO_ARRAY", "FLOAT_LIST_TO_ARRAY", "DOUBLE_LIST_TO_ARRAY", "TIMESTAMP_UTC", "TIMESTAMP_MILLIS_SYSTEM", "TIMESTAMP_MILLIS_UTC", "ZONED_TIMESTAMP_SYSTEM", "ZONED_TIMESTAMP_UTC", "ZONED_TIMESTAMP_PERSISTED", "LOCAL_TIMESTAMP_SYSTEM", "LOCAL_TIMESTAMP_UTC"]
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:cassandraql"
+ template:
+ beans:
+ - name: local-sql-cassandraql-source
+ type: "#class:org.apache.camel.component.cassandra.CassandraComponent"
+ properties:
+ autowiredEnabled: "false"
+ from:
+ uri: "{{local-sql-cassandraql-source}}://{{connectionHost}}:{{connectionPort}}/{{keyspace}}"
+ parameters:
+ username: "{{?username}}"
+ password: "{{?password}}"
+ cql: "{{query}}"
+ consistencyLevel: "{{consistencyLevel}}"
+ resultSetConversionStrategy: "{{resultStrategy}}"
+ extraTypeCodecs: "{{?extraTypeCodecs}}"
+ steps:
+ - marshal:
+ json: {}
+ - to: "kamelet:sink"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: ceph-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4gPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAiIGhlaWdodD0iMTU3IiB2aWV3Qm94PSIwIDAgMTYwIDE1NyIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwKSI+PHBhdGggZD0iTTc5LjgxNTIgOTYuMDczOUM4OC42ODM2IDk2LjA3MzkgOTUuNzA0NCA4OS4wNTMxIDk1LjcwNDQgODAuMTg0OEM5NS43MDQ0IDcxLjMxNjQgODguNjgzNiA2NC4yOTU2IDc5LjgxNTIgNjQuMjk1NkM3MC45NDY5IDY0LjI5NTYgNjMuOTI2MSA3MS4zMTY0IDYzLj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Ceph"
+ camel.apache.org/kamelet.namespace: "Cloud"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Ceph Sink"
+ description: Upload data to an Ceph Bucket managed by a Object Storage Gateway.
+ required:
+ - cephUrl
+ - accessKey
+ - secretKey
+ - bucketName
+ - zoneGroup
+ type: object
+ properties:
+ bucketName:
+ title: Bucket Name
+ description: The Ceph Bucket name.
+ type: string
+ accessKey:
+ title: Access Key
+ description: The access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ zoneGroup:
+ title: Bucket Zone Group
+ description: The bucket zone group.
+ type: string
+ autoCreateBucket:
+ title: Autocreate Bucket
+ description: Specifies to automatically create the bucket.
+ type: boolean
+ default: false
+ cephUrl:
+ title: Ceph Url Address
+ description: Set the Ceph Object Storage Address Url.
+ type: string
+ example: "http://ceph-storage-address.com"
+ keyName:
+ title: Key Name
+ description: The key name for saving an element in the bucket.
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:aws2-s3"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${header[ce-file]}"
+ - simple: "'{{?keyName}}' == ''"
+ steps:
+ - setHeader:
+ name: CamelAwsS3Key
+ simple: "${exchangeId}"
+ - to:
+ uri: "aws2-s3:{{bucketName}}"
+ parameters:
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{zoneGroup}}"
+ autoCreateBucket: "{{autoCreateBucket}}"
+ uriEndpointOverride: "{{?cephUrl}}"
+ overrideEndpoint: "true"
+ keyName: "{{?keyName}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: ceph-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4gPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAiIGhlaWdodD0iMTU3IiB2aWV3Qm94PSIwIDAgMTYwIDE1NyIgZmlsbD0ibm9uZSI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwKSI+PHBhdGggZD0iTTc5LjgxNTIgOTYuMDczOUM4OC42ODM2IDk2LjA3MzkgOTUuNzA0NCA4OS4wNTMxIDk1LjcwNDQgODAuMTg0OEM5NS43MDQ0IDcxLjMxNjQgODguNjgzNiA2NC4yOTU2IDc5LjgxNTIgNjQuMjk1NkM3MC45NDY5IDY0LjI5NTYgNjMuOTI2MSA3MS4zMTY0IDYzLj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Ceph"
+ camel.apache.org/kamelet.namespace: "Cloud"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Ceph Source"
+ description: Receive data from an Ceph Bucket, managed by a Object Storage Gateway.
+ required:
+ - cephUrl
+ - accessKey
+ - secretKey
+ - bucketName
+ - zoneGroup
+ type: object
+ properties:
+ bucketName:
+ title: Bucket Name
+ description: The Ceph Bucket name.
+ type: string
+ deleteAfterRead:
+ title: Auto-delete Objects
+ description: Specifies to delete objects after consuming them.
+ type: boolean
+ default: true
+ accessKey:
+ title: Access Key
+ description: The access key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ secretKey:
+ title: Secret Key
+ description: The secret key.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ zoneGroup:
+ title: Bucket Zone Group
+ description: The bucket zone group.
+ type: string
+ autoCreateBucket:
+ title: Autocreate Bucket
+ description: Specifies to automatically create the bucket.
+ type: boolean
+ default: false
+ includeBody:
+ title: Include Body
+ description: If true, the exchange is consumed and put into the body and closed. If false, the Object stream is put raw into the body and the headers are set with the object metadata.
+ type: boolean
+ default: true
+ prefix:
+ title: Prefix
+ description: The bucket prefix to consider while searching.
+ type: string
+ example: 'folder/'
+ ignoreBody:
+ title: Ignore Body
+ description: If true, the Object body is ignored. Setting this to true overrides any behavior defined by the `includeBody` option. If false, the object is put in the body.
+ type: boolean
+ default: false
+ cephUrl:
+ title: Ceph Url Address
+ description: Set the Ceph Object Storage Address Url.
+ type: string
+ example: "http://ceph-storage-address.com"
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll of the selected bucket.
+ type: integer
+ default: 500
+ dependencies:
+ - "camel:aws2-s3"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "aws2-s3:{{bucketName}}"
+ parameters:
+ autoCreateBucket: "{{autoCreateBucket}}"
+ secretKey: "{{?secretKey}}"
+ accessKey: "{{?accessKey}}"
+ region: "{{zoneGroup}}"
+ includeBody: "{{includeBody}}"
+ ignoreBody: "{{ignoreBody}}"
+ deleteAfterRead: "{{deleteAfterRead}}"
+ prefix: "{{?prefix}}"
+ uriEndpointOverride: "{{cephUrl}}"
+ overrideEndpoint: "true"
+ delay: "{{delay}}"
+ steps:
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: chuck-norris-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDA [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Chuck Norris"
+ camel.apache.org/kamelet.namespace: "Dataset"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Chuck Norris Source"
+ description: Gets periodically Chuck Norris jokes
+ type: object
+ properties:
+ period:
+ title: Period
+ description: The interval (msec) to wait before getting the next joke
+ type: integer
+ default: 10000
+ types:
+ out:
+ mediaType: text/plain
+ dependencies:
+ - "camel:kamelet"
+ - "camel:timer"
+ - "camel:http"
+ - "camel:jsonpath"
+ template:
+ from:
+ uri: "timer:chuck"
+ parameters:
+ period: "{{period}}"
+ steps:
+ - to: "https://api.chucknorris.io/jokes/random"
+ - removeHeaders:
+ pattern: '*'
+ - setBody:
+ jsonpath: "$.value"
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: chunk-template-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Chunk Template Action"
+ description: Apply a Chunk Template.
+ required:
+ - template
+ type: object
+ properties:
+ template:
+ title: Template
+ description: The inline template
+ type: binary
+ dependencies:
+ - "camel:chunk"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "chunk:"
+ parameters:
+ resourceUri: "base64:{{template}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: couchbase-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNjguMzQzIDY4LjM0MyIgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHVzZSB4bGluazpocmVmPSIjQSIgeD0iMi4xNzEiIHk9IjIuMTcxIi8+PHN5bWJvbCBpZD0iQSIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0zMi4wMDIgMEMxNC4zMzEuMDAyLjAwNSAxNC4zMjYgMC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Couchbase"
+ camel.apache.org/kamelet.namespace: "Nosql"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Couchbase Sink"
+ description: Send documents to Couchbase.
+ required:
+ - protocol
+ - couchbaseHostname
+ - bucket
+ type: object
+ properties:
+ protocol:
+ title: Protocol
+ description: The protocol to use
+ type: string
+ couchbaseHostname:
+ title: Hostname
+ description: The hostname to use
+ type: string
+ couchbasePort:
+ title: Port
+ description: The port to use
+ type: integer
+ default: 8091
+ bucket:
+ title: Bucket
+ description: The bucket to use
+ type: string
+ username:
+ title: Username
+ description: Username to connect to Couchbase.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: Password to connect to Couchbase.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ startingId:
+ title: Starting Id
+ description: The starting id
+ type: integer
+ default: 1
+ autoStartId:
+ title: Auto Start Id
+ description: Auto Start Id or not
+ type: boolean
+ default: true
+ dependencies:
+ - "camel:couchbase"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "couchbase:{{protocol}}://{{couchbaseHostname}}:{{couchbasePort}}"
+ parameters:
+ bucket: "{{bucket}}"
+ autoStartIdForInserts: "{{autoStartId}}"
+ startingIdForInsertsFrom: "{{startingId}}"
+ username: "{{username}}"
+ password: "{{password}}"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: counter-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0+DQo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm9 [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Timer"
+ camel.apache.org/kamelet.namespace: "Scheduling"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+ camel.apache.org/kamelet.verified: "true"
+spec:
+ definition:
+ title: "Counter Source"
+ description: Generates sequential number events starting from a configurable value, incrementing by a specified step. Useful for testing, scheduled tasks, or creating ordered event sequences.
+ type: object
+ properties:
+ period:
+ title: Period
+ description: The time interval between two numbers
+ type: integer
+ default: 1000
+ start:
+ title: Starting Number
+ description: The starting number
+ type: integer
+ default: 1
+ numbers:
+ title: Numbers
+ description: How many numbers to generate
+ type: integer
+ dependencies:
+ - "camel:timer"
+ - "camel:core"
+ - "camel:bean"
+ - "camel:kamelet"
+ template:
+ beans:
+ - name: counter
+ type: java.util.concurrent.atomic.AtomicInteger
+ constructors:
+ "0": "{{start}}"
+ from:
+ uri: timer:counter
+ parameters:
+ period: "{{period}}"
+ repeatCount: "{{?numbers}}"
+ steps:
+ - bean:
+ ref: "{{counter}}"
+ method: getAndIncrement
+ - setHeader:
+ name: "Content-Type"
+ constant: "text/plain"
+ - to: kamelet:sink
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: cron-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTAwIiBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9IjAgMCAxOTIuNzU2IDE5Mi43NTYiPjxnIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDE5Mi43NTZ2MTkyLjc1NkgwVjB6Ii8+PHBhdGggZD0iTTQyLjE2IDEwMy4wNzJsNS45MDEgMS40OTZjLTEuMjQyIDQuODY1LTMuNDc2IDguNTc0LTYuNzAxIDExLjEyOXMtNy4xNjcgMy44MzItMTEuODI2IDMuODMyYy00LjgyMyAwLTguNzQ2LS45ODItMTEuNzY3LTIuOTQ3LT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Cron"
+ camel.apache.org/kamelet.namespace: "Scheduling"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Cron Source"
+ description: Send events at specific time.
+ required:
+ - schedule
+ - message
+ type: object
+ properties:
+ schedule:
+ title: Cron Schedule
+ description: A cron expression that is used to trigger events generation.
+ type: string
+ example: "0/3 10 * * * ?"
+ message:
+ title: Message
+ description: The message to generate
+ type: string
+ example: hello world
+ types:
+ out:
+ mediaType: text/plain
+ dependencies:
+ - "camel:quartz"
+ - "camel:core"
+ - "camel:cron"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "cron:tick"
+ parameters:
+ schedule: "{{schedule}}"
+ steps:
+ - setBody:
+ constant: "{{message}}"
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: data-type-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Data Type Action"
+ description: Applies a given data type with respective data transformation.
+ required:
+ - format
+ type: object
+ properties:
+ scheme:
+ title: Component Scheme
+ description: The data type component scheme enables users to apply Camel component specific data type conversions.
+ type: string
+ format:
+ title: Data Type Format
+ description: Defines the data type that is applied by this action. Apache Camel and the Kamelet catalog support different data types and performs automatic message conversion according to the given type.
+ type: string
+ dependencies:
+ - "camel:kamelet"
+ - "camel:core"
+ template:
+ beans:
+ - name: dataTypeProcessor
+ type: "#class:org.apache.camel.processor.transformer.DataTypeProcessor"
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "'{{?scheme}}' != ''"
+ steps:
+ - setProperty:
+ name: CamelDataType
+ simple: "{{?scheme}}:{{format}}"
+ otherwise:
+ steps:
+ - setProperty:
+ name: CamelDataType
+ simple: "{{format}}"
+ - bean:
+ ref: "{{dataTypeProcessor}}"
+ method: process
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: databricks-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIj4KICA8cGF0aCBmaWxsPSIjRkYzNjIxIiBkPSJNMjAgMEw0MCA4LjI3VjEzLjFMMjAgMjAuNUwwIDEzLjFWOC4yN0wyMCAwWiIvPgogIDxwYXRoIGZpbGw9IiNGRjM2MjEiIGQ9Ik0wIDEzLjFMMjAgMjAuNVYyNi45TDAgMTkuNVYxMy4xWiIvPgogIDxwYXRoIGZpbGw9IiNGRjM2MjEiIGQ9Ik00MCAxMy4xTDIwIDIwLjVWMjYuOUw0MCAxOS41VjEzLjFaIi8+CiAgPHBhdGggZmlsbD0iI0ZGMzYyMSIgZD0iTTAgMTkuNUwyMC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "SQL"
+ camel.apache.org/kamelet.namespace: "Database"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Databricks Sink"
+ description: Send data to a Databricks Database. This Kamelet expects a JSON-formatted body. Use key:value pairs to map the JSON fields and parameters. For Unity Catalog workspaces, specify catalog and schema parameters.
+ required:
+ - serverHostname
+ - httpPath
+ - accessToken
+ - query
+ type: object
+ properties:
+ serverHostname:
+ title: Server Hostname
+ description: The Databricks server hostname.
+ type: string
+ example: adb-1234567890123456.7.azuredatabricks.net
+ serverPort:
+ title: Server Port
+ description: The server port for the Databricks data source.
+ type: string
+ default: 443
+ httpPath:
+ title: HTTP Path
+ description: The HTTP path to the Databricks SQL Warehouse or cluster.
+ type: string
+ example: /sql/1.0/warehouses/abc123def456
+ accessToken:
+ title: Access Token
+ description: The personal access token to access Databricks.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ query:
+ title: Query
+ description: The query to execute against the Databricks Database.
+ type: string
+ example: 'INSERT INTO accounts (username,city) VALUES (:#username,:#city)'
+ extraOptions:
+ title: Extra Options
+ description: Additional JDBC connection options (e.g., ConnCatalog=main;ConnSchema=default).
+ type: string
+ default: ''
+ types:
+ in:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:sql"
+ - "mvn:com.databricks:databricks-jdbc:3.0.7"
+ - "mvn:org.apache.commons:commons-dbcp2:2.14.0"
+ template:
+ beans:
+ - name: local-sql-databricks-sink
+ type: "#class:org.apache.camel.component.sql.SqlComponent"
+ properties:
+ autowiredEnabled: "false"
+ - name: dsBean
+ type: "#class:org.apache.commons.dbcp2.BasicDataSource"
+ properties:
+ password: '{{accessToken}}'
+ url: 'jdbc:databricks://{{serverHostname}}:{{serverPort}};httpPath={{httpPath}};AuthMech=3;transportMode=http;ssl=1;UID=token;PWD={{accessToken}}{{extraOptions}}'
+ driverClassName: 'com.databricks.client.jdbc.Driver'
+ from:
+ uri: "kamelet:source"
+ steps:
+ - unmarshal:
+ json:
+ library: Jackson
+ - to:
+ uri: "{{local-sql-databricks-sink}}:{{query}}"
+ parameters:
+ dataSource: "#bean:{{dsBean}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: databricks-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIj4KICA8cGF0aCBmaWxsPSIjRkYzNjIxIiBkPSJNMjAgMEw0MCA4LjI3VjEzLjFMMjAgMjAuNUwwIDEzLjFWOC4yN0wyMCAwWiIvPgogIDxwYXRoIGZpbGw9IiNGRjM2MjEiIGQ9Ik0wIDEzLjFMMjAgMjAuNVYyNi45TDAgMTkuNVYxMy4xWiIvPgogIDxwYXRoIGZpbGw9IiNGRjM2MjEiIGQ9Ik00MCAxMy4xTDIwIDIwLjVWMjYuOUw0MCAxOS41VjEzLjFaIi8+CiAgPHBhdGggZmlsbD0iI0ZGMzYyMSIgZD0iTTAgMTkuNUwyMC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "SQL"
+ camel.apache.org/kamelet.namespace: "Database"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Databricks Source"
+ description: Query data from a Databricks Database. For Unity Catalog workspaces, specify catalog and schema parameters.
+ required:
+ - serverHostname
+ - httpPath
+ - accessToken
+ - query
+ type: object
+ properties:
+ serverHostname:
+ title: Server Hostname
+ description: The Databricks server hostname.
+ type: string
+ example: adb-1234567890123456.7.azuredatabricks.net
+ serverPort:
+ title: Server Port
+ description: The server port for the Databricks data source.
+ type: string
+ default: 443
+ httpPath:
+ title: HTTP Path
+ description: The HTTP path to the Databricks SQL Warehouse or cluster.
+ type: string
+ example: /sql/1.0/warehouses/abc123def456
+ accessToken:
+ title: Access Token
+ description: The personal access token to access Databricks.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ query:
+ title: Query
+ description: The query to execute against the Databricks Database.
+ type: string
+ example: 'SELECT * FROM accounts'
+ extraOptions:
+ title: Extra Options
+ description: Additional JDBC connection options (e.g., ConnCatalog=main;ConnSchema=default).
+ type: string
+ default: ''
+ consumedQuery:
+ title: Consumed Query
+ description: A query to run on a tuple consumed.
+ type: string
+ example: 'DELETE FROM accounts where user_id = :#user_id'
+ delay:
+ title: Delay
+ description: The number of milliseconds before the next poll from the Databricks database.
+ type: integer
+ default: 500
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:sql"
+ - "mvn:com.databricks:databricks-jdbc:3.0.7"
+ - "mvn:org.apache.commons:commons-dbcp2:2.14.0"
+ template:
+ beans:
+ - name: local-sql-databricks-source
+ type: "#class:org.apache.camel.component.sql.SqlComponent"
+ properties:
+ autowiredEnabled: "false"
+ - name: dsBean
+ type: "#class:org.apache.commons.dbcp2.BasicDataSource"
+ properties:
+ password: '{{accessToken}}'
+ url: 'jdbc:databricks://{{serverHostname}}:{{serverPort}};httpPath={{httpPath}};AuthMech=3;transportMode=http;ssl=1;UID=token;PWD={{accessToken}}{{extraOptions}}'
+ driverClassName: 'com.databricks.client.jdbc.Driver'
+ from:
+ uri: "{{local-sql-databricks-source}}:{{query}}"
+ parameters:
+ dataSource: "#bean:{{dsBean}}"
+ onConsume: "{{?consumedQuery}}"
+ delay: "{{delay}}"
+ steps:
+ - marshal:
+ json:
+ library: Jackson
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: delay-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIyLjg4IDEwMC42IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMjIuODggMTAwLjYiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiMyNzI3Mjc7fSAuc3Qxe2ZpbGwtcnVsZTpldmVub2 [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Delay"
+ camel.apache.org/kamelet.namespace: "EIP"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Delay Action"
+ description: Delay the processing using a specific amount of time
+ required:
+ - milliseconds
+ type: object
+ properties:
+ milliseconds:
+ title: Milliseconds
+ description: The number of milliseconds of delay
+ type: integer
+ example: 1000
+ dependencies:
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - delay:
+ constant: "{{milliseconds}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: djl-image-to-text-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Preview"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+Cjxzdmcgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDU1OCA1MjIiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgeG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "AI"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Image-to-Text Action"
+ description: Detect and classify objects in an image into texts using the SSD and ResNet models and the ImageNet dataset.
+ type: object
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "mvn:ai.djl.pytorch:pytorch-engine:0.29.0"
+ - "mvn:ai.djl.pytorch:pytorch-model-zoo:0.29.0"
+ - "camel:core"
+ - "camel:kamelet"
+ - "camel:jackson"
+ - "camel:djl"
+ template:
+ beans:
+ - name: imageNetUtil
+ type: "#class:org.apache.camel.component.djl.ImageNetUtil"
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to: "djl:cv/object_detection?artifactId=ssd"
+ - convertBodyTo: "ai.djl.modality.cv.Image[]"
+ - split:
+ expression:
+ simple: "${body}"
+ aggregationStrategy: "#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+ steps:
+ - to: "djl:cv/image_classification?artifactId=resnet"
+ # The output from the image classification model is classified
+ # as one of 1000 labels from WordNet.
+ # Since it's too fine-grained, we want to find the higher-level
+ # group (= hypernym) for the classification using the WordNet
+ # dictionary.
+ - bean:
+ ref: "{{imageNetUtil}}"
+ method: extractClassName
+ - bean:
+ ref: "{{imageNetUtil}}"
+ method: addHypernym
+ - marshal:
+ json: {}
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: dns-dig-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIyLjg3OSAxMjIuODgxIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMjIuODc5IDEyMi44ODEiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGQ9Ik0xMDkuNDY3LDg5LjUwNWMwLjE4MiwwLDAuMzU5LDAuMDE5LDAuNTMxLDAuMDUzYzEuMT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "DNS"
+ camel.apache.org/kamelet.namespace: "Networking"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "DNS DIG Action"
+ description: Query a DNS through Dig.
+ type: object
+ dependencies:
+ - "camel:core"
+ - "camel:dns"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[domain-name]}"
+ steps:
+ - setHeader:
+ name: dns.name
+ simple: "${header[domain-name]}"
+ - simple: "${header[ce-domainname]}"
+ steps:
+ - setHeader:
+ name: dns.name
+ simple: "${header[ce-domainname]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: dns.name
+ simple: "${body}"
+ - choice:
+ when:
+ - simple: "${header[dns-type]}"
+ steps:
+ - setHeader:
+ name: dns.type
+ simple: "${header[dns-type]}"
+ - simple: "${header[ce-dnstype]}"
+ steps:
+ - setHeader:
+ name: dns.type
+ simple: "${header[ce-dnstype]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: dns.type
+ constant: "A"
+ - to:
+ uri: "dns:dig"
+ - convertBodyTo:
+ type: "java.lang.String"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: dns-ip-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIyLjg3OSAxMjIuODgxIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMjIuODc5IDEyMi44ODEiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGQ9Ik0xMDkuNDY3LDg5LjUwNWMwLjE4MiwwLDAuMzU5LDAuMDE5LDAuNTMxLDAuMDUzYzEuMT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "DNS"
+ camel.apache.org/kamelet.namespace: "Networking"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "DNS IP Action"
+ description: Get an IP from a DNS
+ type: object
+ dependencies:
+ - "camel:core"
+ - "camel:dns"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[domain]}"
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${header[domain]}"
+ - simple: "${header[ce-domain]}"
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${header[ce-domain]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${body}"
+ - to:
+ uri: "dns:ip"
+ - convertBodyTo:
+ type: "java.lang.String"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: dns-lookup-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIyLjg3OSAxMjIuODgxIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMjIuODc5IDEyMi44ODEiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGQ9Ik0xMDkuNDY3LDg5LjUwNWMwLjE4MiwwLDAuMzU5LDAuMDE5LDAuNTMxLDAuMDUzYzEuMT [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "DNS"
+ camel.apache.org/kamelet.namespace: "Networking"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "DNS Lookup Action"
+ description: Lookup for a domain
+ type: object
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:dns"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[domain-name]}"
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${header[domain-name]}"
+ - simple: "${header[ce-domainname]}"
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${header[ce-domainname]}"
+ otherwise:
+ steps:
+ - setHeader:
+ name: dns.domain
+ simple: "${body}"
+ - to:
+ uri: "dns:lookup"
+ - marshal:
+ json: {}
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: drop-field-action
+ labels:
+ camel.apache.org/kamelet.type: "action"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+spec:
+ definition:
+ title: "Drop Field Action"
+ description: Removes a custom field by given name from the message in transit.
+ required:
+ - field
+ properties:
+ field:
+ title: Field
+ description: The name of the field to be removed
+ type: string
+ type: object
+ dependencies:
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:kafka"
+ template:
+ beans:
+ - name: dropField
+ type: "#class:org.apache.camel.component.kafka.transform.DropField"
+ properties:
+ field: '{{field}}'
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[Content-Type]} == 'application/json'"
+ steps:
+ - setProperty:
+ name: deserialized
+ constant: "true"
+ - unmarshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - process:
+ ref: "{{dropField}}"
+ - choice:
+ when:
+ - simple: "${exchangeProperty[deserialized]} == 'true'"
+ steps:
+ - marshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - setHeader:
+ name: "Content-Type"
+ constant: "application/json"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: drop-header-action
+ labels:
+ camel.apache.org/kamelet.type: "action"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "EIP"
+spec:
+ definition:
+ title: "Drop Header Action"
+ description: "Remove an header from the message in transit."
+ required:
+ - name
+ properties:
+ name:
+ title: Name
+ description: The name of the header to be removed.
+ type: string
+ example: headername
+ type: object
+ dependencies:
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - removeHeader:
+ name: "{{name}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: drop-headers-action
+ labels:
+ camel.apache.org/kamelet.type: "action"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "EIP"
+spec:
+ definition:
+ title: "Drop Headers Action"
+ description: "Remove headers from the message in transit based on a pattern."
+ required:
+ - pattern
+ properties:
+ pattern:
+ title: Pattern
+ description: Name or pattern of headers to remove. The pattern is matched in the following order, 1 = exact match 2 = wildcard (pattern ends with a and the name starts with the pattern) 3 = regular expression (all of above is case in-sensitive).
+ type: string
+ example: Camel*
+ excludePattern:
+ title: Exclusion Pattern
+ description: Name or pattern of headers to not remove. The pattern is matched in the following order, 1 = exact match 2 = wildcard (pattern ends with a and the name starts with the pattern) 3 = regular expression (all of above is case in-sensitive).
+ type: string
+ example: Camel*
+ type: object
+ dependencies:
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - removeHeaders:
+ pattern: "{{pattern}}"
+ excludePattern: "{{?excludePattern}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: dropbox-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjQzcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQzIDQwIiB2ZXJzaW9uPSIxLjEiIGhlaWdodD0iNDBweCI+CiA8cGF0aCBkPSJtMTIuNSAwbC0xMi41IDguMSA4LjcgNyAxMi41LTcuOC04LjctNy4zem0tMTIuNSAyMS45bDEyLjUgOC4yIDguNy03LjMtMTIuNS03LjctOC43IDYuOHptMjEuMiAwLjlsOC44IDcuMyAxMi40LTguMS04LjYtNi45LTEyLjYgNy43em0yMS4yLTE0LjdsLTEyLjQtOC4xLTguOC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Dropbox"
+ camel.apache.org/kamelet.namespace: "Cloud"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Dropbox Sink"
+ description: Upload Files to Dropbox.
+ required:
+ - accessToken
+ - clientIdentifier
+ - remotePath
+ - uploadMode
+ type: object
+ properties:
+ accessToken:
+ title: Dropbox Access Token
+ description: The access Token to use to access Dropbox
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientIdentifier:
+ title: Client Identifier
+ description: Dropbox App client Identifier
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ remotePath:
+ title: Remote Path
+ description: Original file or folder to work with
+ type: string
+ uploadMode:
+ title: Upload Mode
+ description: The uploading mode in case a file with the same name exists on Dropbox. Choose `add` or `force`. With `add`, the new file is renamed. With `force`, the existing file is overwritten.
+ type: string
+ default: add
+ dependencies:
+ - "camel:core"
+ - "camel:dropbox"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - choice:
+ when:
+ - simple: "${header[file]}"
+ steps:
+ - setHeader:
+ name: CamelDropboxPutFileName
+ simple: "${header[file]}"
+ - simple: "${header[ce-file]}"
+ steps:
+ - setHeader:
+ name: CamelDropboxPutFileName
+ simple: "${header[ce-file]}"
+ - to:
+ uri: 'dropbox:put'
+ parameters:
+ accessToken: '{{accessToken}}'
+ remotePath: '{{remotePath}}'
+ clientIdentifier: '{{clientIdentifier}}'
+ uploadMode: '{{uploadMode}}'
+
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: dropbox-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjQzcHgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDQzIDQwIiB2ZXJzaW9uPSIxLjEiIGhlaWdodD0iNDBweCI+CiA8cGF0aCBkPSJtMTIuNSAwbC0xMi41IDguMSA4LjcgNyAxMi41LTcuOC04LjctNy4zem0tMTIuNSAyMS45bDEyLjUgOC4yIDguNy03LjMtMTIuNS03LjctOC43IDYuOHptMjEuMiAwLjlsOC44IDcuMyAxMi40LTguMS04LjYtNi45LTEyLjYgNy43em0yMS4yLTE0LjdsLTEyLjQtOC4xLTguOC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Dropbox"
+ camel.apache.org/kamelet.namespace: "Cloud"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "Dropbox Source"
+ description: Consume Files from Dropbox.
+ required:
+ - period
+ - accessToken
+ - clientIdentifier
+ - remotePath
+ - query
+ type: object
+ properties:
+ period:
+ title: Period between Polls
+ description: The interval between fetches to the Dropbox remote path in milliseconds
+ type: integer
+ default: 10000
+ accessToken:
+ title: Dropbox Access Token
+ description: The access Token to use to access Dropbox
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ clientIdentifier:
+ title: Client Identifier
+ description: Dropbox App client Identifier
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ remotePath:
+ title: Remote Path
+ description: Original file or folder to work with
+ type: string
+ query:
+ title: Queries
+ description: A space-separated list of sub-strings to search for. A file matches only if it contains all the sub-strings. If this option is not set, all files is matched.
+ type: string
+ dependencies:
+ - "camel:dropbox"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jsonpath"
+ - "camel:timer"
+ template:
+ from:
+ uri: "timer:dropbox-stream"
+ parameters:
+ period: "{{period}}"
+ steps:
+ - to:
+ uri: "dropbox:search"
+ parameters:
+ accessToken: "{{accessToken}}"
+ remotePath: "{{remotePath}}"
+ clientIdentifier: "{{clientIdentifier}}"
+ query: "{{query}}"
+ - split:
+ jsonpath: "$.*"
+ steps:
+ - setProperty:
+ name: dropboxFileName
+ simple: ${body.metadata.pathDisplay}
+ - toD: "dropbox:get?accessToken={{accessToken}}&clientIdentifier={{clientIdentifier}}&remotePath=${exchangeProperty.dropboxFileName}"
+ - to: "kamelet:sink"
+ - toD: "dropbox:del?accessToken={{accessToken}}&clientIdentifier={{clientIdentifier}}&remotePath=${exchangeProperty.dropboxFileName}"
+
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: earthquake-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzEwMHB4JyB3aWR0aD0nMTAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwLjAwMyA3OS45OTciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDEwMC4wMDMgNzkuOTk3IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBkPSJNODEuNjUzLDQyLjk0Yy0xLjM4NywwLTIuNjY2LDAuNzY3LTMuMzE1LDEuOTkyTDcyLjk0Miw1NS4xbC02Lj [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Earthquake"
+ camel.apache.org/kamelet.namespace: "Dataset"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+ camel.apache.org/kamelet.verified: "true"
+spec:
+ definition:
+ title: "Earthquake Source"
+ description: Get data about current earthquake events happening in the world using the USGS API
+ type: object
+ properties:
+ period:
+ title: Period between Polls
+ description: The interval between fetches to the earthquake API in milliseconds.
+ type: integer
+ default: 60000
+ lookAhead:
+ title: Look-ahead Minutes
+ description: The amount of minutes to look ahead when starting the integration afresh.
+ type: integer
+ default: 120
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:caffeine"
+ - "camel:http"
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:jsonpath"
+ - "camel:timer"
+ template:
+ from:
+ uri: "timer:earthquake"
+ parameters:
+ period: "{{period}}"
+ steps:
+ - setHeader:
+ name: CamelCaffeineAction
+ constant: GET
+ - toD: "caffeine-cache:cache-${routeId}?key=lastUpdate"
+ - choice:
+ when:
+ - simple: "${header.CamelCaffeineActionHasResult}"
+ steps:
+ - setProperty:
+ name: lastUpdate
+ simple: "${body}"
+ otherwise:
+ steps:
+ - setProperty:
+ name: lastUpdate
+ simple: "${date-with-timezone:now-{{lookAhead}}m:UTC:yyyy-MM-dd'T'HH:mm:ss.SSS}"
+ - setHeader:
+ name: CamelHttpMethod
+ constant: GET
+ - toD: "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&updatedafter=${exchangeProperty.lastUpdate}&orderby=time-asc"
+ - removeHeader:
+ name: CamelHttpMethod
+ - unmarshal:
+ json: {}
+ - setProperty:
+ name: generated
+ simple: "${body[metadata][generated]}"
+ - setProperty:
+ name: lastUpdate
+ simple: "${date-with-timezone:exchangeProperty.generated:UTC:yyyy-MM-dd'T'HH:mm:ss.SSS}"
+ - claimCheck:
+ operation: Push
+ - setBody:
+ exchange-property: lastUpdate
+ - setHeader:
+ name: CamelCaffeineAction
+ constant: PUT
+ - toD: "caffeine-cache:cache-${routeId}?key=lastUpdate"
+ - claimCheck:
+ operation: Pop
+ - split:
+ jsonpath: "$.features[*]"
+ steps:
+ - marshal:
+ json: {}
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: elasticsearch-index-sink
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.group: "ElasticSearch"
+ camel.apache.org/kamelet.namespace: "Search"
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1NTAgMjUwIiB2aWV3Qm94PSI3Nyw4Myw0MTAsOTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiA8cGF0aCBkPSJtMTc4IDEwMi41aDMxM3Y0MWgtMzEzeiIgZmlsbD0ibm9uZSIvPgogPGcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyI+CiAgPHBhdGggZD0ibTE5My4zIDEzOS40Yy00IDAtNy4yLTEuMi05LjUtMy41cy0zLjQtNS42LTMuNC05LjdjMC00LjIgMS4xLTcuNiAzLjItMTBzNS0zLjYgOC43LTMuNmMzLjQgMCA2Lj [...]
+spec:
+ definition:
+ title: "ElasticSearch Index Sink"
+ description: Stores JSON-formatted data into ElasticSearch.
+ required:
+ - clusterName
+ - hostAddresses
+ type: object
+ properties:
+ user:
+ title: Username
+ description: The username to connect to ElasticSearch.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password to connect to ElasticSearch.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ enableSSL:
+ title: Enable SSL
+ description: Specifies to connect by using SSL.
+ type: boolean
+ default: true
+ hostAddresses:
+ title: Host Addresses
+ description: A comma-separated list of remote transport addresses in `ip:port format`.
+ type: string
+ example: quickstart-es-http:9200
+ clusterName:
+ title: ElasticSearch Cluster Name
+ description: The name of the ElasticSearch cluster.
+ type: string
+ example: quickstart
+ indexName:
+ title: Index in ElasticSearch
+ description: The name of the ElasticSearch index.
+ type: string
+ example: data
+ certificate:
+ title: Certificate
+ description: The Certificate for accessing the Elasticsearch cluster. You must encode this value in base64.
+ type: string
+ types:
+ out:
+ mediaType: text/plain
+ in:
+ mediaType: application/json
+ dependencies:
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:kamelet"
+ - "camel:elasticsearch"
+ - "camel:gson"
+ - "camel:bean"
+ template:
+ beans:
+ - name: local-es
+ type: "#class:org.apache.camel.component.es.ElasticsearchComponent"
+ properties:
+ user: "{{?user}}"
+ password: "{{?password}}"
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[indexId]}"
+ steps:
+ - setHeader:
+ name: "indexId"
+ simple: "${header[indexId]}"
+ - simple: "${header[ce-indexid]}"
+ steps:
+ - setHeader:
+ name: "indexId"
+ simple: "${header[ce-indexid]}"
+ - choice:
+ when:
+ - simple: "${header[indexName]}"
+ steps:
+ - setHeader:
+ name: "indexName"
+ simple: "${header[indexName]}"
+ - simple: "${header[ce-indexname]}"
+ steps:
+ - setHeader:
+ name: "indexName"
+ simple: "${header[ce-indexname]}"
+ - unmarshal:
+ json: {}
+ - to:
+ uri: "{{local-es}}:{{clusterName}}"
+ parameters:
+ operation: "INDEX"
+ hostAddresses: "{{hostAddresses}}"
+ enableSSL: "{{enableSSL}}"
+ indexName: "{{?indexName}}"
+ certificatePath: "base64:{{?certificate}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: elasticsearch-search-source
+ labels:
+ camel.apache.org/kamelet.type: "source"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.group: "ElasticSearch"
+ camel.apache.org/kamelet.namespace: "Search"
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1NTAgMjUwIiB2aWV3Qm94PSI3Nyw4Myw0MTAsOTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiA8cGF0aCBkPSJtMTc4IDEwMi41aDMxM3Y0MWgtMzEzeiIgZmlsbD0ibm9uZSIvPgogPGcgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyI+CiAgPHBhdGggZD0ibTE5My4zIDEzOS40Yy00IDAtNy4yLTEuMi05LjUtMy41cy0zLjQtNS42LTMuNC05LjdjMC00LjIgMS4xLTcuNiAzLjItMTBzNS0zLjYgOC43LTMuNmMzLjQgMCA2Lj [...]
+spec:
+ definition:
+ title: "ElasticSearch Search Source"
+ description: Search data on ElasticSearch
+ required:
+ - query
+ - clusterName
+ - indexName
+ - hostAddresses
+ type: object
+ properties:
+ period:
+ title: Period
+ description: The time interval between two searches
+ type: integer
+ default: 1000
+ query:
+ title: Query
+ description: The query we want to use to search on ElasticSearch.
+ type: string
+ user:
+ title: Username
+ description: Username to connect to ElasticSearch.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: Password to connect to ElasticSearch.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ enableSSL:
+ title: Enable SSL
+ description: Do we want to connect using SSL?
+ type: boolean
+ default: true
+ hostAddresses:
+ title: Host Addresses
+ description: Comma separated list with ip:port formatted remote transport addresses to use.
+ type: string
+ indexName:
+ title: Index in ElasticSearch
+ description: The name of the index to act against.
+ type: string
+ clusterName:
+ title: ElasticSearch Cluster Name
+ description: The name of the cluster.
+ type: string
+ certificate:
+ title: Certificate
+ description: The Certificate for accessing the Elasticsearch cluster. You must encode this value in base64.
+ type: string
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:core"
+ - "camel:kamelet"
+ - "camel:timer"
+ - "camel:elasticsearch"
+ - "camel:gson"
+ template:
+ beans:
+ - name: local-es
+ type: "#class:org.apache.camel.component.es.ElasticsearchComponent"
+ properties:
+ user: "{{?user}}"
+ password: "{{?password}}"
+ from:
+ uri: timer:tick
+ parameters:
+ period: "{{period}}"
+ steps:
+ - setBody:
+ constant: "{{query?nested=false}}"
+ - to:
+ uri: "{{local-es}}:{{clusterName}}"
+ parameters:
+ operation: "SEARCH"
+ indexName: "{{indexName}}"
+ hostAddresses: "{{hostAddresses}}"
+ enableSSL: "{{enableSSL}}"
+ certificatePath: "base64:{{?certificate}}"
+ - marshal:
+ json:
+ library: Gson
+ - to: kamelet:sink
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: exec-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDIwMDEwOTA0Ly9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy1TVkctMjAwMTA5MDQvRFREL3N2ZzEwLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4wIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiB3aWR0aD0iMTI4MC4wMDAwMDBwdCIgaGVpZ2h0PSIxMDEyLjAwMDAwMHB0IiB2aWV3Qm94PSIwIDAgMTI4MC4wMDAwMDAgMTAxMi4wMDAwMDAiCiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZW [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Exec"
+ camel.apache.org/kamelet.namespace: "System"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "Exec Sink"
+ description: Execute system commands
+ required:
+ - executable
+ type: object
+ properties:
+ executable:
+ title: Executable Command
+ description: The command to execute
+ type: string
+ dependencies:
+ - "camel:core"
+ - "camel:exec"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[args]}"
+ steps:
+ - setHeader:
+ name: CamelExecCommandArgs
+ simple: "${header[args]}"
+ - simple: "${header[ce-args]}"
+ steps:
+ - setHeader:
+ name: CamelExecCommandArgs
+ simple: "${header[ce-args]}"
+ - to:
+ uri: "exec:{{executable}}"
+ - setBody:
+ simple: "${body.stdout}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: extract-field-action
+ labels:
+ camel.apache.org/kamelet.type: "action"
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+spec:
+ definition:
+ title: "Extract Field Action"
+ description: Extract a field from the message body.
+ required:
+ - field
+ properties:
+ field:
+ title: Field
+ description: The name of the field to extract
+ type: string
+ headerOutput:
+ title: Header Output
+ description: If enable the action will store the extracted field in an header named CamelKameletsExtractFieldName
+ type: boolean
+ default: false
+ headerOutputName:
+ title: Header Output Name
+ description: A custom name for the header containing the extracted field
+ default: "none"
+ type: string
+ strictHeaderCheck:
+ title: Strict Header Check
+ description: If enabled the action will check if the header output name (custom or default) has been used already in the exchange. If so, the extracted field is stored in the message body, if not, the extracted field is stored in the selected header (custom or default).
+ type: boolean
+ default: false
+ trimField:
+ title: Trim Field
+ description: If enabled we return the Raw extracted field
+ type: boolean
+ default: false
+ type: object
+ dependencies:
+ - "camel:kamelet"
+ - "camel:core"
+ - "camel:jackson"
+ - "camel:kafka"
+ template:
+ beans:
+ - name: extractField
+ type: "#class:org.apache.camel.component.kafka.transform.ExtractField"
+ properties:
+ field: '{{field}}'
+ headerOutput: '{{headerOutput}}'
+ headerOutputName: '{{headerOutputName}}'
+ strictHeaderCheck: '{{strictHeaderCheck}}'
+ trimField: '{{trimField}}'
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ when:
+ - simple: "${header[Content-Type]} == 'application/json'"
+ steps:
+ - setProperty:
+ name: deserialized
+ constant: "true"
+ - unmarshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - process:
+ ref: "{{extractField}}"
+ - choice:
+ when:
+ - simple: "${exchangeProperty[trimField]} == 'false'"
+ steps:
+ - choice:
+ when:
+ - simple: "${exchangeProperty[deserialized]} == 'true'"
+ steps:
+ - marshal:
+ json:
+ library: Jackson
+ unmarshalType: com.fasterxml.jackson.databind.JsonNode
+ - setHeader:
+ name: "Content-Type"
+ constant: "application/json"
+---
+
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: fhir-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTUuMiAzMDAiPjxzdHlsZT48L3N0eWxlPjxnIGlkPSJMYXllcl8yIj48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzFfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjYyLjY0NCIgeTE9IjI2OC4yMDEiIHgyPSIzMC43MjEiIHkyPSI4Ny4xNTUiPjxzdG9wIG9mZnNldD0iLjE1NCIgc3RvcC1jb2xvcj0iI2ZmZTQwZSIvPjxzdG9wIG9mZnNldD0iLjkxIiBzdG9wLWNvbG9yPSIjZTEwZTE5Ii8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSJNNzkuNiA3OC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "FHIR"
+ camel.apache.org/kamelet.namespace: "API"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "FHIR Sink"
+ description: Forward data to a FHIR endpoint.
+ required:
+ - serverUrl
+ - methodName
+ type: object
+ properties:
+ apiName:
+ title: API Name
+ description: "What kind of operation to perform."
+ type: string
+ enum: ["CAPABILITIES", "CREATE", "DELETE", "HISTORY", "LOAD_PAGE", "META", "OPERATION", "PATCH", "READ", "SEARCH", "TRANSACTION", "UPDATE", "VALIDATE"]
+ methodName:
+ title: Method Name
+ description: "What sub operation to use for the selected operation."
+ type: string
+ encoding:
+ title: Encoding
+ description: "Encoding to use for all request. One of: [JSON] [XML]."
+ type: string
+ default: "JSON"
+ fhirVersion:
+ title: FHIR Version
+ description: "The FHIR Version to use."
+ type: string
+ enum: ["DSTU2", "DSTU2_HL7ORG", "DSTU2_1", "DSTU3", "R4", "R5"]
+ default: "R4"
+ log:
+ title: Log
+ description: "Will log every requests and responses."
+ type: boolean
+ default: false
+ prettyPrint:
+ title: Pretty Print
+ description: "Pretty print all request."
+ type: boolean
+ default: false
+ serverUrl:
+ title: Server URL
+ description: The FHIR server base URL.
+ type: string
+ lazyStartProducer:
+ title: Lazy Start Producer
+ description: "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the [...]
+ type: boolean
+ default: false
+ proxyHost:
+ title: Proxy Host
+ description: The proxy host.
+ type: string
+ proxyPassword:
+ title: Proxy Password
+ description: The proxy password.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ proxyPort:
+ title: Proxy Port
+ description: The proxy port.
+ type: integer
+ proxyUser:
+ title: Proxy User
+ description: The proxy username.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ accessToken:
+ title: Access Token
+ description: OAuth access token.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ username:
+ title: Username
+ description: Username to use for basic authentication.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: Password to use for basic authentication.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ dependencies:
+ - "camel:fhir"
+ - "camel:core"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: kamelet:source
+ steps:
+ - choice:
+ precondition: true
+ when:
+ - simple: "${properties:encoding} =~ 'JSON'"
+ steps:
+ - unmarshal:
+ fhirJson:
+ fhirVersion: "{{fhirVersion}}"
+ prettyPrint: "{{prettyPrint}}"
+ - simple: "${properties:encoding} =~ 'XML'"
+ steps:
+ - unmarshal:
+ fhirXml:
+ fhirVersion: "{{fhirVersion}}"
+ prettyPrint: "{{prettyPrint}}"
+ - to:
+ uri: "fhir://{{apiName}}/{{methodName}}"
+ parameters:
+ serverUrl: "{{serverUrl}}"
+ inBody: "resource"
+ encoding: "{{encoding}}"
+ fhirVersion: "{{fhirVersion}}"
+ log: "{{log}}"
+ prettyPrint: "{{prettyPrint}}"
+ lazyStartProducer: "{{lazyStartProducer}}"
+ proxyHost: "{{?proxyHost}}"
+ proxyPassword: "{{?proxyPassword}}"
+ proxyPort: "{{?proxyPort}}"
+ proxyUser: "{{?proxyUser}}"
+ accessToken: "{{?accessToken}}"
+ username: "{{?username}}"
+ password: "{{?password}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: fhir-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTUuMiAzMDAiPjxzdHlsZT48L3N0eWxlPjxnIGlkPSJMYXllcl8yIj48bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzFfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjYyLjY0NCIgeTE9IjI2OC4yMDEiIHgyPSIzMC43MjEiIHkyPSI4Ny4xNTUiPjxzdG9wIG9mZnNldD0iLjE1NCIgc3RvcC1jb2xvcj0iI2ZmZTQwZSIvPjxzdG9wIG9mZnNldD0iLjkxIiBzdG9wLWNvbG9yPSIjZTEwZTE5Ii8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSJNNzkuNiA3OC [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "FHIR"
+ camel.apache.org/kamelet.namespace: "API"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "FHIR Source"
+ description: Receive data from FHIR server.
+ required:
+ - serverUrl
+ - username
+ - password
+ type: object
+ properties:
+ serverUrl:
+ title: Server URL
+ description: The FHIR server url.
+ type: string
+ url:
+ title: URL
+ description: The FHIR resource type url.
+ type: string
+ default: "/Patient"
+ encoding:
+ title: Encoding
+ description: Encoding to use for all request.
+ type: string
+ default: "JSON"
+ enum: ["JSON", "XML"]
+ fhirVersion:
+ title: FHIR Version
+ description: The FHIR Version to use.
+ type: string
+ default: "R4"
+ enum: ["DSTU2", "DSTU2_HL7ORG", "DSTU2_1", "DSTU3", "R4", "R5"]
+ username:
+ title: Username
+ description: The username to access the FHIR server.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password to access the FHIR server.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ prettyPrint:
+ title: Json Pretty Print
+ description: Define if the Json must be pretty print or not.
+ type: boolean
+ default: true
+ types:
+ out:
+ mediaType: application/json
+ dependencies:
+ - "camel:fhir"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "fhir://search/searchByUrl"
+ parameters:
+ serverUrl: "{{serverUrl}}"
+ url: "{{url}}"
+ encoding: "{{encoding}}"
+ fhirVersion: "{{fhirVersion}}"
+ prettyPrint: "{{prettyPrint}}"
+ username: "{{username}}"
+ password: "{{password}}"
+ steps:
+ - marshal:
+ fhirJson:
+ fhirVersion: "{{fhirVersion}}"
+ prettyPrint: "{{prettyPrint}}"
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: file-watch-source
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzY4LjU1MyAzNjguNTUzIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bm [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "File Watch"
+ camel.apache.org/kamelet.namespace: "File"
+ labels:
+ camel.apache.org/kamelet.type: "source"
+spec:
+ definition:
+ title: "File Watch Source"
+ description: Receive events related to a file or folder. It may require a volume mounting on Kubernetes.
+ required:
+ - filePath
+ - events
+ type: object
+ properties:
+ filePath:
+ title: Path to Watch
+ description: Path of file or folder to watch
+ type: string
+ events:
+ title: Events
+ description: The type of events to consume
+ type: string
+ default: "CREATE,MODIFY,DELETE"
+ dependencies:
+ - "camel:file-watch"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "file-watch:{{filePath}}"
+ parameters:
+ events: "{{events}}"
+ steps:
+ - to: "kamelet:sink"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: freemarker-template-action
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "Actions"
+ camel.apache.org/kamelet.namespace: "Transformation"
+ labels:
+ camel.apache.org/kamelet.type: "action"
+spec:
+ definition:
+ title: "Freemarker Template Action"
+ description: Apply a Freemarker Template.
+ required:
+ - template
+ type: object
+ properties:
+ template:
+ title: Template
+ description: The inline template
+ type: string
+ example: "file:////template.ftl"
+ pattern: "^(http|https|file|classpath|ref|bean)://.*"
+ dependencies:
+ - "camel:freemarker"
+ - "camel:kamelet"
+ template:
+ from:
+ uri: "kamelet:source"
+ steps:
+ - to:
+ uri: "freemarker:"
+ parameters:
+ resourceUri: "{{template}}"
+---
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+ name: ftp-sink
+ annotations:
+ camel.apache.org/kamelet.support.level: "Stable"
+ camel.apache.org/catalog.version: "4.18.0"
+ camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyMjEuMSAzMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwID [...]
+ camel.apache.org/provider: "Apache Software Foundation"
+ camel.apache.org/kamelet.group: "FTP"
+ camel.apache.org/kamelet.namespace: "File"
+ labels:
+ camel.apache.org/kamelet.type: "sink"
+spec:
+ definition:
+ title: "FTP Sink"
+ description: Send data to an FTP server.
+ required:
+ - connectionHost
+ - connectionPort
+ - username
+ - password
+ - directoryName
+ type: object
+ properties:
+ connectionHost:
+ title: Connection Host
+ description: The hostname of the FTP server.
+ type: string
+ connectionPort:
+ title: Connection Port
+ description: The port of the FTP server.
+ type: string
+ default: 21
+ username:
+ title: Username
+ description: The username to access the FTP server.
+ type: string
+ x-descriptors:
+ - urn:camel:group:credentials
+ password:
+ title: Password
+ description: The password to access the FTP server.
+ type: string
+ format: password
+ x-descriptors:
... 18091 lines suppressed ...
(camel-karavan) 01/33: Java Code for 4.18.0
Posted by ma...@apache.org.
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 ae55144b924c4d6dfdf23cba3f08ba488081bbd2
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 15:45:01 2026 -0500
Java Code for 4.18.0
---
karavan-app/pom.xml | 62 +--
.../org/apache/camel/karavan/KaravanConstants.java | 11 +-
.../org/apache/camel/karavan/KaravanEvents.java | 5 +
.../apache/camel/karavan/KaravanStartupLoader.java | 176 --------
.../apache/camel/karavan/api/AccessResource.java | 36 +-
.../apache/camel/karavan/api/ActivityFilter.java | 10 +-
.../apache/camel/karavan/api/ActivityResource.java | 18 +-
.../org/apache/camel/karavan/api/AuthResource.java | 21 +-
.../camel/karavan/api/ContainerResource.java | 29 +-
.../karavan/api/CookieSessionAuthMechanism.java | 1 +
.../apache/camel/karavan/api/LogWatchResource.java | 89 +---
.../camel/karavan/api/ProjectFileResource.java | 36 +-
.../apache/camel/karavan/api/ProjectResource.java | 15 +-
.../camel/karavan/api/ProjectZipResource.java | 13 +-
.../apache/camel/karavan/api/PublicResource.java | 14 +-
.../apache/camel/karavan/cache/AccessPassword.java | 16 -
.../org/apache/camel/karavan/cache/AccessRole.java | 12 -
.../apache/camel/karavan/cache/AccessSession.java | 33 +-
.../org/apache/camel/karavan/cache/AccessUser.java | 27 --
.../apache/camel/karavan/cache/CamelStatus.java | 15 -
.../camel/karavan/cache/CamelStatusValue.java | 19 -
.../apache/camel/karavan/cache/ContainerPort.java | 14 -
.../apache/camel/karavan/cache/ContainerType.java | 18 -
.../camel/karavan/cache/DeploymentStatus.java | 26 --
.../org/apache/camel/karavan/cache/GroupedKey.java | 7 -
.../apache/camel/karavan/cache/KaravanCache.java | 457 +++++++++++---------
.../camel/karavan/cache/KaravanStoreSchema.java | 36 --
.../camel/karavan/cache/PodContainerStatus.java | 69 ---
.../apache/camel/karavan/cache/ProjectFile.java | 17 -
.../camel/karavan/cache/ProjectFileCommitDiff.java | 48 ++-
.../camel/karavan/cache/ProjectFileCommited.java | 62 +--
.../apache/camel/karavan/cache/ProjectFolder.java | 79 +---
.../camel/karavan/cache/ProjectFolderCommit.java | 24 +-
.../apache/camel/karavan/cache/ServiceStatus.java | 25 --
.../camel/karavan/complexity/ComplexityFile.java | 10 +-
.../karavan/complexity/ComplexityProject.java | 19 +
.../camel/karavan/complexity/ComplexityRoute.java | 18 +
.../camel/karavan/docker/DockerEventHandler.java | 3 +-
.../camel/karavan/docker/DockerForKaravan.java | 10 +-
.../apache/camel/karavan/docker/DockerService.java | 476 ++++++++-------------
.../apache/camel/karavan/docker/DockerUtils.java | 10 +-
.../karavan/kubernetes/KubernetesService.java | 18 +-
.../camel/karavan/kubernetes/PodEventHandler.java | 6 +-
.../camel/karavan/listener/ActivityListener.java | 11 +-
.../camel/karavan/listener/CommitListener.java | 22 +-
.../karavan/listener/NotificationListener.java | 2 +
.../apache/camel/karavan/model/ActivityUser.java | 31 +-
.../karavan/scheduler/CamelStatusScheduler.java | 2 +-
.../karavan/scheduler/DockerStatusScheduler.java | 22 +-
.../karavan/scheduler/KaravanSkipPredicate.java | 25 --
.../apache/camel/karavan/service/AuthService.java | 48 ++-
.../apache/camel/karavan/service/CodeService.java | 76 ++--
.../camel/karavan/service/ComplexityService.java | 34 +-
.../apache/camel/karavan/service/GitService.java | 200 ++++-----
.../camel/karavan/service/ProjectService.java | 163 ++++---
55 files changed, 1096 insertions(+), 1650 deletions(-)
diff --git a/karavan-app/pom.xml b/karavan-app/pom.xml
index a853a569..de95ab7a 100644
--- a/karavan-app/pom.xml
+++ b/karavan-app/pom.xml
@@ -33,26 +33,17 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
- <quarkus.platform.version>3.27.0</quarkus.platform.version>
+ <quarkus.platform.version>3.27.2</quarkus.platform.version>
<surefire-plugin.version>3.1.0</surefire-plugin.version>
- <jgit.version>3.6.0</jgit.version>
- <infinispan-embedded.version>1.2.1</infinispan-embedded.version>
- <quinoa.version>2.6.2</quinoa.version>
+ <jgit.version>3.6.1</jgit.version>
+ <quinoa.version>2.7.1</quinoa.version>
<commons-text.version>1.14.0</commons-text.version>
<resources-plugin.version>3.3.0</resources-plugin.version>
- <docker-java.version>3.6.0</docker-java.version>
- <build-helper-version>3.6.0</build-helper-version>
+ <docker-java.version>3.7.0</docker-java.version>
</properties>
<dependencyManagement>
<dependencies>
- <dependency>
- <groupId>org.hibernate.search</groupId>
- <artifactId>hibernate-search-bom</artifactId>
- <version>7.1.2.Final</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
@@ -92,18 +83,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-common</artifactId>
</dependency>
- <dependency>
- <groupId>io.quarkiverse.infinispan</groupId>
- <artifactId>quarkus-infinispan-embedded</artifactId>
- <version>${infinispan-embedded.version}</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate.search</groupId>
- <artifactId>hibernate-search-bom</artifactId>
- <version>7.1.2.Final</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
<dependency>
<groupId>io.quarkiverse.jgit</groupId>
<artifactId>quarkus-jgit</artifactId>
@@ -137,13 +116,16 @@
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java-core</artifactId>
+ <version>${docker-java.version}</version>
<optional>false</optional>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
- <artifactId>docker-java-transport-zerodep</artifactId>
+ <artifactId>docker-java-transport-httpclient5</artifactId>
+ <version>${docker-java.version}</version>
<optional>false</optional>
</dependency>
+ <!-- Docker-->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
@@ -153,6 +135,21 @@
<artifactId>quarkus-quinoa</artifactId>
<version>${quinoa.version}</version>
</dependency>
+ <!-- Hibernate ORM specific dependencies -->
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-hibernate-orm-panache</artifactId>
+ </dependency>
+ <!-- JDBC driver dependencies -->
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jdbc-postgresql</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-flyway</artifactId>
+ </dependency>
+ <!-- YAML Validator -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
@@ -228,17 +225,4 @@
</plugin>
</plugins>
</build>
- <repositories>
- <repository>
- <id>apache.snapshots</id>
- <name>Apache Development Snapshot Repository</name>
- <url>https://repository.apache.org/content/repositories/snapshots/</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
</project>
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanConstants.java b/karavan-app/src/main/java/org/apache/camel/karavan/KaravanConstants.java
index 7fd3185f..f3b1485f 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanConstants.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/KaravanConstants.java
@@ -18,22 +18,18 @@ package org.apache.camel.karavan;
public class KaravanConstants {
- public static final String PLATFORM_ISSUER = "Platform";
- public static final String PLATFORM_AUDIENCE = "Platform";
- public static final String PLATFORM_EMAIL = "test@platform.demo";
-
public static final String DEV = "dev";
public static final String DEVMODE_IMAGE = "karavan.devmode.image";
public static final String DEVMODE_IMAGE_PULL_POLICY = "karavan.devmode.withImagePullPolicy";
public static final String ENV_VAR_VERBOSE_OPTION_NAME = "VERBOSE_OPTION";
- public static final String RUN_IN_COMPILE_MODE = "RUN_IN_COMPILE_MODE";
- public static final String RUN_IN_BUILD_MODE = "RUN_IN_BUILD_MODE";
+ public static final String ENV_VAR_RUN_IN_COMPILE_MODE = "RUN_IN_COMPILE_MODE";
+ public static final String ENV_VAR_RUN_IN_BUILD_MODE = "RUN_IN_BUILD_MODE";
public static final String ENV_VAR_VERBOSE_OPTION_VALUE = "--verbose";
+ public static final String ENV_VAR_BUILDER_SESSION_ID = "BUILDER_SESSION_ID";
public static final String LABEL_PART_OF = "app.kubernetes.io/part-of";
public static final String LABEL_TYPE = "org.apache.camel.karavan/type";
public static final String LABEL_PROJECT_ID = "org.apache.camel.karavan/projectId";
- public static final String LABEL_INTEGRATION_NAME = "org.apache.camel.karavan/integrationName";
public static final String LABEL_CAMEL_RUNTIME = "org.apache.camel.karavan/runtime";
public static final String LABEL_TAG = "org.apache.camel.karavan/tag";
public static final String LABEL_DOCKER_STACK_NAMESPACE = "com.docker.stack.namespace";
@@ -42,7 +38,6 @@ public class KaravanConstants {
public static final String BUILDER_SUFFIX = "-builder";
public static final String CAMEL_PREFIX = "camel";
- public static final String PLATFORM_PREFIX = "platform";
public static final String BUILD_SCRIPT_VOLUME_NAME = "build-script";
public static final String BUILD_SCRIPT_CONFIG_MAP = "build.sh";
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanEvents.java b/karavan-app/src/main/java/org/apache/camel/karavan/KaravanEvents.java
index c5e87c2b..ea9a16df 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanEvents.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/KaravanEvents.java
@@ -21,6 +21,7 @@ public class KaravanEvents {
public static final String CMD_PUSH_PROJECT = "CMD_PUSH_PROJECT";
public static final String NOTIFICATION_PROJECTS_STARTED = "NOTIFICATION_PROJECTS_STARTED";
+ public static final String NOTIFICATION_PROJECTS_IMPORTED = "NOTIFICATION_PROJECTS_IMPORTED";
public static final String COMMIT_HAPPENED = "COMMIT_HAPPENED";
public static final String NOTIFICATION_IMAGES_LOADED = "NOTIFICATION_IMAGES_LOADED";
@@ -57,4 +58,8 @@ public class KaravanEvents {
public static final String ON_PROJECT_ACTIVITY = "ON_PROJECT_ACTIVITY";
public static final String ON_CONTAINER_ACTIVITY = "ON_CONTAINER_ACTIVITY";
+ public static final String PERSIST_PROJECT = "PERSIST_PROJECT";
+ public static final String PERSIST_ACCESS = "PERSIST_ACCESS";
+ public static final String PERSIST_SESSION = "PERSIST_SESSION";
+
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanStartupLoader.java b/karavan-app/src/main/java/org/apache/camel/karavan/KaravanStartupLoader.java
deleted file mode 100644
index 81ad9458..00000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/KaravanStartupLoader.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.
- */
-package org.apache.camel.karavan;
-
-import io.quarkus.runtime.Quarkus;
-import io.quarkus.runtime.ShutdownEvent;
-import io.quarkus.runtime.StartupEvent;
-import io.vertx.mutiny.core.eventbus.EventBus;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.event.Observes;
-import jakarta.enterprise.inject.Default;
-import jakarta.inject.Inject;
-import org.apache.camel.karavan.cache.KaravanCache;
-import org.apache.camel.karavan.cache.ProjectFile;
-import org.apache.camel.karavan.cache.ProjectFolder;
-import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.service.*;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.eclipse.microprofile.health.HealthCheck;
-import org.eclipse.microprofile.health.HealthCheckResponse;
-import org.eclipse.microprofile.health.Readiness;
-import org.jboss.logging.Logger;
-
-import java.time.Instant;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.regex.Pattern;
-
-import static org.apache.camel.karavan.KaravanConstants.DEV;
-import static org.apache.camel.karavan.KaravanEvents.NOTIFICATION_PROJECTS_STARTED;
-
-@Default
-@Readiness
-@ApplicationScoped
-public class KaravanStartupLoader implements HealthCheck {
-
- private static final Logger LOGGER = Logger.getLogger(KaravanStartupLoader.class.getName());
-
- @ConfigProperty(name = "karavan.environment", defaultValue = KaravanConstants.DEV)
- String environment;
-
- @Inject
- ProjectService projectService;
-
- @Inject
- KaravanCache karavanCache;
-
- @Inject
- DockerService dockerService;
-
- @Inject
- GitService gitService;
-
- @Inject
- CodeService codeService;
-
- @Inject
- EventBus eventBus;
-
- @Inject
- AuthService authService;
-
- private final AtomicBoolean ready = new AtomicBoolean(false);
-
- @Override
- public HealthCheckResponse call() {
- if (ready.get()) {
- return HealthCheckResponse.named("Projects").up().build();
- } else {
- return HealthCheckResponse.named("Projects").down().build();
- }
- }
-
- void onStart(@Observes StartupEvent ev) throws Exception {
- LOGGER.info("Starting " + ConfigService.getAppName() + " in " + environment + " env in " + (ConfigService.inKubernetes() ? "Kubernetes" : "Docker"));
- if (!ConfigService.inKubernetes() && !dockerService.checkDocker()){
- Quarkus.asyncExit();
- } else {
- createCaches();
- }
- }
- void onStop(@Observes ShutdownEvent ev) {
- LOGGER.info("Stopping " + ConfigService.getAppName() + " in " + environment + " env in " + (ConfigService.inKubernetes() ? "Kubernetes" : "Docker"));
- karavanCache.stopCacheManager();
- }
-
- void createCaches() {
- try {
- LOGGER.info("Creating defaults...");
- authService.loadDefaults();
- LOGGER.info("Loading projects ...");
- tryStart();
- eventBus.publish(NOTIFICATION_PROJECTS_STARTED, null);
- LOGGER.info("Projects loaded");
- } catch (Exception e) {
- LOGGER.error(e.getMessage());
- }
- }
-
- public void tryStart() throws Exception {
- boolean git = gitService.checkGit();
- LOGGER.info("Starting Project service: git is " + (git ? "ready" : "not ready"));
- if (gitService.checkGit()) {
- if (karavanCache.getFolders().isEmpty()) {
- projectService.importProjects(false);
- }
- if (Objects.equals(environment, DEV)) {
- addKameletsProject();
- addBuildInProject(ProjectFolder.Type.templates.name());
- addBuildInProject(ProjectFolder.Type.configuration.name());
- addBuildInProject(ProjectFolder.Type.services.name());
- addBuildInProject(ProjectFolder.Type.shared.name());
- addBuildInProject(ProjectFolder.Type.documentation.name());
- }
- ready.set(true);
- } else {
- LOGGER.info("Projects are not ready");
- throw new Exception("Projects are not ready");
- }
- }
-
-
-
- void addKameletsProject() {
- try {
- ProjectFolder kamelets = karavanCache.getProject(ProjectFolder.Type.kamelets.name());
- if (kamelets == null) {
- LOGGER.info("Add custom kamelets project");
- kamelets = new ProjectFolder(ProjectFolder.Type.kamelets.name(), "Custom Kamelets", "", Instant.now().toEpochMilli(), ProjectFolder.Type.kamelets);
- karavanCache.saveProject(kamelets);
- }
- } catch (Exception e) {
- LOGGER.error("Error during custom kamelets project creation", e);
- }
- }
-
- public void addBuildInProject(String projectId) {
- try {
- ProjectFolder projectFolder = karavanCache.getProject(projectId);
- if (projectFolder == null) {
- var title = Pattern.compile("^.").matcher(projectId).replaceFirst(m -> m.group().toUpperCase());
- projectFolder = new ProjectFolder(projectId, title, "", Instant.now().toEpochMilli(), ProjectFolder.Type.valueOf(projectId));
- karavanCache.saveProject(projectFolder);
-
- codeService.getBuildInProjectFiles(projectId).forEach((name, value) -> {
- ProjectFile file = new ProjectFile(name, value, projectId, Instant.now().toEpochMilli());
- karavanCache.saveProjectFile(file, false);
- });
- } else {
- codeService.getBuildInProjectFiles(projectId).forEach((name, value) -> {
- ProjectFile f = karavanCache.getProjectFile(projectId, name);
- if (f == null) {
- ProjectFile file = new ProjectFile(name, value, projectId, Instant.now().toEpochMilli());
- karavanCache.saveProjectFile(file, false);
- }
- });
- }
- } catch (Exception e) {
- LOGGER.error("Error during creation of project " + projectId, e);
- }
- }
-}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/AccessResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/AccessResource.java
index 7f7e673a..f8605463 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/AccessResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/AccessResource.java
@@ -15,8 +15,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import static org.apache.camel.karavan.service.AuthService.ROLE_ADMIN;
-import static org.apache.camel.karavan.service.AuthService.ROLE_USER;
+import static org.apache.camel.karavan.service.AuthService.*;
@Path("/ui/access")
public class AccessResource extends AbstractApiResource {
@@ -30,7 +29,7 @@ public class AccessResource extends AbstractApiResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/users")
- @RolesAllowed({ROLE_ADMIN})
+ @RolesAllowed({ROLE_ADMIN, ROLE_DEVELOPER})
public List<AccessUser> getAllUsers() {
return karavanCache.getUsers();
}
@@ -48,7 +47,7 @@ public class AccessResource extends AbstractApiResource {
@RolesAllowed({ROLE_ADMIN})
@Path("/users")
public Response addUser(AccessUser user) {
- karavanCache.saveUser(user);
+ karavanCache.saveUser(user, true);
return Response.ok().entity(user).build();
}
@@ -57,7 +56,7 @@ public class AccessResource extends AbstractApiResource {
@RolesAllowed({ROLE_ADMIN})
@Path("/roles")
public Response addRole(AccessRole role) {
- karavanCache.saveRole(role);
+ karavanCache.saveRole(role, true);
return Response.ok().entity(role).build();
}
@@ -70,7 +69,7 @@ public class AccessResource extends AbstractApiResource {
if (Objects.equals(name, user.username)) {
var currentUser = karavanCache.getUser(user.username);
user.setRoles(currentUser.getRoles());
- karavanCache.saveUser(user);
+ karavanCache.saveUser(user, true);
return Response.ok().entity(user).build();
} else {
return Response.status(Response.Status.FORBIDDEN).build();
@@ -93,7 +92,7 @@ public class AccessResource extends AbstractApiResource {
roles.remove(role);
}
currentUser.setRoles(roles);
- karavanCache.saveUser(currentUser);
+ karavanCache.saveUser(currentUser, true);
return Response.ok().entity(currentUser).build();
}
@@ -103,7 +102,7 @@ public class AccessResource extends AbstractApiResource {
@Path("/users/{status}")
public Response setUserStatus(AccessUser user, @PathParam("status") String status) {
user.setStatus(AccessUser.UserStatus.valueOf(status));
- karavanCache.saveUser(user);
+ karavanCache.saveUser(user, true);
return Response.ok().entity(user).build();
}
@@ -115,13 +114,32 @@ public class AccessResource extends AbstractApiResource {
try {
var user = karavanCache.getUser(username);
user.setStatus(AccessUser.UserStatus.DELETED);
- karavanCache.saveUser(user);
+ karavanCache.saveUser(user, true);
return Response.accepted().build();
} catch (Exception e) {
return Response.notModified().build();
}
}
+ @DELETE
+ @Produces(MediaType.APPLICATION_JSON)
+ @RolesAllowed({ROLE_ADMIN})
+ @Path("/roles/{name}")
+ public Response deleteRole(@PathParam("name") String name) {
+ try {
+ if (!Objects.equals(ROLE_ADMIN, name) && !Objects.equals(ROLE_USER, name) && !Objects.equals(ROLE_DEVELOPER, name)) {
+ var role = karavanCache.getRole(name);
+ if (role != null) {
+ karavanCache.deleteRole(role);
+ return Response.accepted().build();
+ }
+ }
+ return Response.notModified().build();
+ } catch (Exception e) {
+ return Response.notModified().build();
+ }
+ }
+
@POST
@Path("/password")
@RolesAllowed({ROLE_ADMIN})
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityFilter.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityFilter.java
index 78e93151..dbc22a29 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityFilter.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityFilter.java
@@ -14,12 +14,14 @@ import jakarta.ws.rs.ext.Provider;
import org.apache.camel.karavan.cache.ProjectFolder;
import org.apache.camel.karavan.model.ActivityContainer;
import org.apache.camel.karavan.model.ActivityProject;
+import org.apache.camel.karavan.model.ActivityUser;
import org.jboss.logging.Logger;
import java.io.IOException;
import java.util.Objects;
import static org.apache.camel.karavan.KaravanEvents.ON_PROJECT_ACTIVITY;
+import static org.apache.camel.karavan.KaravanEvents.ON_USER_ACTIVITY;
@Provider
@ApplicationScoped
@@ -68,7 +70,11 @@ public class ActivityFilter extends AbstractApiResource implements ContainerResp
try {
var user = getIdentity();
var userName = user.getString("username");
-// eventBus.publish(ON_USER_ACTIVITY, JsonObject.mapFrom(new ActivityUser(userName)));
+ if (method.equals("GET")) {
+ eventBus.publish(ON_USER_ACTIVITY, JsonObject.mapFrom(new ActivityUser(userName, ActivityUser.ActivityType.HEARTBEAT)));
+ } else {
+ eventBus.publish(ON_USER_ACTIVITY, JsonObject.mapFrom(new ActivityUser(userName, ActivityUser.ActivityType.WORKING)));
+ }
if (info.getPathParameters().containsKey(projectIdKey)) {
var projectId = info.getPathParameters().get(projectIdKey).get(0);
@@ -76,7 +82,7 @@ public class ActivityFilter extends AbstractApiResource implements ContainerResp
} else if (info.getQueryParameters().containsKey(projectIdKey)) {
var projectId = info.getQueryParameters().get(projectIdKey).get(0);
eventBus.publish(ON_PROJECT_ACTIVITY, JsonObject.mapFrom(ActivityProject.createAdd(userName, projectId)));
- } else if (path.startsWith("/ui/devmode") || !Objects.equals(method, "GET")) {
+ } else if (path.startsWith("/ui/devmode") || !Objects.equals(method, "GET")) {
if (responseContext.getEntity() instanceof ProjectFolder projectFolder) {
eventBus.publish(ON_PROJECT_ACTIVITY, JsonObject.mapFrom(ActivityProject.createAdd(userName, projectFolder.getProjectId())));
} else if (responseContext.getEntity() instanceof String string) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityResource.java
index 618712cf..00d66e3b 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ActivityResource.java
@@ -7,7 +7,7 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.apache.camel.karavan.cache.KaravanCache;
-import org.jboss.logging.Logger;
+import org.apache.camel.karavan.model.ActivityUser;
import java.util.ArrayList;
import java.util.List;
@@ -17,17 +17,27 @@ import java.util.stream.Collectors;
@Path("/ui/activity")
public class ActivityResource {
- private static final Logger LOGGER = Logger.getLogger(ActivityResource.class.getName());
-
@Inject
KaravanCache karavanCache;
@GET
+ @Path("/projects")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
- public Map<String, List<String>> getProjectActivities() {
+ public Map<String, List<String>> getProjectsActivities() {
return karavanCache.getCopyProjectActivities().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> new ArrayList<>(e.getValue().keySet())));
}
+ @GET
+ @Authenticated
+ @Path("/users")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Map<String, ActivityUser>> getUsersActivities() {
+ return Map.of(
+ ActivityUser.ActivityType.HEARTBEAT.name(), karavanCache.getCopyUsersHeartBeat(),
+ ActivityUser.ActivityType.WORKING.name(), karavanCache.getCopyUsersWorking()
+ );
+ }
+
}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java
index 99e219e2..f8e71178 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java
@@ -6,23 +6,21 @@ import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.*;
-import org.apache.camel.karavan.cache.AccessSession;
import org.apache.camel.karavan.cache.AccessUser;
import org.apache.camel.karavan.cache.KaravanCache;
import org.apache.camel.karavan.service.AuthService;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;
-import java.security.SecureRandom;
-import java.util.Base64;
import java.util.Map;
+import static org.apache.camel.karavan.service.AuthService.SESSION_MAX_AGE;
+
@Path("/ui/auth")
@Produces(MediaType.APPLICATION_JSON)
public class AuthResource extends AbstractApiResource {
private static final Logger LOGGER = Logger.getLogger(AuthResource.class.getName());
- static final SecureRandom RNG = new SecureRandom();
private static final String SESSION_ID = "sessionId";
private static final String CSRF = "csrf";
@@ -61,12 +59,9 @@ public class AuthResource extends AbstractApiResource {
public Response login(JsonObject body) throws Exception {
try {
final AccessUser user = authService.login(body.getString("username"), body.getString("password"));
- String sessionId = random(32);
- String csrf = random(16);
- var session = new AccessSession(sessionId, user.username, csrf, System.currentTimeMillis());
- karavanCache.saveAccessSession(session);
- NewCookie sidCookie = new NewCookie.Builder(SESSION_ID).value(sessionId).path("/").maxAge(12 * 60 * 60).secure(true).httpOnly(true).build();
- NewCookie csrfCookie = new NewCookie.Builder(CSRF).value(csrf).path("/").maxAge(12 * 60 * 60).secure(false).httpOnly(true).build();
+ var session = authService.createAndSaveSession(user.username, true);
+ NewCookie sidCookie = new NewCookie.Builder(SESSION_ID).value(session.sessionId).path("/").maxAge(SESSION_MAX_AGE).secure(true).httpOnly(true).build();
+ NewCookie csrfCookie = new NewCookie.Builder(CSRF).value(session.csrfToken).path("/").maxAge(SESSION_MAX_AGE).secure(false).httpOnly(true).build();
return Response.ok(JsonObject.of("username", user.getUsername(), "roles", user.getRoles()))
.cookie(sidCookie).cookie(csrfCookie).build();
} catch (Exception e) {
@@ -74,12 +69,6 @@ public class AuthResource extends AbstractApiResource {
}
}
- private static String random(int bytes) {
- byte[] b = new byte[bytes];
- RNG.nextBytes(b);
- return Base64.getUrlEncoder().withoutPadding().encodeToString(b);
- }
-
@POST
@Path("/password")
@Authenticated
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
index e310f39e..0846e81b 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
@@ -29,7 +29,6 @@ import org.apache.camel.karavan.KaravanConstants;
import org.apache.camel.karavan.cache.ContainerType;
import org.apache.camel.karavan.cache.KaravanCache;
import org.apache.camel.karavan.cache.PodContainerStatus;
-import org.apache.camel.karavan.docker.DockerComposeConverter;
import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.docker.StackToServiceSpecConverter;
import org.apache.camel.karavan.kubernetes.KubernetesService;
@@ -127,25 +126,13 @@ public class ContainerResource {
}
public void deployContainer(String projectId, String type, JsonObject command) throws InterruptedException {
- if (Objects.equals(type, ContainerType.devservice.name())) {
- String code = projectService.getDockerDevServiceCode();
- DockerComposeService dockerComposeService = DockerComposeConverter.fromCode(code, projectId);
- if (dockerComposeService != null) {
- Map<String, String> labels = new HashMap<>();
- labels.put(LABEL_TYPE, ContainerType.devservice.name());
- labels.put(LABEL_PROJECT_ID, projectId);
- labels.put(LABEL_INTEGRATION_NAME, projectId);
- dockerService.createContainerFromCompose(dockerComposeService, labels, needPull(command));
- dockerService.runContainer(dockerComposeService.getContainer_name());
- }
- } else if (Objects.equals(type, ContainerType.packaged.name())) {
+ if (Objects.equals(type, ContainerType.packaged.name())) {
DockerComposeService dockerComposeService = projectService.getProjectDockerComposeService(projectId);
if (dockerComposeService != null) {
Map<String, String> labels = new HashMap<>();
labels.put(LABEL_TYPE, ContainerType.packaged.name());
labels.put(LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue());
labels.put(LABEL_PROJECT_ID, projectId);
- labels.put(LABEL_INTEGRATION_NAME, projectId);
dockerService.createContainerFromCompose(dockerComposeService, labels, needPull(command));
dockerService.runContainer(dockerComposeService.getContainer_name());
}
@@ -157,25 +144,13 @@ public class ContainerResource {
}
public void deployService(String projectId, String type, JsonObject command) throws InterruptedException {
- if (Objects.equals(type, ContainerType.devservice.name())) {
-// String code = projectService.getDockerDevServiceCode();
-// DockerComposeService dockerComposeService = DockerComposeConverter.fromCode(code, projectId);
-// if (dockerComposeService != null) {
-// Map<String, String> labels = new HashMap<>();
-// labels.put(LABEL_TYPE, ContainerType.devservice.name());
-// labels.put(LABEL_PROJECT_ID, projectId);
-// labels.put(LABEL_INTEGRATION_NAME, projectId);
-// dockerService.createContainerFromCompose(dockerComposeService, labels, needPull(command));
-// dockerService.runContainer(dockerComposeService.getContainer_name());
-// }
- } else if (Objects.equals(type, ContainerType.packaged.name())) {
+ if (Objects.equals(type, ContainerType.packaged.name())) {
DockerStackService stack = projectService.getProjectDockerStackService(projectId);
if (stack != null) {
Map<String, String> labels = new HashMap<>();
labels.put(LABEL_TYPE, ContainerType.packaged.name());
labels.put(LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue());
labels.put(LABEL_PROJECT_ID, projectId);
- labels.put(LABEL_INTEGRATION_NAME, projectId);
stack.setLabels(labels);
var serviceSpec = StackToServiceSpecConverter.convertService(projectId, stack);
dockerService.createService(projectId, serviceSpec);
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/CookieSessionAuthMechanism.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/CookieSessionAuthMechanism.java
index 4bd573e6..82825c67 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/CookieSessionAuthMechanism.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/CookieSessionAuthMechanism.java
@@ -41,6 +41,7 @@ public class CookieSessionAuthMechanism implements HttpAuthenticationMechanism {
var builder = QuarkusSecurityIdentity.builder();
try {
+ builder.setPrincipal(() -> "anonymous");
builder.setAnonymous(true);
var cookie = ctx.request().getCookie("sessionId");
if (cookie == null) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
index a10fd2f9..b454ea73 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -16,12 +16,9 @@
*/
package org.apache.camel.karavan.api;
-import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.dsl.LogWatch;
import io.quarkus.security.Authenticated;
import io.smallrye.context.api.ManagedExecutorConfig;
import io.smallrye.context.api.NamedInstance;
-import io.smallrye.mutiny.tuples.Tuple2;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@@ -31,31 +28,15 @@ import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
-import org.apache.camel.karavan.docker.DockerLogCallback;
-import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.kubernetes.KubernetesService;
-import org.apache.camel.karavan.service.ConfigService;
+import org.apache.camel.karavan.service.LogStreamingService;
import org.apache.camel.karavan.service.NotificationService;
import org.eclipse.microprofile.context.ManagedExecutor;
-import org.jboss.logging.Logger;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.concurrent.ConcurrentHashMap;
@Path("/ui/logwatch")
public class LogWatchResource extends AbstractApiResource {
- private static final Logger LOGGER = Logger.getLogger(LogWatchResource.class.getName());
- private static final String SERVICE_NAME = "LOGWATCH";
- private static final ConcurrentHashMap<String, Tuple2<LogWatch, KubernetesClient>> logWatches = new ConcurrentHashMap<>();
-
- @Inject
- KubernetesService kubernetesService;
-
@Inject
- DockerService dockerService;
+ LogStreamingService logStreamingService;
@Inject
NotificationService notificationService;
@@ -74,65 +55,13 @@ public class LogWatchResource extends AbstractApiResource {
@PathParam("username") String username,
@Context SseEventSink eventSink,
@Context Sse sse) {
- notificationService.sinkCleanup(SERVICE_NAME + ":" + type + ":" + name, username, eventSink);
- managedExecutor.execute(() -> {
- LOGGER.info("LogWatch for " + name + " starting... ");
- if (ConfigService.inKubernetes()) {
- getKubernetesLogs(name, username, eventSink, sse);
- } else {
- getDockerLogs(type, name, eventSink, sse);
- }
- });
- }
-
- private void getDockerLogs(String type, String name, SseEventSink eventSink, Sse sse) {
- LOGGER.info("LogCallback for " + name + " starting");
- try (SseEventSink sink = eventSink) {
- DockerLogCallback dockerLogCallback = new DockerLogCallback(line -> {
- if (!sink.isClosed()) {
- sink.send(sse.newEvent(line));
- }
- });
- dockerService.logContainer(name, dockerLogCallback);
- dockerLogCallback.close();
- sink.close();
- LOGGER.info("LogCallback for " + name + " closed");
- } catch (Exception e) {
- LOGGER.error(e.getMessage());
- }
- }
- private void getKubernetesLogs(String name, String username, SseEventSink eventSink, Sse sse) {
- try (SseEventSink sink = eventSink) {
- Tuple2<LogWatch, KubernetesClient> request = kubernetesService.getContainerLogWatch(name);
- logWatchCleanup(SERVICE_NAME, username, request);
- LogWatch logWatch = request.getItem1();
- BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput()));
- try {
- for (String line; (line = reader.readLine()) != null && !sink.isClosed(); ) {
- sink.send(sse.newEvent(line));
- }
- } catch (IOException e) {
- LOGGER.error(e.getMessage());
- }
- logWatch.close();
- request.getItem2().close();
- sink.close();
- LOGGER.info("LogWatch for " + name + " closed");
- }
- }
+ // 1. Handle Notifications cleanup (API concern)
+ notificationService.sinkCleanup(LogStreamingService.SERVICE_NAME + ":" + type + ":" + name, username, eventSink);
- protected void logWatchCleanup(String service, String username, Tuple2<LogWatch, KubernetesClient> logWatch) {
- String key = service + ":" + username;
- if (logWatches.containsKey(key)) {
- var lw = logWatches.get(key);
- try {
- lw.getItem1().close();
- lw.getItem2().close();
- } catch (Exception e) {
- LOGGER.error(e.getMessage());
- }
- }
- logWatches.put(key, logWatch);
+ // 2. Hand off the heavy lifting to the thread pool
+ managedExecutor.execute(() -> {
+ logStreamingService.streamLog(type, name, username, eventSink, sse);
+ });
}
}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectFileResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectFileResource.java
index ed4944b1..a8d5ea5a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectFileResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectFileResource.java
@@ -25,8 +25,6 @@ import jakarta.ws.rs.core.Response;
import org.apache.camel.karavan.cache.KaravanCache;
import org.apache.camel.karavan.cache.ProjectFile;
import org.apache.camel.karavan.cache.ProjectFileCommited;
-import org.apache.camel.karavan.cache.ProjectFolder;
-import org.apache.camel.karavan.service.CodeService;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
@@ -67,11 +65,21 @@ public class ProjectFileResource {
return karavanCache.getProjectFilesByName(filename);
}
+ @GET
+ @Authenticated
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/commited/{projectId}")
+ public List<ProjectFileCommited> getCommitedFiles(@PathParam("projectId") String projectId) {
+ return karavanCache.getProjectFilesCommited(projectId).stream()
+ .map(f -> new ProjectFileCommited(f.getName(), "", f.getProjectId(), f.getCommitId(), f.getCommitTime()))
+ .collect(Collectors.toList());
+ }
+
@GET
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
@Path("/commited/{projectId}/{filename}")
- public ProjectFileCommited getCommited(@PathParam("projectId") String projectId, @PathParam("filename") String filename) {
+ public ProjectFileCommited getCommitedFile(@PathParam("projectId") String projectId, @PathParam("filename") String filename) {
return karavanCache.getProjectFileCommited(projectId, filename);
}
@@ -102,27 +110,17 @@ public class ProjectFileResource {
return result;
}
- @GET
- @Authenticated
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/templates/beans")
- public List<ProjectFile> getBeanTemplates() throws Exception {
- return karavanCache.getProjectFiles(ProjectFolder.Type.templates.name()).stream()
- .filter(file -> file.getName().endsWith(CodeService.BEAN_TEMPLATE_SUFFIX_FILENAME))
- .toList();
- }
-
@POST
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response create(ProjectFile file) throws Exception {
- file.setLastUpdate(Instant.now().toEpochMilli());
+ file.setLastUpdate(Instant.now().getEpochSecond() * 1000L);
boolean projectFileExists = karavanCache.getProjectFile(file.getProjectId(), file.getName()) != null;
if (projectFileExists) {
return Response.serverError().entity("File with given name already exists " + file.getName() + " in project " + file.getProjectId()).build();
} else {
- karavanCache.saveProjectFile(file, false);
+ karavanCache.saveProjectFile(file, null, true);
return Response.ok(file).build();
}
}
@@ -132,8 +130,8 @@ public class ProjectFileResource {
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public ProjectFile update(ProjectFile file) throws Exception {
- file.setLastUpdate(Instant.now().toEpochMilli());
- karavanCache.saveProjectFile(file, false);
+ file.setLastUpdate(Instant.now().getEpochSecond() * 1000L);
+ karavanCache.saveProjectFile(file, null, true);
return file;
}
@@ -158,7 +156,7 @@ public class ProjectFileResource {
file.setCode(fromFile.getCode());
file.setLastUpdate(fromFile.getLastUpdate());
file.setProjectId(fromFile.getProjectId());
- karavanCache.saveProjectFile(file, false);
+ karavanCache.saveProjectFile(file, null, true);
karavanCache.deleteProjectFile(projectId, filename);
karavanCache.deleteProjectFileCommited(projectId, filename);
return Response.ok(file).build();
@@ -196,7 +194,7 @@ public class ProjectFileResource {
var copyFile = file.copy();
copyFile.setProjectId(toProjectId);
copyFile.setName(toFilename);
- karavanCache.saveProjectFile(copyFile, false);
+ karavanCache.saveProjectFile(copyFile, null, true);
return Response.ok().build();
} else {
return Response.notModified().build();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index 789e898a..329036c9 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -71,13 +71,20 @@ public class ProjectResource extends AbstractApiResource {
return projectService.getAllProjects(type);
}
+ @GET
+ @Authenticated
+ @Path("/commited/all")
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<ProjectFolderCommited> getAllCommited() {
+ return karavanCache.getFoldersCommited();
+ }
@GET
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
- @Path("/{project}")
- public ProjectFolder get(@PathParam("project") String project) throws Exception {
- return karavanCache.getProject(project);
+ @Path("/{projectId}")
+ public ProjectFolder get(@PathParam("projectId") String projectId) throws Exception {
+ return karavanCache.getProject(projectId);
}
@POST
@@ -110,6 +117,7 @@ public class ProjectResource extends AbstractApiResource {
karavanCache.getProjectFiles(projectId).forEach(file -> karavanCache.deleteProjectFile(projectId, file.getName()));
karavanCache.getProjectFilesCommited(projectId).forEach(file -> karavanCache.deleteProjectFileCommited(projectId, file.getName()));
karavanCache.deleteProject(projectId);
+ karavanCache.deleteProjectCommited(projectId);
// delete from git
gitService.deleteProject(projectId, identity.getString("username"), identity.getString("email"));
LOGGER.info("Project deleted");
@@ -126,7 +134,6 @@ public class ProjectResource extends AbstractApiResource {
return Response.ok().entity(projectFolder).build();
} catch (Exception e) {
LOGGER.error(e.getCause() != null ? e.getCause().getMessage() : e.getMessage());
- e.printStackTrace();
return Response.serverError().entity(e.getMessage()).build();
}
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectZipResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectZipResource.java
index 9caa733c..702f0fd6 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectZipResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectZipResource.java
@@ -2,6 +2,7 @@ package org.apache.camel.karavan.api;
import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.tuples.Tuple2;
+import io.vertx.core.eventbus.EventBus;
import io.vertx.core.json.JsonArray;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
@@ -27,6 +28,8 @@ import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import static org.apache.camel.karavan.KaravanEvents.NOTIFICATION_PROJECTS_IMPORTED;
+
@Path("/ui/zip")
public class ProjectZipResource {
@@ -41,6 +44,9 @@ public class ProjectZipResource {
@Inject
KaravanCache karavanCache;
+ @Inject
+ EventBus eventBus;
+
@POST
@Path("/project")
@Authenticated
@@ -54,11 +60,12 @@ public class ProjectZipResource {
var projectData = getProjectId(appPropertiesBytes);
if (karavanCache.getProject(projectData.getItem1()) == null) {
var project = new ProjectFolder(projectData.getItem1(), projectData.getItem2());
- karavanCache.saveProject(project);
+ karavanCache.saveProject(project, true);
zipEntries.entrySet().stream().filter(e -> !e.getKey().startsWith(".")).forEach(e -> {
- var pf = new ProjectFile(e.getKey(), new String(e.getValue()), project.getProjectId(), Instant.now().toEpochMilli());
- karavanCache.saveProjectFile(pf, false);
+ var pf = new ProjectFile(e.getKey(), new String(e.getValue()), project.getProjectId(), Instant.now().getEpochSecond() * 1000L);
+ karavanCache.saveProjectFile(pf, null, true);
});
+ eventBus.publish(NOTIFICATION_PROJECTS_IMPORTED, project.getProjectId());
return Response.ok().entity(JsonArray.of(zipEntries.keySet())).build();
} else {
return Response.notModified().entity(name).build();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/PublicResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/PublicResource.java
index 0d8053b8..7c880378 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/PublicResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/PublicResource.java
@@ -23,10 +23,12 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
-import org.apache.camel.karavan.KaravanStartupLoader;
+import org.apache.camel.karavan.KaravanConstants;
import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.kubernetes.KubernetesStatusService;
+import org.apache.camel.karavan.loader.StartupLoader;
import org.apache.camel.karavan.service.ConfigService;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.HealthCheckResponse;
import java.util.List;
@@ -37,7 +39,7 @@ import java.util.Objects;
public class PublicResource {
@Inject
- KaravanStartupLoader karavanStartupLoader;
+ StartupLoader startupLoader;
@Inject
KubernetesStatusService kubernetesStatusService;
@@ -45,6 +47,9 @@ public class PublicResource {
@Inject
DockerService dockerService;
+ @ConfigProperty(name = "karavan.environment", defaultValue = KaravanConstants.DEV)
+ String environment;
+
@GET
@Path("/readiness")
@PermitAll
@@ -54,11 +59,12 @@ public class PublicResource {
List<HealthCheckResponse> list = List.of(
infraCheck,
- karavanStartupLoader.call()
+ startupLoader.call()
);
return Response.ok(Map.of(
"status", list.stream().allMatch(h -> Objects.equals(h.getStatus(), HealthCheckResponse.Status.UP)),
- "checks", list
+ "checks", list,
+ "environment", environment
)).build();
}
}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessPassword.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessPassword.java
index 80ad790c..43760047 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessPassword.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessPassword.java
@@ -1,42 +1,26 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class AccessPassword {
- @Basic
- @ProtoField(1)
public String username;
- @ProtoField(2)
public String pwdHash;
- @ProtoField(3)
public int costAtCreation;
- @ProtoField(4)
public long changedAt;
- @ProtoField(5)
public long lastAttempt;
- @ProtoField(6)
public long lastLogin;
- @ProtoField(7)
public int failedAttempts;
- @ProtoField(8)
public long lockedUntil; // epoch millis; 0 = not locked
public AccessPassword() {
}
- @ProtoFactory
public AccessPassword(String username, String pwdHash, int costAtCreation, long changedAt, long lastAttempt, long lastLogin, int failedAttempts, long lockedUntil) {
this.username = username;
this.pwdHash = pwdHash;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessRole.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessRole.java
index a9f3133b..80451f4f 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessRole.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessRole.java
@@ -1,25 +1,13 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.api.annotations.indexing.Text;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class AccessRole {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
public String name;
- @Text
- @ProtoField(2)
public String description;
public AccessRole() {
}
- @ProtoFactory
public AccessRole(String name, String description) {
this.name = name;
this.description = description;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessSession.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessSession.java
index 5358a22c..5a69ddb5 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessSession.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessSession.java
@@ -1,36 +1,25 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
+import java.time.Instant;
-@Indexed
public class AccessSession {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
public String sessionId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
public String username;
- @Keyword(projectable = true)
- @ProtoField(3)
public String csrfToken;
- @Basic
- @ProtoField(4)
public long createdAtMillis;
- @ProtoFactory
- public AccessSession(String sessionId, String username, String csrfToken, long createdAtMillis) {
+ public Instant expiredAt;
+
+ public AccessSession(String sessionId, String username, String csrfToken, long createdAtMillis, Instant expiredAt) {
this.sessionId = sessionId;
this.username = username;
this.csrfToken = csrfToken;
this.createdAtMillis = createdAtMillis;
+ this.expiredAt = expiredAt;
}
public String getSessionId() {
@@ -64,4 +53,16 @@ public class AccessSession {
public void setCreatedAtMillis(long createdAtMillis) {
this.createdAtMillis = createdAtMillis;
}
+
+ public Instant getExpiredAt() {
+ return expiredAt;
+ }
+
+ public void setExpiredAt(Instant expiredAt) {
+ this.expiredAt = expiredAt;
+ }
+
+ public AccessSession copy() {
+ return new AccessSession(sessionId, username, csrfToken, createdAtMillis, expiredAt);
+ }
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessUser.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessUser.java
index c1814e0f..f4f421e8 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessUser.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/AccessUser.java
@@ -1,52 +1,25 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.api.annotations.indexing.Text;
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-import java.util.ArrayList;
import java.util.List;
-@Indexed
public class AccessUser {
public enum UserStatus {
- @ProtoEnumValue(number = 0, name = "ACTIVE")
ACTIVE,
- @ProtoEnumValue(number = 1, name = "INACTIVE")
INACTIVE,
- @ProtoEnumValue(number = 2, name = "DELETED")
DELETED
}
-
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
public String username;
- @Text
- @ProtoField(2)
public String firstName;
- @Text
- @ProtoField(3)
public String lastName;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(4)
public String email;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(5)
public UserStatus status;
- @Text(name = "roles_text", projectable = true)
- @Keyword(name = "roles", projectable = true)
- @ProtoField(value = 6, collectionImplementation = ArrayList.class)
public List<String> roles;
public AccessUser() {
}
- @ProtoFactory
public AccessUser(String username, String firstName, String lastName, String email, UserStatus status, List<String> roles) {
this.username = username;
this.firstName = firstName;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatus.java
index b461b6cd..6498c89c 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatus.java
@@ -17,33 +17,18 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-import java.util.ArrayList;
import java.util.List;
-@Indexed
public class CamelStatus {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String projectId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
String containerName;
- @ProtoField(value = 3, collectionImplementation = ArrayList.class)
List<CamelStatusValue> statuses;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(4)
String env;
public CamelStatus() {
}
- @ProtoFactory
public CamelStatus(String projectId, String containerName, List<CamelStatusValue> statuses, String env) {
this.projectId = projectId;
this.containerName = containerName;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatusValue.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatusValue.java
index 57f9c45d..070a286f 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatusValue.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CamelStatusValue.java
@@ -17,48 +17,29 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
public class CamelStatusValue {
public enum Name {
- @ProtoEnumValue(number = 0, name = "context")
context,
- @ProtoEnumValue(number = 1, name = "inflight")
inflight,
- @ProtoEnumValue(number = 2, name = "memory")
memory,
- @ProtoEnumValue(number = 3, name = "properties")
properties,
- @ProtoEnumValue(number = 4, name = "route")
route,
- @ProtoEnumValue(number = 5, name = "trace")
trace,
- @ProtoEnumValue(number = 6, name = "jvm")
jvm,
- @ProtoEnumValue(number = 7, name = "source")
source,
- @ProtoEnumValue(number = 8, name = "debug")
debug,
- @ProtoEnumValue(number = 9, name = "thread")
thread,
- @ProtoEnumValue(number = 10, name = "processor")
processor,
- @ProtoEnumValue(number = 11, name = "consumer")
consumer
}
- @ProtoField(1)
Name name;
- @ProtoField(2)
String status;
public CamelStatusValue() {
}
- @ProtoFactory
public CamelStatusValue(Name name, String status) {
this.name = name;
this.status = status;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerPort.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerPort.java
index b1f75599..f6713ce7 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerPort.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerPort.java
@@ -17,29 +17,15 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class ContainerPort {
- @Basic
- @ProtoField(1)
Integer privatePort;
- @Basic
- @ProtoField(2)
Integer publicPort;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String type;
public ContainerPort() {
}
- @ProtoFactory
public ContainerPort(Integer privatePort, Integer publicPort, String type) {
this.privatePort = privatePort;
this.publicPort = publicPort;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerType.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerType.java
index 8be11519..c8e5febc 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerType.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ContainerType.java
@@ -17,28 +17,10 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-
-@Indexed
public enum ContainerType {
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 0, name = "internal")
internal,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 1, name = "devmode")
devmode,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 2, name = "devservice")
- devservice,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 3, name = "packaged")
packaged,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 4, name = "build")
build,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 5, name = "unknown")
unknown,
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/DeploymentStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/DeploymentStatus.java
index 909eeea6..d903a971 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/DeploymentStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/DeploymentStatus.java
@@ -17,41 +17,16 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class DeploymentStatus {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String projectId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
String namespace;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String env;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(4)
String cluster;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(5)
String image;
- @Basic(projectable = true, sortable = true)
- @ProtoField(6)
Integer replicas;
- @Basic(projectable = true, sortable = true)
- @ProtoField(7)
Integer readyReplicas;
- @Basic(projectable = true, sortable = true)
- @ProtoField(8)
Integer unavailableReplicas;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(9)
ContainerType type;
public DeploymentStatus() {
@@ -68,7 +43,6 @@ public class DeploymentStatus {
this.unavailableReplicas = 0;
}
- @ProtoFactory
public DeploymentStatus(String projectId, String namespace, String cluster, String env, String image, Integer replicas, Integer readyReplicas, Integer unavailableReplicas, ContainerType type) {
this.projectId = projectId;
this.namespace = namespace;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/GroupedKey.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/GroupedKey.java
index 980dda61..2570bf6a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/GroupedKey.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/GroupedKey.java
@@ -17,22 +17,15 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
public class GroupedKey {
- @ProtoField(number = 1)
String projectId;
- @ProtoField(number = 2)
String env;
- @ProtoField(number = 3)
String key;
public GroupedKey() {
}
- @ProtoFactory
public GroupedKey(String projectId, String env, String key) {
this.projectId = projectId;
this.env = env;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
index 2acab180..4495659e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
@@ -16,173 +16,197 @@
*/
package org.apache.camel.karavan.cache;
-import io.quarkiverse.infinispan.embedded.Embedded;
-import io.quarkus.runtime.ShutdownEvent;
-import io.vertx.core.json.JsonObject;
-import jakarta.enterprise.event.Observes;
+import io.vertx.core.eventbus.EventBus;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
+import org.apache.camel.karavan.model.ActivityUser;
import org.apache.camel.karavan.service.AuthService;
-import org.infinispan.Cache;
-import org.infinispan.manager.EmbeddedCacheManager;
import org.jboss.logging.Logger;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.apache.camel.karavan.KaravanConstants.DEV;
-import static org.apache.camel.karavan.KaravanConstants.PLATFORM_PREFIX;
+import static org.apache.camel.karavan.KaravanEvents.*;
+import static org.apache.camel.karavan.cache.CacheEvent.Operation.DELETE;
+import static org.apache.camel.karavan.cache.CacheEvent.Operation.SAVE;
+import static org.apache.camel.karavan.cache.CacheUtils.query;
+import static org.apache.camel.karavan.cache.CacheUtils.queryFirst;
import static org.apache.camel.karavan.service.AuthService.USER_ADMIN;
@Default
@Singleton
public class KaravanCache {
- private static final Logger LOGGER = Logger.getLogger(KaravanCache.class.getName());
-
- @Embedded("ProjectFolder")
- Cache<String, ProjectFolder> folders;
- @Embedded("ProjectFile")
- Cache<String, ProjectFile> files;
- @Embedded("ProjectFileCommited")
- Cache<String, ProjectFileCommited> filesCommited;
-
- @Embedded("DeploymentStatus")
- Cache<String, DeploymentStatus> deploymentStatuses;
- @Embedded("PodContainerStatus")
- Cache<String, PodContainerStatus> podContainerStatuses;
- @Embedded("ServiceStatus")
- Cache<String, ServiceStatus> serviceStatuses;
- @Embedded("CamelStatus")
- Cache<String, CamelStatus> camelStatuses;
-
- @Embedded("AccessUser")
- Cache<String, AccessUser> users;
- @Embedded("AccessPassword")
- Cache<String, AccessPassword> passwords;
- @Embedded("AccessRole")
- Cache<String, AccessRole> roles;
- @Embedded("AccessSession")
- Cache<String, AccessSession> sessions;
+ @Inject
+ EventBus eventBus;
+
+ static final Logger LOGGER = Logger.getLogger(KaravanCache.class.getName());
+
+ final Map<String, ProjectFolder> folders = new ConcurrentHashMap<>();
+ final Map<String, ProjectFolderCommited> foldersCommited = new ConcurrentHashMap<>();
+ final Map<String, ProjectFile> files = new ConcurrentHashMap<>();
+ final Map<String, ProjectFileCommited> filesCommited = new ConcurrentHashMap<>();
+
+ final Map<String, DeploymentStatus> deploymentStatuses = new ConcurrentHashMap<>();
+ final Map<String, PodContainerStatus> podContainerStatuses = new ConcurrentHashMap<>();
+ final Map<String, ServiceStatus> serviceStatuses = new ConcurrentHashMap<>();
+ final Map<String, CamelStatus> camelStatuses = new ConcurrentHashMap<>();
+
+ final Map<String, AccessUser> users = new ConcurrentHashMap<>();
+ final Map<String, AccessPassword> passwords = new ConcurrentHashMap<>();
+ final Map<String, AccessRole> roles = new ConcurrentHashMap<>();
+ final Map<String, AccessSession> sessions = new ConcurrentHashMap<>();
final Map<String, Map<String, Instant>> projectActivities = new ConcurrentHashMap<>();
+ final Map<String, ActivityUser> usersWorking = new ConcurrentHashMap<>();
+ final Map<String, ActivityUser> usersHeartBeat = new ConcurrentHashMap<>();
- @Inject
- EmbeddedCacheManager cacheManager;
+ final Map<String, List<ProjectFolderCommit>> lastFolderCommits = new ConcurrentHashMap<>();
+ final Map<String, SystemCommit> systemCommits = new ConcurrentHashMap<>();
- void onShutdown(@Observes ShutdownEvent event) {
- if (cacheManager.isDefaultRunning()) {
- cacheManager.stop();
- }
+ public List<ProjectFolderCommit> getProjectLastCommits(String projectId) {
+ return lastFolderCommits.get(projectId);
}
- public String getTemplate(String name, String className, String template) {
- return getTemplate(name, className, template, 0, true);
+ public void saveProjectLastCommits(String projectId, List<ProjectFolderCommit> commits) {
+ lastFolderCommits.put(projectId, commits);
}
- public String getTemplate(String name, String className, String template, long lifespan, Boolean indexing) {
- var json = new JsonObject(template);
- var firstKey = json.fieldNames().iterator().next();
- json.getJsonObject(firstKey).put("name", name);
- if (indexing) {
- json.getJsonObject(firstKey).getJsonObject("indexing").getJsonArray("indexed-entities").add(PLATFORM_PREFIX + "." + className);
- } else {
- json.getJsonObject(firstKey).remove("indexing");
- }
- if (lifespan > 0) {
- var expiration = new JsonObject().put("lifespan", lifespan);
- json.getJsonObject(firstKey).put("expiration", expiration);
- }
- return json.encodePrettily();
+ public void saveSystemCommit(SystemCommit commit) {
+ systemCommits.put(commit.getId(), commit);
+ }
+ public void saveSystemCommits(List<SystemCommit> commits) {
+ commits.forEach(this::saveSystemCommit);;
}
- public EmbeddedCacheManager getCacheManager() {
- return cacheManager;
+ public List<SystemCommit> getSystemLastCommits() {
+ return systemCommits.values().stream().sorted(Comparator.comparing(SystemCommit::getCommitTime)).collect(Collectors.toList()).reversed();
}
+ // --- Project Folders ---
+
public List<ProjectFolder> getFolders() {
- return new ArrayList<>(folders.values().stream().toList());
+ return query(folders, f -> true, ProjectFolder::copy);
}
- public void saveProject(ProjectFolder projectFolder) {
+ public void saveProject(ProjectFolder projectFolder, boolean persist) {
var key = GroupedKey.create(projectFolder.getProjectId(), DEV, projectFolder.getProjectId());
+ if (projectFolder.lastUpdate == 0) {
+ projectFolder.setLastUpdate(Instant.now().getEpochSecond() * 1000L);
+ }
folders.put(key, projectFolder);
+ if (persist) {
+ eventBus.publish(PERSIST_PROJECT, new CacheEvent(key, SAVE, projectFolder));
+ }
+ }
+
+ public void deleteProject(String projectId) {
+ var key = GroupedKey.create(projectId, DEV, projectId);
+ folders.remove(key);
+ eventBus.publish(PERSIST_PROJECT, new CacheEvent(key, DELETE, null));
+ }
+
+ public ProjectFolder getProject(String projectId) {
+ ProjectFolder f = folders.get(GroupedKey.create(projectId, DEV, projectId));
+ return f != null ? f.copy() : null;
+ }
+
+ // --- Project Folders Commited ---
+
+ public List<ProjectFolderCommited> getFoldersCommited() {
+ return query(foldersCommited, f -> true, ProjectFolderCommited::copy);
+ }
+
+ public void saveProjectCommited(ProjectFolderCommited projectFolder) {
+ var key = GroupedKey.create(projectFolder.getProjectId(), DEV, projectFolder.getProjectId());
+ foldersCommited.put(key, projectFolder);
+ }
+
+ public void deleteProjectCommited(String projectId) {
+ var key = GroupedKey.create(projectId, DEV, projectId);
+ foldersCommited.remove(key);
+ }
+
+ public ProjectFolderCommited getProjectCommited(String projectId) {
+ ProjectFolderCommited f = foldersCommited.get(GroupedKey.create(projectId, DEV, projectId));
+ return f != null ? f.copy() : null;
+ }
+
+ // --- Project Files ---
+
+ public Map<String, Long> getLatestUpdatePerProject() {
+ return files.values().stream().collect(Collectors.toMap(
+ ProjectFile::getProjectId,
+ ProjectFile::getLastUpdate,
+ Math::max
+ ));
}
public List<ProjectFile> getProjectFiles(String projectId) {
- return files.<ProjectFile>query("FROM " + ProjectFile.class.getCanonicalName() + " WHERE projectId = :projectId")
- .setParameter("projectId", projectId)
- .execute().list();
+ return query(files, f -> Objects.equals(f.getProjectId(), projectId), ProjectFile::copy);
}
public Map<String, ProjectFile> getProjectFilesMap(String projectId) {
return getProjectFiles(projectId).stream()
- .collect(Collectors.toMap(ProjectFile::getName, ProjectFile::copy));
+ .collect(Collectors.toMap(ProjectFile::getName, f -> f)); // Already copies from getProjectFiles
}
public ProjectFile getProjectFile(String projectId, String filename) {
- var list = files.<ProjectFile>query("FROM " + ProjectFile.class.getCanonicalName() + " WHERE projectId = :projectId AND name = :filename")
- .setParameter("projectId", projectId)
- .setParameter("filename", filename)
- .execute().list();
- return list.isEmpty() ? null : list.getFirst();
+ return queryFirst(files,
+ f -> Objects.equals(f.getProjectId(), projectId) && Objects.equals(f.getName(), filename),
+ ProjectFile::copy);
}
public List<ProjectFile> getProjectFilesByName(String filename) {
- return files.<ProjectFile>query("FROM " + ProjectFile.class.getCanonicalName() + " WHERE name = :filename")
- .setParameter("filename", filename)
- .execute().list();
+ return query(files, f -> Objects.equals(f.getName(), filename), ProjectFile::copy);
}
- public void saveProjectFile(ProjectFile file, boolean commited) {
+ public void saveProjectFile(ProjectFile file, String commitId, boolean persist) {
var key = GroupedKey.create(file.getProjectId(), DEV, file.getName());
files.put(key, file);
- if (commited) {
- filesCommited.put(key, ProjectFileCommited.fromFile(file));
+ if (commitId != null) {
+ saveProjectFileCommited(ProjectFileCommited.fromFile(file, commitId));
+ }
+ if (persist) {
+ eventBus.publish(PERSIST_PROJECT, new CacheEvent(key, SAVE, file));
}
}
- public void syncFilesCommited(String projectId, List<String> fileNames) {
- List<String> currentFileNames = new ArrayList<>();
- getProjectFilesCommited(projectId).stream().filter(file -> fileNames.contains(file.getName()))
- .forEach(pf -> currentFileNames.add(pf.getName()));
-
- currentFileNames.forEach(name -> deleteProjectFileCommited(projectId, name));
- getProjectFiles(projectId).stream().filter(file -> fileNames.contains(file.getName()))
- .forEach(f -> saveProjectFileCommited(ProjectFileCommited.fromFile(f)));
- }
-
- public void saveProjectFiles(Map<String, ProjectFile> filesToSave) {
- long lastUpdate = Instant.now().toEpochMilli();
+ public void saveProjectFiles(Map<String, ProjectFile> filesToSave, boolean persist) {
+ long lastUpdate = Instant.now().getEpochSecond() * 1000L;
filesToSave.forEach((groupedKey, projectFile) -> {
projectFile.setLastUpdate(lastUpdate);
- saveProjectFile(projectFile, false);
+ saveProjectFile(projectFile, null, persist);
});
}
public void deleteProjectFile(String projectId, String filename) {
var key = GroupedKey.create(projectId, DEV, filename);
files.remove(key);
+ eventBus.publish(PERSIST_PROJECT, new CacheEvent(key, DELETE, null));
}
+ // --- Committed Files ---
+
public List<ProjectFileCommited> getProjectFilesCommited(String projectId) {
- return filesCommited.<ProjectFileCommited>query("FROM " + ProjectFileCommited.class.getCanonicalName() + " WHERE projectId = :projectId")
- .setParameter("projectId", projectId)
- .execute().list();
+ return query(filesCommited, f -> Objects.equals(f.getProjectId(), projectId), ProjectFileCommited::copy);
}
public ProjectFileCommited getProjectFileCommited(String projectId, String filename) {
- var list = filesCommited.<ProjectFileCommited>query("FROM " + ProjectFileCommited.class.getCanonicalName() + " WHERE projectId = :projectId AND name = :filename")
- .setParameter("projectId", projectId)
- .setParameter("filename", filename)
- .execute().list();
- return list.isEmpty() ? null : list.getFirst();
+ return queryFirst(filesCommited,
+ f -> Objects.equals(f.getProjectId(), projectId) && Objects.equals(f.getName(), filename),
+ ProjectFileCommited::copy);
}
+ public void deleteProjectFileCommited(String projectId) {
+ getProjectFilesCommited(projectId).forEach(file -> {
+ filesCommited.remove(GroupedKey.create(projectId, DEV, file.name));
+ });
+ }
public void deleteProjectFileCommited(String projectId, String filename) {
filesCommited.remove(GroupedKey.create(projectId, DEV, filename));
}
@@ -191,18 +215,7 @@ public class KaravanCache {
filesCommited.put(GroupedKey.create(file.getProjectId(), DEV, file.getName()), file);
}
- public void deleteProject(String projectId) {
- var key = GroupedKey.create(projectId, DEV, projectId);
- folders.remove(key);
- }
-
- public ProjectFolder getProject(String projectId) {
- return folders.get(GroupedKey.create(projectId, DEV, projectId));
- }
-
- public DeploymentStatus getDeploymentStatus(String projectId, String environment) {
- return deploymentStatuses.get(GroupedKey.create(projectId, environment, projectId));
- }
+ // --- Deployment Status ---
public void saveDeploymentStatus(DeploymentStatus status) {
deploymentStatuses.put(GroupedKey.create(status.getProjectId(), status.getEnv(), status.getProjectId()), status);
@@ -213,13 +226,16 @@ public class KaravanCache {
}
public List<DeploymentStatus> getDeploymentStatuses() {
- return new ArrayList<>(deploymentStatuses.values().stream().toList());
+ return query(deploymentStatuses, s -> true, DeploymentStatus::copy);
}
public List<DeploymentStatus> getDeploymentStatuses(String env) {
- return deploymentStatuses.<DeploymentStatus>query("FROM " + DeploymentStatus.class.getCanonicalName() + " WHERE env = :env")
- .setParameter("env", env)
- .execute().list();
+ return query(deploymentStatuses, s -> Objects.equals(s.getEnv(), env), DeploymentStatus::copy);
+ }
+
+ public DeploymentStatus getDeploymentStatus(String projectId, String environment) {
+ DeploymentStatus s = deploymentStatuses.get(GroupedKey.create(projectId, environment, projectId));
+ return s != null ? s.copy() : null;
}
public void deleteAllDeploymentsStatuses() {
@@ -238,15 +254,26 @@ public class KaravanCache {
return new ArrayList<>(serviceStatuses.values().stream().toList());
}
- public List<PodContainerStatus> getPodContainerStatuses() {
- return new ArrayList<>(podContainerStatuses.values().stream().toList());
- }
+ // --- Pod / Container Status ---
public List<PodContainerStatus> getPodContainerStatuses(String projectId, String env) {
- return podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE projectId = :projectId AND env = :env")
- .setParameter("projectId", projectId)
- .setParameter("env", env)
- .execute().list();
+ return query(podContainerStatuses,
+ s -> Objects.equals(s.getProjectId(), projectId) && Objects.equals(s.getEnv(), env),
+ PodContainerStatus::copy);
+ }
+
+ public PodContainerStatus getBuildPodContainerStatus(String projectId, String env) {
+ return queryFirst(podContainerStatuses,
+ s -> Objects.equals(s.getProjectId(), projectId) && Objects.equals(s.getEnv(), env) && s.getType() == ContainerType.build,
+ PodContainerStatus::copy);
+ }
+
+ public List<PodContainerStatus> getDevModeStatuses() {
+ return query(podContainerStatuses, s -> s.getType() == ContainerType.devmode, PodContainerStatus::copy);
+ }
+
+ public List<PodContainerStatus> getPodContainerStatuses() {
+ return new ArrayList<>(podContainerStatuses.values().stream().toList());
}
public PodContainerStatus getPodContainerStatus(String projectId, String env, String containerName) {
@@ -261,28 +288,19 @@ public class KaravanCache {
return podContainerStatuses.get(key);
}
- public PodContainerStatus getBuildPodContainerStatus(String projectId, String env) {
- var list = podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE projectId = :projectId AND env = :env AND type = :type")
- .setParameter("projectId", projectId)
- .setParameter("env", env)
- .setParameter("type", ContainerType.build)
- .execute().list();
- return list.isEmpty() ? null : list.getFirst();
- }
public PodContainerStatus getDevModePodContainerStatus(String projectId, String env) {
- var list = podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE projectId = :projectId AND env = :env AND type = :type")
- .setParameter("projectId", projectId)
- .setParameter("env", env)
- .setParameter("type", ContainerType.devmode)
- .execute().list();
- return list.isEmpty() ? null : list.getFirst();
+ return queryFirst(podContainerStatuses,
+ status -> Objects.equals(status.getProjectId(), projectId)
+ && Objects.equals(status.getEnv(), env)
+ && status.getType() == ContainerType.devmode,
+ PodContainerStatus::copy);
}
public List<PodContainerStatus> getPodContainerStatuses(String env) {
- return podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE env = :env")
- .setParameter("env", env)
- .execute().list();
+ return query(podContainerStatuses,
+ status -> Objects.equals(status.getEnv(), env),
+ PodContainerStatus::copy);
}
public List<PodContainerStatus> getAllContainerStatuses() {
@@ -301,40 +319,31 @@ public class KaravanCache {
podContainerStatuses.clear();
}
-// public void deletePodContainerStatus(String projectId, String env, String containerName) {
-// podContainerStatuses.remove(GroupedKey.create(projectId, env, containerName));
-// }
-//
-// public CamelStatus getCamelStatus(String projectId, String env, String containerName) {
-// var key = GroupedKey.create(projectId, env, containerName);
-// return camelStatuses.get(key);
-// }
-//
-// public CamelStatus getCamelStatus(String key) {
-// return camelStatuses.get(key);
-// }
+ // --- Camel Status ---
+
+ public List<CamelStatus> getCamelStatusesByProjectAndEnv(String projectId, String env) {
+ return query(camelStatuses,
+ s -> Objects.equals(s.getProjectId(), projectId) && Objects.equals(s.getEnv(), env),
+ CamelStatus::copy);
+ }
public List<CamelStatus> getCamelStatusesByName(CamelStatusValue.Name name) {
- var allStatuses = new ArrayList<>(camelStatuses.values().stream().toList());
- return allStatuses.stream().map(cs -> {
- var status = cs.copy();
- var values = new ArrayList<>(status.getStatuses());
- status.setStatuses(values.stream().filter(v -> Objects.equals(v.getName().toString(), name.name())).toList());
- return status;
- }).toList();
+ return camelStatuses.values().stream()
+ .map(cs -> {
+ var copy = cs.copy();
+ var filteredValues = copy.getStatuses().stream()
+ .filter(v -> Objects.equals(v.getName(), name))
+ .toList();
+ copy.setStatuses(filteredValues);
+ return copy;
+ }).toList();
}
+
public List<CamelStatus> getCamelAllStatuses() {
return new ArrayList<>(camelStatuses.values().stream().toList());
}
- public List<CamelStatus> getCamelStatusesByProjectAndEnv(String projectId, String env) {
- return camelStatuses.<CamelStatus>query("FROM " + CamelStatus.class.getCanonicalName() + " WHERE projectId = :projectId AND env = :env")
- .setParameter("projectId", projectId)
- .setParameter("env", env)
- .execute().list();
- }
-
public void saveCamelStatus(CamelStatus status) {
var key = GroupedKey.create(status.getProjectId(), status.getEnv(), status.getContainerName());
camelStatuses.put(key, status);
@@ -346,51 +355,32 @@ public class KaravanCache {
}
public void deleteCamelStatuses(String projectId, String env) {
- var list = camelStatuses.<CamelStatus>query("FROM " + CamelStatus.class.getCanonicalName() + " WHERE projectId = :projectId AND env = :env")
- .setParameter("projectId", projectId)
- .setParameter("env", env)
- .execute().list();
- if (!list.isEmpty()) {
- list.forEach(s -> {
- var key = GroupedKey.create(projectId, env, s.getContainerName());
- camelStatuses.remove(key);
- });
- }
+ camelStatuses.entrySet().removeIf(entry -> {
+ CamelStatus status = entry.getValue();
+ return Objects.equals(status.getProjectId(), projectId)
+ && Objects.equals(status.getEnv(), env);
+ });
}
-
+
public void deleteAllCamelStatuses() {
camelStatuses.clear();
}
- public List<PodContainerStatus> getLoadedDevModeStatuses() {
- return podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE type = :type AND codeLoaded = true")
- .setParameter("type", ContainerType.devmode)
- .execute().list();
- }
-
- public List<PodContainerStatus> getDevModeStatuses() {
- return podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE type = :type")
- .setParameter("type", ContainerType.devmode)
- .execute().list();
- }
+ // --- Access & Sessions ---
- public List<PodContainerStatus> getContainerStatusByEnv(String env) {
- return podContainerStatuses.<PodContainerStatus>query("FROM " + PodContainerStatus.class.getCanonicalName() + " WHERE env = :env")
- .setParameter("env", env)
- .execute().list();
- }
-
- // Access
public AccessPassword getPassword(String username) {
- return passwords.get(username);
+ var key = GroupedKey.create(AccessPassword.class.getSimpleName(), DEV, username);
+ return passwords.get(key);
}
public AccessUser getUser(String username) {
- return users.get(username);
+ var key = GroupedKey.create(AccessUser.class.getSimpleName(), DEV, username);
+ return users.get(key);
}
public AccessRole getRole(String name) {
- return roles.get(name);
+ var key = GroupedKey.create(AccessRole.class.getSimpleName(), DEV, name);
+ return roles.get(key);
}
public List<AccessUser> getUsers() {
@@ -400,40 +390,70 @@ public class KaravanCache {
return new ArrayList<>(roles.values().stream().toList());
}
- public void saveUser(AccessUser user) {
- users.put(user.username, user);
+ public void saveUser(AccessUser user, boolean persist) {
+ var key = GroupedKey.create(user.getClass().getSimpleName(), DEV, user.username);
+ users.put(key, user);
+ if (persist) {
+ eventBus.send(PERSIST_ACCESS, new CacheEvent(key, SAVE, user));
+ }
}
- public void savePassword(AccessPassword pass) {
- passwords.put(pass.username, pass);
+ public void savePassword(AccessPassword pass, boolean persist) {
+ var key = GroupedKey.create(pass.getClass().getSimpleName(), DEV, pass.username);
+ passwords.put(key, pass);
+ if (persist) {
+ eventBus.send(PERSIST_ACCESS, new CacheEvent(key, SAVE, pass));
+ }
}
- public void saveRole(AccessRole role) {
- roles.put(role.name, role);
+ public void saveRole(AccessRole role, boolean persist) {
+ var key = GroupedKey.create(role.getClass().getSimpleName(), DEV, role.name);
+ roles.put(key, role);
+ if (persist) {
+ eventBus.send(PERSIST_ACCESS, new CacheEvent(key, SAVE, role));
+ }
}
public void deleteUser(String username) {
+ var key = GroupedKey.create(AccessUser.class.getSimpleName(), DEV, username);
if (!USER_ADMIN.equals(username)) {
- users.remove(username);
+ users.remove(key);
+ eventBus.send(PERSIST_ACCESS, new CacheEvent(key, DELETE, null));
}
}
public void deleteRole(AccessRole role) {
+ var key = GroupedKey.create(role.getClass().getSimpleName(), DEV, role.name);
if (!AuthService.getAllRoles().contains(role.name)) {
- roles.remove(role.name, role);
+ roles.remove(key, role);
+ eventBus.send(PERSIST_ACCESS, new CacheEvent(key, DELETE, null));
}
}
// Sessions
+
+ public List<AccessSession> getAccessSessions() {
+ return sessions.values().stream().map(AccessSession::copy).toList();
+ }
+
public AccessSession getAccessSession(String sessionsId) {
return sessions.get(sessionsId);
}
- public void saveAccessSession(AccessSession session) {
- sessions.put(session.sessionId, session, 12 * 60, TimeUnit.MINUTES); // 12h absolute
+ public void saveAccessSession(AccessSession session, boolean persist) {
+ sessions.put(session.sessionId, session); // 12h absolute
+ if (persist) {
+ eventBus.send(PERSIST_SESSION, new CacheEvent(session.sessionId, SAVE, session));
+ }
}
public void deleteAccessSession(String sessionId) {
+ var session = sessions.get(sessionId);
+ if (session != null) {
+ deleteUserHeartBeat(session.username);
+ deleteUserWorking(session.username);
+ }
sessions.remove(sessionId);
+ eventBus.send(PERSIST_SESSION, new CacheEvent(sessionId, DELETE, null));
}
public void clearAllStatuses() {
@@ -453,6 +473,29 @@ public class KaravanCache {
return Map.copyOf(projectActivities);
}
+ public void saveUserWorking(ActivityUser activityUser) {
+ usersWorking.put(activityUser.getUserName(), activityUser);
+ }
+
+ public Map<String, ActivityUser> getCopyUsersWorking() {
+ return Map.copyOf(usersWorking);
+ }
+ public void saveUserHeartBeat(ActivityUser activityUser) {
+ usersHeartBeat.put(activityUser.getUserName(), activityUser);
+ }
+
+ public Map<String, ActivityUser> getCopyUsersHeartBeat() {
+ return Map.copyOf(usersHeartBeat);
+ }
+
+ public void deleteUserHeartBeat(String userName) {
+ usersHeartBeat.remove(userName);
+ }
+
+ public void deleteUserWorking(String userName) {
+ usersWorking.remove(userName);
+ }
+
public void clearExpiredActivity(Instant limit) {
getCopyProjectActivities().forEach((projectId, activities) -> {
Map<String, Instant> acts = new HashMap<>();
@@ -464,10 +507,4 @@ public class KaravanCache {
projectActivities.put(projectId, acts);
});
}
-
- public void stopCacheManager() {
- if (cacheManager != null) {
- cacheManager.stop();
- }
- }
}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanStoreSchema.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanStoreSchema.java
deleted file mode 100644
index cf5747ab..00000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanStoreSchema.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.apache.camel.karavan.cache;
-
-import org.infinispan.protostream.GeneratedSchema;
-import org.infinispan.protostream.annotations.ProtoSchema;
-import org.infinispan.protostream.annotations.ProtoSyntax;
-
-import static org.apache.camel.karavan.KaravanConstants.PLATFORM_PREFIX;
-
-@ProtoSchema(
- includeClasses = {
- GroupedKey.class,
- ProjectFolder.class,
- ProjectFolder.Type.class,
- ProjectFile.class,
- ProjectFileCommited.class,
- ContainerType.class,
- DeploymentStatus.class,
- ServiceStatus.class,
- ContainerPort.class,
- PodContainerStatus.class,
- PodContainerStatus.Command.class,
- PodContainerStatus.State.class,
- CamelStatus.class,
- CamelStatusValue.class,
- CamelStatusValue.Name.class,
- AccessPassword.class,
- AccessUser.class,
- AccessUser.UserStatus.class,
- AccessRole.class,
- AccessSession.class,
- },
- syntax = ProtoSyntax.PROTO3,
- schemaFileName = PLATFORM_PREFIX + ".proto")
-public interface KaravanStoreSchema extends GeneratedSchema {
-
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/PodContainerStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/PodContainerStatus.java
index 39327ac6..d42d0cd9 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/PodContainerStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/PodContainerStatus.java
@@ -17,120 +17,51 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Embedded;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.api.annotations.indexing.Text;
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
import java.time.Instant;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-@Indexed
public class PodContainerStatus {
- @Indexed
public enum State {
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 0, name = "created")
created,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 1, name = "running")
running,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 2, name = "restarting")
restarting,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 3, name = "paused")
paused,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 4, name = "exited")
exited,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 5, name = "dead")
dead
}
- @Indexed
public enum Command {
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 0, name = "run")
run,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 1, name = "pause")
pause,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 2, name = "stop")
stop,
- @Keyword(projectable = true, sortable = true)
- @ProtoEnumValue(number = 3, name = "delete")
delete,
}
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String projectId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
String containerName;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String containerId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(4)
String image;
- @Embedded
- @ProtoField(value = 5, collectionImplementation = ArrayList.class)
List<ContainerPort> ports;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(6)
String env;
- @Embedded
- @ProtoField(7)
ContainerType type;
- @Text
- @ProtoField(8)
String memoryInfo;
- @Text
- @ProtoField(9)
String cpuInfo;
- @ProtoField(10)
String created;
- @ProtoField(11)
String finished;
- @Embedded
- @ProtoField(value = 12, collectionImplementation = ArrayList.class)
List<Command> commands;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(13)
String state;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(14)
String phase;
- @ProtoField(15)
Boolean codeLoaded;
- @ProtoField(16)
Boolean inTransit = false;
- @ProtoField(17)
String initDate;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(18)
String podIP;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(19)
String camelRuntime;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(20)
String commit;
- @ProtoField(value = 21, mapImplementation = HashMap.class)
Map<String, String> labels;
- @ProtoFactory
public PodContainerStatus(String projectId, String containerName, String containerId, String image, List<ContainerPort> ports, String env, ContainerType type, String memoryInfo, String cpuInfo, String created, String finished, List<Command> commands, String state, String phase, Boolean codeLoaded, Boolean inTransit, String initDate, String podIP, String camelRuntime, String commit, Map<String, String> labels) {
this.projectId = projectId;
this.containerName = containerName;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFile.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFile.java
index 457ac6f5..2f98fa20 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFile.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFile.java
@@ -17,30 +17,13 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.api.annotations.indexing.Text;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class ProjectFile {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String name;
- @Text
- @ProtoField(2)
String code;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String projectId;
- @Basic(projectable = true, sortable = true)
- @ProtoField(4)
Long lastUpdate;
- @ProtoFactory
public ProjectFile(String name, String code, String projectId, Long lastUpdate) {
this.name = name;
this.code = code;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommitDiff.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommitDiff.java
index 5ad31c96..d8b2567b 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommitDiff.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommitDiff.java
@@ -22,31 +22,77 @@ public class ProjectFileCommitDiff {
private String newPath;
private String oldPath;
private String diff;
+ private String before;
+ private String after;
public ProjectFileCommitDiff() {
}
- public ProjectFileCommitDiff(String changeType, String newPath, String oldPath, String diff) {
+ public ProjectFileCommitDiff(String changeType, String newPath, String oldPath, String diff, String before, String after) {
this.changeType = changeType;
this.newPath = newPath;
this.oldPath = oldPath;
this.diff = diff;
+ this.before = before;
+ this.after = after;
}
public String getChangeType() {
return changeType;
}
+ public void setChangeType(String changeType) {
+ this.changeType = changeType;
+ }
+
public String getNewPath() {
return newPath;
}
+ public void setNewPath(String newPath) {
+ this.newPath = newPath;
+ }
+
public String getOldPath() {
return oldPath;
}
+ public void setOldPath(String oldPath) {
+ this.oldPath = oldPath;
+ }
+
public String getDiff() {
return diff;
}
+
+ public void setDiff(String diff) {
+ this.diff = diff;
+ }
+
+ public String getBefore() {
+ return before;
+ }
+
+ public void setBefore(String before) {
+ this.before = before;
+ }
+
+ public String getAfter() {
+ return after;
+ }
+
+ public void setAfter(String after) {
+ this.after = after;
+ }
+
+ @Override
+ public String toString() {
+ return "ProjectFileCommitDiff{" +
+ "changeType='" + changeType + '\'' +
+ ", newPath='" + newPath + '\'' +
+ ", oldPath='" + oldPath + '\'' +
+ ", diff='" + diff + '\'' +
+ '}';
+ }
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommited.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommited.java
index cae6c271..efb8f427 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommited.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFileCommited.java
@@ -17,54 +17,42 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.api.annotations.indexing.Text;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class ProjectFileCommited {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String name;
- @Text
- @ProtoField(2)
String code;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String projectId;
- @Basic(projectable = true, sortable = true)
- @ProtoField(4)
- Long lastUpdate;
- @Basic(projectable = true, sortable = true)
- @ProtoField(5)
- Long syncDate;
-
- @ProtoFactory
- public ProjectFileCommited(String name, String code, String projectId, Long lastUpdate, Long syncDate) {
+ String commitId;
+ Long commitTime;
+
+ public ProjectFileCommited(String name, String code, String projectId, String commitId, Long commitTime) {
this.name = name;
this.code = code;
this.projectId = projectId;
- this.lastUpdate = lastUpdate;
- this.syncDate = syncDate;
+ this.commitId = commitId;
+ this.commitTime = commitTime;
}
public ProjectFileCommited() {
}
- public static ProjectFileCommited fromFile(ProjectFile file) {
+ public static ProjectFileCommited fromFile(ProjectFile file, String commitId) {
var fileCommited = new ProjectFileCommited();
fileCommited.name = file.getName();
fileCommited.code = file.getCode();
fileCommited.projectId = file.getProjectId();
- fileCommited.lastUpdate = file.getLastUpdate();
+ fileCommited.commitTime = file.getLastUpdate();
+ fileCommited.commitId = commitId;
return fileCommited;
}
+ public String getCommitId() {
+ return commitId;
+ }
+ public void setCommitId(String commitId) {
+ this.commitId = commitId;
+ }
public String getName() {
return name;
@@ -90,24 +78,16 @@ public class ProjectFileCommited {
this.projectId = projectId;
}
- public Long getLastUpdate() {
- return lastUpdate;
- }
-
- public void setLastUpdate(Long lastUpdate) {
- this.lastUpdate = lastUpdate;
- }
-
- public Long getSyncDate() {
- return syncDate;
+ public Long getCommitTime() {
+ return commitTime;
}
- public void setSyncDate(Long syncDate) {
- this.syncDate = syncDate;
+ public void setCommitTime(Long commitTime) {
+ this.commitTime = commitTime;
}
public ProjectFileCommited copy() {
- return new ProjectFileCommited(name, code, projectId, lastUpdate, syncDate);
+ return new ProjectFileCommited(name, code, projectId, commitId, commitTime);
}
@Override
@@ -116,7 +96,7 @@ public class ProjectFileCommited {
"name='" + name + '\'' +
", code='" + code + '\'' +
", projectId='" + projectId + '\'' +
- ", lastUpdate=" + lastUpdate +
+ ", lastUpdate=" + commitTime +
'}';
}
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolder.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolder.java
index c95bcf29..50a63e95 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolder.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolder.java
@@ -17,80 +17,51 @@
package org.apache.camel.karavan.cache;
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
-@Indexed
public class ProjectFolder {
public enum Type {
-
- @ProtoEnumValue(number = 0, name = "templates")
templates,
- @ProtoEnumValue(number = 1, name = "kamelets")
kamelets,
- @ProtoEnumValue(number = 2, name = "configuration")
configuration,
- @ProtoEnumValue(number = 3, name = "documentation")
documentation,
- @ProtoEnumValue(number = 4, name = "shared")
- shared,
- @ProtoEnumValue(number = 5, name = "services")
+ contracts,
services,
- @ProtoEnumValue(number = 6, name = "integration")
integration,
+ backlog,
}
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String projectId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
String name;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
- String lastCommit;
- @Basic(projectable = true, sortable = true)
- @ProtoField(4)
- Long lastCommitTimestamp;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(5)
+ Long lastUpdate = 0L;
Type type;
- @ProtoFactory
- public ProjectFolder(String projectId, String name, String lastCommit, Long lastCommitTimestamp, Type type) {
+ public ProjectFolder(String projectId, String name, Long lastUpdate, Type type) {
this.projectId = projectId;
this.name = name;
- this.lastCommit = lastCommit;
- this.lastCommitTimestamp = lastCommitTimestamp;
+ this.lastUpdate = lastUpdate;
this.type = type;
}
- public ProjectFolder(String projectId, String name, String lastCommit, Long lastCommitTimestamp) {
+ public ProjectFolder(String projectId, String name, Long lastUpdate) {
this.projectId = projectId;
this.name = name;
- this.lastCommit = lastCommit;
- this.lastCommitTimestamp = lastCommitTimestamp;
+ this.lastUpdate = lastUpdate;
this.type = Arrays.stream(Type.values()).anyMatch(t -> t.name().equals(projectId)) ? Type.valueOf(projectId) : Type.integration;
}
public ProjectFolder(String projectId, String name) {
this.projectId = projectId;
this.name = name;
- this.lastCommitTimestamp = Instant.now().toEpochMilli();
+ this.lastUpdate = Instant.now().getEpochSecond() * 1000L;
this.type = Arrays.stream(Type.values()).anyMatch(t -> t.name().equals(projectId)) ? Type.valueOf(projectId) : Type.integration;
}
public ProjectFolder copy() {
- return new ProjectFolder(projectId, name, lastCommit, lastCommitTimestamp, type);
+ return new ProjectFolder(projectId, name, lastUpdate, type);
}
public ProjectFolder() {
@@ -113,20 +84,12 @@ public class ProjectFolder {
this.name = name;
}
- public String getLastCommit() {
- return lastCommit;
- }
-
- public void setLastCommit(String lastCommit) {
- this.lastCommit = lastCommit;
- }
-
- public Long getLastCommitTimestamp() {
- return lastCommitTimestamp;
+ public Long getLastUpdate() {
+ return lastUpdate;
}
- public void setLastCommitTimestamp(Long lastCommitTimestamp) {
- this.lastCommitTimestamp = lastCommitTimestamp;
+ public void setLastUpdate(Long lastUpdate) {
+ this.lastUpdate = lastUpdate;
}
public Type getType() {
@@ -139,11 +102,12 @@ public class ProjectFolder {
public static List<String> getBuildInNames(){
return List.of(
- Type.configuration.name(),
- Type.kamelets.name(),
- Type.templates.name(),
- Type.shared.name(),
- Type.documentation.name()
+ Type.configuration.name(),
+ Type.kamelets.name(),
+ Type.templates.name(),
+ Type.contracts.name(),
+ Type.documentation.name(),
+ Type.backlog.name()
);
}
@@ -152,9 +116,8 @@ public class ProjectFolder {
return "Project{" +
"projectId='" + projectId + '\'' +
", name='" + name + '\'' +
- ", lastCommit='" + lastCommit + '\'' +
- ", lastCommitTimestamp=" + lastCommitTimestamp +
+ ", lastUpdate=" + lastUpdate +
", type=" + type +
'}';
}
-}
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommit.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommit.java
index 1640a0a3..4a9f8e39 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommit.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommit.java
@@ -25,17 +25,19 @@ public class ProjectFolderCommit {
private String projectId;
private String authorName;
private String authorEmail;
+ private Long commitTime;
private String message;
private List<ProjectFileCommitDiff> diffs = new ArrayList<>();
public ProjectFolderCommit() {
}
- public ProjectFolderCommit(String id, String projectId, String authorName, String authorEmail, String message, List<ProjectFileCommitDiff> diffs) {
+ public ProjectFolderCommit(String id, String projectId, String authorName, String authorEmail, Long commitTime, String message, List<ProjectFileCommitDiff> diffs) {
this.id = id;
this.projectId = projectId;
this.authorName = authorName;
this.authorEmail = authorEmail;
+ this.commitTime = commitTime;
this.message = message;
this.diffs = diffs;
}
@@ -87,4 +89,24 @@ public class ProjectFolderCommit {
public void setDiffs(List<ProjectFileCommitDiff> diffs) {
this.diffs = diffs;
}
+
+ public Long getCommitTime() {
+ return commitTime;
+ }
+
+ public void setCommitTime(Long commitTime) {
+ this.commitTime = commitTime;
+ }
+
+ @Override
+ public String toString() {
+ return "ProjectFolderCommit{" +
+ "id='" + id + '\'' +
+ ", projectId='" + projectId + '\'' +
+ ", authorName='" + authorName + '\'' +
+ ", authorEmail='" + authorEmail + '\'' +
+ ", message='" + message + '\'' +
+ ", diffs=" + diffs +
+ '}';
+ }
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ServiceStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ServiceStatus.java
index fcd04aec..13d45576 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ServiceStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ServiceStatus.java
@@ -17,45 +17,20 @@
package org.apache.camel.karavan.cache;
-
-import org.infinispan.api.annotations.indexing.Basic;
-import org.infinispan.api.annotations.indexing.Indexed;
-import org.infinispan.api.annotations.indexing.Keyword;
-import org.infinispan.protostream.annotations.ProtoFactory;
-import org.infinispan.protostream.annotations.ProtoField;
-
-@Indexed
public class ServiceStatus {
- @Keyword(projectable = true, sortable = true)
- @ProtoField(1)
String projectId;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(2)
String namespace;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(3)
String env;
- @Keyword(projectable = true, sortable = true)
- @ProtoField(4)
String cluster;
- @Basic
- @ProtoField(5)
Integer port;
- @Basic
- @ProtoField(6)
Integer targetPort;
- @Basic
- @ProtoField(7)
String clusterIP;
- @Basic
- @ProtoField(8)
String type;
public ServiceStatus() {
}
- @ProtoFactory
public ServiceStatus(String projectId, String namespace, String env, String cluster, Integer port, Integer targetPort, String clusterIP, String type) {
this.projectId = projectId;
this.namespace = namespace;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityFile.java b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityFile.java
index 91f62c58..9d004982 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityFile.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityFile.java
@@ -5,7 +5,7 @@ import java.util.Map;
public class ComplexityFile {
- public enum Type {camel, java, docker, kubernetes, properties, other}
+ public enum Type {camel, java, docker, kubernetes, properties, other, openapi}
private String fileName;
private String error;
@@ -14,6 +14,7 @@ public class ComplexityFile {
private Integer routes = 0;
private Integer beans = 0;
private Integer rests = 0;
+ private boolean isGenerated = false;
private Complexity complexity = Complexity.easy;
private Complexity complexityLines = Complexity.easy;
private Complexity complexityRoutes = Complexity.easy;
@@ -207,6 +208,13 @@ public class ComplexityFile {
kamelets.put(component, kamelets.getOrDefault(component, 0) + count);
}
+ public boolean isGenerated() {
+ return isGenerated;
+ }
+
+ public void setGenerated(boolean generated) {
+ isGenerated = generated;
+ }
@Override
public String toString() {
return "ComplexityFile{" +
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityProject.java b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityProject.java
index 2a715051..7cab8948 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityProject.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityProject.java
@@ -6,6 +6,7 @@ import java.util.List;
public class ComplexityProject {
private String projectId;
+ private String type;
private Long lastUpdateDate = 0L;
private Complexity complexityRoute = Complexity.easy;
private Complexity complexityRest = Complexity.easy;
@@ -14,12 +15,21 @@ public class ComplexityProject {
private List<ComplexityFile> files = new ArrayList<>();
private List<ComplexityRoute> routes = new ArrayList<>();
private Integer rests = 0;
+ private boolean exposesOpenApi = false;
private List<String> dependencies = new ArrayList<>();
public ComplexityProject() {
}
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
public String getProjectId() {
return projectId;
}
@@ -104,6 +114,14 @@ public class ComplexityProject {
this.dependencies = dependencies;
}
+ public boolean isExposesOpenApi() {
+ return exposesOpenApi;
+ }
+
+ public void setExposesOpenApi(boolean exposesOpenApi) {
+ this.exposesOpenApi = exposesOpenApi;
+ }
+
@Override
public String toString() {
return "ComplexityProject{" +
@@ -119,4 +137,5 @@ public class ComplexityProject {
", dependencies=" + dependencies +
'}';
}
+
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityRoute.java b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityRoute.java
index db10ca0a..3d4b9ec3 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityRoute.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/complexity/ComplexityRoute.java
@@ -9,6 +9,8 @@ public class ComplexityRoute {
private String routeId;
private String nodePrefixId;
+ private String routeTemplateRef;
+ private Boolean isTemplated;
private String fileName;
private Complexity complexityProcessors = Complexity.easy;
private Complexity complexityComponentsInt = Complexity.easy;
@@ -150,4 +152,20 @@ public class ComplexityRoute {
public void addConsumer(ComplexityComponent producer) {
this.consumers.add(producer);
}
+
+ public String getRouteTemplateRef() {
+ return routeTemplateRef;
+ }
+
+ public void setRouteTemplateRef(String routeTemplateRef) {
+ this.routeTemplateRef = routeTemplateRef;
+ }
+
+ public Boolean getTemplated() {
+ return isTemplated;
+ }
+
+ public void setTemplated(Boolean templated) {
+ isTemplated = templated;
+ }
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventHandler.java
index 71eed6c2..28613799 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventHandler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventHandler.java
@@ -58,6 +58,7 @@ public class DockerEventHandler implements ResultCallback<Event> {
@Override
public void onNext(Event event) {
+ LOGGER.debug("DockerEventListener onNext " + event.getAction());
try {
var actorId = event.getActor().getId();
if (Objects.equals(event.getType(), EventType.CONTAINER)) {
@@ -72,7 +73,7 @@ public class DockerEventHandler implements ResultCallback<Event> {
}
public void onContainerEvent(Event event, Container container) throws InterruptedException {
- String projectId = container.getLabels().containsKey(LABEL_INTEGRATION_NAME) ? container.getLabels().get(LABEL_INTEGRATION_NAME) : container.getLabels().get(LABEL_PROJECT_ID);
+ String projectId = container.getLabels().get(LABEL_PROJECT_ID);
if ("exited".equalsIgnoreCase(container.getState())
&& Objects.equals(container.getLabels().get(LABEL_TYPE), ContainerType.build.name())) {
String tag = container.getLabels().get(LABEL_TAG);
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
index 46ca4dfa..f71046c2 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
@@ -69,7 +69,7 @@ public class DockerForKaravan {
env.add(ENV_VAR_VERBOSE_OPTION_NAME + "=" + ENV_VAR_VERBOSE_OPTION_VALUE);
}
if (compile) {
- env.add(RUN_IN_COMPILE_MODE + "=true");
+ env.add(ENV_VAR_RUN_IN_COMPILE_MODE + "=true");
}
if (createM2.orElse(false)) {
@@ -84,7 +84,6 @@ public class DockerForKaravan {
}
containerLabels.put(LABEL_TYPE, ContainerType.devmode.name());
containerLabels.put(LABEL_PROJECT_ID, projectId);
- containerLabels.put(LABEL_INTEGRATION_NAME, projectId);
containerLabels.put(LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue());
return dockerService.createContainer(projectId,
@@ -112,7 +111,7 @@ public class DockerForKaravan {
stack.addEnvironment(ENV_VAR_VERBOSE_OPTION_NAME, ENV_VAR_VERBOSE_OPTION_VALUE);
}
if (compile) {
- stack.addEnvironment(RUN_IN_COMPILE_MODE, "true");
+ stack.addEnvironment(ENV_VAR_RUN_IN_COMPILE_MODE, "true");
}
if (createM2.orElse(false)) {
@@ -128,7 +127,6 @@ public class DockerForKaravan {
}
containerLabels.put(LABEL_TYPE, ContainerType.devmode.name());
containerLabels.put(LABEL_PROJECT_ID, projectId);
- containerLabels.put(LABEL_INTEGRATION_NAME, projectId);
containerLabels.put(LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue());
stack.setLabels(containerLabels);
@@ -143,7 +141,6 @@ public class DockerForKaravan {
if (createM2.orElse(false)) {
compose.getVolumes().add(new DockerVolumeDefinition(MountType.VOLUME.name(), projectFolder.getProjectId() + "-build-m2-repository", "/karavan/.m2/repository"));
}
- compose.addEnvironment(RUN_IN_BUILD_MODE, "true");
Container c = createBuildContainer(containerName, projectFolder, compose.getEnvironmentList(), compose.getVolumes(), tag);
dockerService.copyExecFile(c.getId(), "/karavan/builder", BUILD_SCRIPT_FILENAME, script);
sshFiles.forEach((name, text) -> {
@@ -159,7 +156,6 @@ public class DockerForKaravan {
stack.getVolumes().add(new DockerVolumeDefinition(MountType.VOLUME.name(), projectFolder.getProjectId() + "-build-m2-repository", "/karavan/.m2/repository"));
}
stack.setHostname(serviceName);
- stack.addEnvironment(RUN_IN_BUILD_MODE, "true");
stack.addConfig(new DockerConfigDefinition(BUILD_SCRIPT_FILENAME, "/karavan/builder" + BUILD_SCRIPT_FILENAME));
// Map<String, String> sshFiles = codeService.getSshFiles();
// TODO: ssh_keys for Docker in Swarm Mode should be already in Secrets
@@ -168,7 +164,6 @@ public class DockerForKaravan {
stack.addLabel(LABEL_TYPE, ContainerType.build.name());
stack.addLabel(LABEL_PROJECT_ID, projectFolder.getProjectId());
- stack.addLabel(LABEL_INTEGRATION_NAME, projectFolder.getProjectId());
stack.addLabel(LABEL_TAG, tag);
stack.setImage(devmodeImage);
stack.setCommand("/karavan/builder/build.sh");
@@ -184,7 +179,6 @@ public class DockerForKaravan {
Map.of(
LABEL_TYPE, ContainerType.build.name(),
LABEL_PROJECT_ID, projectFolder.getProjectId(),
- LABEL_INTEGRATION_NAME, projectFolder.getProjectId(),
LABEL_TAG, tag
),
volumes, null, RestartPolicy.noRestart(), DockerService.PULL_IMAGE.ifNotExists,
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index c9841c90..10405b81 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -1,19 +1,3 @@
-/*
- * 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.
- */
package org.apache.camel.karavan.docker;
import com.github.dockerjava.api.DockerClient;
@@ -23,9 +7,8 @@ import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.DockerClientImpl;
import com.github.dockerjava.core.command.ExecStartResultCallback;
+import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;
-import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
-import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import io.vertx.core.Vertx;
@@ -57,7 +40,6 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
-import java.util.stream.Collectors;
import static org.apache.camel.karavan.KaravanConstants.*;
@@ -93,9 +75,8 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
@Inject
Vertx vertx;
- private DockerClient dockerClient;
-
- private DockerClient dockerClientConnectedToRegistry;
+ private volatile DockerClient dockerClient;
+ private volatile DockerClient dockerClientConnectedToRegistry;
private static Boolean IN_SWARM_MODE = null;
@@ -108,24 +89,50 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
void onStart(@Observes StartupEvent ev) {
if (!ConfigService.inKubernetes()) {
+// getDockerClient().eventsCmd().withEventFilter("pull", "create", "attach", "start", "stop", "kill").exec(dockerEventHandler);
try (EventsCmd cmd = getDockerClient().eventsCmd()) {
cmd.exec(dockerEventHandler);
}
}
}
- void onStop(@Observes ShutdownEvent ev) throws IOException {
+ void onStop(@Observes ShutdownEvent ev) {
if (!ConfigService.inKubernetes()) {
- dockerEventHandler.close();
+ try {
+ dockerEventHandler.close();
+ } catch (Exception e) {
+ LOGGER.warn("Error closing DockerEventHandler", e);
+ }
+ shutdownClients();
+ }
+ }
+
+ private synchronized void shutdownClients() {
+ LOGGER.info("Shutting down DockerClient");
+ if (dockerClient != null) {
+ try {
+ dockerClient.close();
+ } catch (IOException e) {
+ LOGGER.warn("Error closing DockerClient", e);
+ } finally {
+ dockerClient = null;
+ }
+ }
+ if (dockerClientConnectedToRegistry != null) {
+ try {
+ dockerClientConnectedToRegistry.close();
+ } catch (IOException e) {
+ LOGGER.warn("Error closing DockerClientConnectedToRegistry", e);
+ } finally {
+ dockerClientConnectedToRegistry = null;
+ }
}
}
public boolean checkDocker() {
+ LOGGER.info("Checking Docker");
try {
- try (InfoCmd cmd = getDockerClient().infoCmd()) {
- Info info = cmd.exec();
- ClusterInfo clusterInfo = info.getSwarm().getClusterInfo();
- }
+ getDockerClient().infoCmd().exec();
return true;
} catch (Exception e) {
LOGGER.error("Error connecting Docker: " + e.getMessage());
@@ -135,12 +142,10 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
public boolean checkDockerSwarm() {
try {
- try (InfoCmd cmd = getDockerClient().infoCmd()) {
- Info info = cmd.exec();
- var swarmInfo = info.getSwarm();
- var nodes = (swarmInfo != null && swarmInfo.getNodes() != null) ? swarmInfo.getNodes() : 0;
- return swarmInfo != null && nodes > 0;
- }
+ Info info = getDockerClient().infoCmd().exec();
+ var swarmInfo = info.getSwarm();
+ var nodes = (swarmInfo != null && swarmInfo.getNodes() != null) ? swarmInfo.getNodes() : 0;
+ return swarmInfo != null && nodes > 0;
} catch (Exception e) {
LOGGER.error("Error connecting Docker: " + e.getMessage());
return false;
@@ -148,8 +153,8 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
}
public JsonObject getInfo() {
- try (InfoCmd cmd = getDockerClient().infoCmd()) {
- var info = cmd.exec();
+ try {
+ var info = getDockerClient().infoCmd().exec();
var swarm = info.getSwarm();
if (swarm != null) {
return JsonObject.of(
@@ -159,23 +164,16 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
"Error", swarm.getError(),
"MemTotal", info.getMemTotal()
);
- } else {
- return JsonObject.of(
- "Nodes", 0,
- "NodeId", null,
- "Managers", null,
- "Error", "Swarm is Null",
- "MemTotal", 0
- );
}
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
}
+ return JsonObject.of("Nodes", 0, "Error", "Swarm or Info is unavailable");
}
public Container getContainer(String id) {
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id))) {
- List<Container> containers = cmd.exec();
- return containers.isEmpty() ? null : containers.getFirst();
- }
+ List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id)).exec();
+ return containers.isEmpty() ? null : containers.getFirst();
}
public Container getContainerByName(String name) {
@@ -184,98 +182,71 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
}
public List<Container> getAllContainers() {
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true)) {
- return cmd.exec();
- }
+ return getDockerClient().listContainersCmd().withShowAll(true).exec();
}
public List<Service> getAllServices() {
- try (ListServicesCmd cmd = getDockerClient().listServicesCmd()) {
- return cmd.exec();
- }
+ return getDockerClient().listServicesCmd().exec();
}
public Secret getSecret(String secretName) {
- try (ListSecretsCmd cmd = getDockerClient().listSecretsCmd().withNameFilter(List.of(secretName))) {
- return cmd.exec().getFirst();
- }
+ return getDockerClient().listSecretsCmd().withNameFilter(List.of(secretName)).exec().getFirst();
}
public CreateSecretResponse createSecret(String secretName, String secretValue) {
var spec = new SecretSpec().withData(secretValue).withName(secretName);
- try (CreateSecretCmd cmd = getDockerClient().createSecretCmd(spec)) {
- return cmd.exec();
- }
+ return getDockerClient().createSecretCmd(spec).exec();
}
public Container createContainerFromCompose(DockerComposeService compose, Map<String, String> labels, PULL_IMAGE pullImage) throws InterruptedException {
List<Container> containers = findContainers(compose.getContainer_name());
if (containers.isEmpty()) {
HealthCheck healthCheck = DockerUtils.getHealthCheck(compose.getHealthcheck());
-
List<String> env = compose.getEnvironmentList();
-
- LOGGER.infof("Compose Service started for %s in network:%s", compose.getContainer_name(), networkName);
-
RestartPolicy restartPolicy = RestartPolicy.noRestart();
- if (Objects.equals(compose.getRestart(), RestartPolicy.onFailureRestart(10).getName())) {
+ if (Objects.equals(compose.getRestart(), "on-failure")) {
restartPolicy = RestartPolicy.onFailureRestart(10);
- } else if (Objects.equals(compose.getRestart(), RestartPolicy.alwaysRestart().getName())) {
+ } else if (Objects.equals(compose.getRestart(), "always")) {
restartPolicy = RestartPolicy.alwaysRestart();
}
return createContainer(compose.getContainer_name(), compose.getImage(),
env, compose.getPortsMap(), healthCheck, labels, compose.getVolumes(), networkName, restartPolicy, pullImage,
compose.getCpus(), compose.getCpu_percent(), compose.getMem_limit(), compose.getMem_reservation(), compose.getCommand());
-
} else {
- LOGGER.info("Compose Service already exists: " + containers.getFirst().getId());
return containers.getFirst();
}
}
public List<Container> findContainersByProjectId(String projectId) {
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withLabelFilter(Map.of(LABEL_INTEGRATION_NAME, projectId))) {
- return cmd.exec();
- }
+ return getDockerClient().listContainersCmd().withLabelFilter(Map.of(LABEL_PROJECT_ID, projectId)).exec();
}
public List<Container> findContainersByServiceId(String serviceId) {
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withLabelFilter(Map.of(LABEL_SWARM_SERVICE_ID, serviceId))) {
- return cmd.exec();
- }
+ return getDockerClient().listContainersCmd().withLabelFilter(Map.of(LABEL_SWARM_SERVICE_ID, serviceId)).exec();
}
public List<Container> findContainers(String containerName) {
var isSwarm = isInSwarmMode();
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(containerName))) {
- var list = cmd.exec();
- return list.stream().filter(c -> {
- var contName = c.getNames()[0].replace("/", "");
- if (Objects.equals(contName, containerName)) {
- return true;
- } else if (isSwarm) {
- var stack = c.getLabels().get(LABEL_DOCKER_STACK_NAMESPACE);
- var fullName = stack + "_" + containerName;
- return contName.startsWith(fullName);
- } else {
- return false;
- }
- }).toList();
- }
+ var list = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(containerName)).exec();
+ return list.stream().filter(c -> {
+ var contName = c.getNames()[0].replace("/", "");
+ if (Objects.equals(contName, containerName)) return true;
+ if (isSwarm) {
+ var stack = c.getLabels().get(LABEL_DOCKER_STACK_NAMESPACE);
+ return contName.startsWith(stack + "_" + containerName);
+ }
+ return false;
+ }).toList();
}
public List<Service> findServices(String serviceName) {
- try (ListServicesCmd cmd = getDockerClient().listServicesCmd().withNameFilter(List.of(serviceName))) {
- var list = cmd.exec();
- return list.stream().filter(c -> c.getId() != null && c.getId().startsWith(serviceName)).toList();
- }
+ var list = getDockerClient().listServicesCmd().withNameFilter(List.of(serviceName)).exec();
+ return list.stream().filter(c -> c.getId() != null && c.getId().startsWith(serviceName)).toList();
}
public List<Service> findServicesByProjectId(String projectId) {
- try (ListServicesCmd cmd = getDockerClient().listServicesCmd().withLabelFilter(Map.of(LABEL_INTEGRATION_NAME, projectId))) {
- return cmd.exec();
- }
+ return getDockerClient().listServicesCmd().withLabelFilter(Map.of(LABEL_PROJECT_ID, projectId)).exec();
}
public Container createContainer(String name, String image, List<String> env, Map<Integer, Integer> ports,
@@ -283,98 +254,39 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
List<DockerVolumeDefinition> volumes, String network, RestartPolicy restartPolicy,
PULL_IMAGE pullImage, String cpus, String cpu_percent, String mem_limit, String mem_reservation,
String dockerCommand) throws InterruptedException {
- List<Container> containers = findContainers(name);
- if (containers.isEmpty()) {
- if (Objects.equals(labels.get(LABEL_TYPE), ContainerType.devmode.name())
- || Objects.equals(labels.get(LABEL_TYPE), ContainerType.build.name())
- || Objects.equals(labels.get(LABEL_TYPE), ContainerType.devservice.name())) {
- LOGGER.info("Pulling DevMode image from DockerHub: " + image);
- pullImageFromDockerHub(image, Objects.equals(pullImage, PULL_IMAGE.always));
- }
- if (Objects.equals(labels.get(LABEL_TYPE), ContainerType.packaged.name())) {
- LOGGER.info("Pulling Project image from Registry: " + image);
- pullImage(image, Objects.equals(pullImage, PULL_IMAGE.always));
- }
- Ports portBindings = DockerUtils.getPortBindings(ports);
- List<ExposedPort> exposePorts = DockerUtils.getExposedPorts(ports);
- try (CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image)
- .withName(name).withLabels(labels).withEnv(env).withHostName(name).withExposedPorts(exposePorts).withHealthcheck(healthCheck)) {
-
- List<Mount> mounts = new ArrayList<>();
- if (volumes != null && !volumes.isEmpty()) {
- volumes.forEach(volume -> {
- var mount = new Mount().withType(MountType.valueOf(volume.getType().toUpperCase())).withTarget(volume.getTarget());
- if (volume.getSource() != null) {
- mount = mount.withSource(volume.getSource());
- }
- mounts.add(mount);
- });
- }
- if (dockerCommand != null) {
- createContainerCmd.withCmd("/bin/sh", "-c", dockerCommand);
- }
-// if (Objects.equals(labels.get(LABEL_PROJECT_ID), ContainerType.build.name())) {
-// mounts.add(new Mount().withType(MountType.BIND).withSource("/var/run/docker.sock").withTarget("/var/run/docker.sock"));
-// }
-
- createContainerCmd.withHostConfig(new HostConfig()
- .withRestartPolicy(restartPolicy)
- .withPortBindings(portBindings)
- .withMounts(mounts)
- .withMemory(DockerUtils.parseMemory(mem_limit))
- .withMemoryReservation(DockerUtils.parseMemory(mem_reservation))
- .withCpuPercent(NumberUtils.toLong(cpu_percent))
- .withNanoCPUs(NumberUtils.toLong(cpus))
- .withNetworkMode(network != null ? network : networkName));
-
- CreateContainerResponse response = createContainerCmd.exec();
- LOGGER.info("Container created: " + response.getId());
-
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(Collections.singleton(response.getId()))) {
- return cmd.exec().getFirst();
- }
- }
- } else {
- LOGGER.info("Container already exists: " + containers.getFirst().getId());
- return containers.getFirst();
+ if (Objects.equals(labels.get(LABEL_TYPE), ContainerType.devmode.name()) || Objects.equals(labels.get(LABEL_TYPE), ContainerType.build.name())) {
+ pullImageFromDockerHub(image, Objects.equals(pullImage, PULL_IMAGE.always));
+ } else if (Objects.equals(labels.get(LABEL_TYPE), ContainerType.packaged.name())) {
+ pullImage(image, Objects.equals(pullImage, PULL_IMAGE.always));
}
- }
- public Service createService(String name, ServiceSpec serviceSpec) {
- List<Service> services = findServices(name);
- if (services.isEmpty()) {
- try (CreateServiceCmd createServiceCmd = getDockerClient().createServiceCmd(serviceSpec)) {
- CreateServiceResponse response = createServiceCmd.exec();
- LOGGER.info("Service created: " + response.getId());
-
- try (ListServicesCmd cmd = getDockerClient().listServicesCmd().withIdFilter(List.of(response.getId()))) {
- return cmd.exec().getFirst();
- }
- }
- } else {
- LOGGER.info("Service already exists: " + services.getFirst().getId());
- return services.getFirst();
- }
- }
+ Ports portBindings = DockerUtils.getPortBindings(ports);
+ List<ExposedPort> exposePorts = DockerUtils.getExposedPorts(ports);
- public void runContainer(String name) {
- List<Container> containers = findContainers(name);
- if (containers.size() == 1) {
- runContainer(containers.getFirst());
+ CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image)
+ .withName(name).withLabels(labels).withEnv(env).withHostName(name)
+ .withExposedPorts(exposePorts).withHealthcheck(healthCheck);
+
+ List<Mount> mounts = new ArrayList<>();
+ if (volumes != null) {
+ volumes.forEach(v -> mounts.add(new Mount().withType(MountType.valueOf(v.getType().toUpperCase())).withTarget(v.getTarget()).withSource(v.getSource())));
}
+ if (dockerCommand != null) createContainerCmd.withCmd("/bin/sh", "-c", dockerCommand);
+
+ createContainerCmd.withHostConfig(new HostConfig()
+ .withRestartPolicy(restartPolicy).withPortBindings(portBindings).withMounts(mounts)
+ .withMemory(DockerUtils.parseMemory(mem_limit)).withMemoryReservation(DockerUtils.parseMemory(mem_reservation))
+ .withCpuPercent(NumberUtils.toLong(cpu_percent)).withNanoCPUs(NumberUtils.toLong(cpus))
+ .withNetworkMode(network != null ? network : networkName));
+
+ CreateContainerResponse response = createContainerCmd.exec();
+ return getContainer(response.getId());
}
- public void runContainer(Container container) {
- if (container.getState().equals("paused")) {
- try (UnpauseContainerCmd cmd = getDockerClient().unpauseContainerCmd(container.getId())) {
- cmd.exec();
- }
- } else if (!container.getState().equals("running")) {
- try (StartContainerCmd cmd = getDockerClient().startContainerCmd(container.getId())) {
- cmd.exec();
- }
- }
+ public Service createService(String name, ServiceSpec serviceSpec) {
+ CreateServiceResponse response = getDockerClient().createServiceCmd(serviceSpec).exec();
+ return getDockerClient().listServicesCmd().withIdFilter(List.of(response.getId())).exec().getFirst();
}
public void copyFiles(String containerId, String containerPath, Map<String, String> files, boolean dirChildrenOnly) throws IOException {
@@ -410,22 +322,33 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
}
}
+ public void runContainer(Container container) {
+ if (container != null) {
+ if (container.getState().equals("paused")) {
+ getDockerClient().unpauseContainerCmd(container.getId()).exec();
+ } else if (!container.getState().equals("running")) {
+ getDockerClient().startContainerCmd(container.getId()).exec();
+ }
+ }
+ }
+
+
+ public void runContainer(String name) {
+ Container container = getContainerByName(name);
+ runContainer(container);
+ }
+
public void logContainer(String containerName, DockerLogCallback callback) {
try {
Container container = getContainerByName(containerName);
if (container != null) {
- try (LogContainerCmd cmd = getDockerClient().logContainerCmd(container.getId())
- .withStdOut(true)
- .withStdErr(true)
- .withTimestamps(false)
- .withFollowStream(true)
- .withTail(100)) {
- cmd.exec(callback);
- callback.awaitCompletion();
- }
+ getDockerClient().logContainerCmd(container.getId())
+ .withStdOut(true).withStdErr(true).withFollowStream(true).withTail(100)
+ .exec(callback);
+ callback.awaitCompletion();
}
} catch (Exception e) {
- LOGGER.error(e.getMessage());
+ LOGGER.error("Logging error: " + e.getMessage());
}
}
@@ -434,32 +357,22 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
if (containers.size() == 1) {
Container container = containers.getFirst();
if (container.getState().equals("running")) {
- try (PauseContainerCmd cmd = getDockerClient().pauseContainerCmd(container.getId())) {
- cmd.exec();
- }
+ getDockerClient().pauseContainerCmd(container.getId()).exec();
}
}
}
public void stopContainer(String name) {
- List<Container> containers = findContainers(name);
- if (containers.size() == 1) {
- Container container = containers.getFirst();
- if (container.getState().equals("running") || container.getState().equals("paused")) {
- try (StopContainerCmd cmd = getDockerClient().stopContainerCmd(container.getId()).withTimeout(1)) {
- cmd.exec();
- }
- }
+ Container container = getContainerByName(name);
+ if (container != null && (container.getState().equals("running") || container.getState().equals("paused"))) {
+ getDockerClient().stopContainerCmd(container.getId()).withTimeout(1).exec();
}
}
public void deleteContainer(String name) {
- List<Container> containers = findContainers(name);
- if (containers.size() == 1) {
- Container container = containers.getFirst();
- try (RemoveContainerCmd cmd = getDockerClient().removeContainerCmd(container.getId()).withForce(true)) {
- cmd.exec();
- }
+ Container container = getContainerByName(name);
+ if (container != null) {
+ getDockerClient().removeContainerCmd(container.getId()).withForce(true).exec();
}
}
@@ -467,169 +380,116 @@ public class DockerService implements org.eclipse.microprofile.health.HealthChec
List<Service> services = findServicesByProjectId(projectId);
if (services.size() == 1) {
Service service = services.getFirst();
- try (RemoveServiceCmd cmd = getDockerClient().removeServiceCmd(service.getId())) {
- cmd.exec();
- }
+ getDockerClient().removeServiceCmd(service.getId()).exec();
}
}
public void execCommandInContainer(String containerName, String cmd) throws InterruptedException {
List<Container> containers = findContainers(containerName);
- Quarkus.asyncExit();
if (containers.size() == 1) {
Container container = containers.getFirst();
if (container.getState().equals("running")) {
- try (ExecCreateCmd execCreateCmd = getDockerClient().execCreateCmd(container.getId()).withAttachStdout(true).withAttachStderr(true).withCmd(cmd.split("\\s+"))) {
- var execCreateCmdResponse = execCreateCmd.exec();
- try (ExecStartCmd execStartCmd = getDockerClient().execStartCmd(execCreateCmdResponse.getId())) {
- execStartCmd.exec(new ExecStartResultCallback(System.out, System.err)).awaitCompletion();
- }
-
-
- }
+ var execCreateCmdResponse = getDockerClient().execCreateCmd(container.getId()).withAttachStdout(true).withAttachStderr(true).withCmd(cmd.split("\\s+")).exec();
+ getDockerClient().execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback(System.out, System.err)).awaitCompletion();
}
}
}
+
public void pullImage(String image, boolean pullAlways) throws InterruptedException {
- try (ListImagesCmd cmd = getDockerClient().listImagesCmd().withShowAll(true)) {
- List<Image> images = cmd.exec();
- List<String> tags = images.stream()
- .map(i -> Arrays.stream(i.getRepoTags()).collect(Collectors.toList()))
- .flatMap(Collection::stream)
- .toList();
-
- if (pullAlways || images.stream().noneMatch(i -> tags.contains(image))) {
- var callback = new DockerPullCallback(LOGGER::info);
- try (PullImageCmd pullImageCmd = getDockerClient().pullImageCmd(image)) {
- pullImageCmd.exec(callback);
- callback.awaitCompletion();
- }
- }
+ List<Image> images = getDockerClient().listImagesCmd().withShowAll(true).exec();
+ if (pullAlways || images.stream().noneMatch(i -> Arrays.asList(i.getRepoTags()).contains(image))) {
+ var callback = new DockerPullCallback(LOGGER::info);
+ getDockerClient().pullImageCmd(image).exec(callback);
+ callback.awaitCompletion();
}
}
public void pullImageFromDockerHub(String image, boolean pullAlways) throws InterruptedException {
- try (ListImagesCmd cmd = getDockerClientNotConnectedToRegistry().listImagesCmd().withShowAll(true)) {
- List<Image> images = cmd.exec();
- List<String> tags = images.stream()
- .map(i -> Arrays.stream(i.getRepoTags()).collect(Collectors.toList()))
- .flatMap(Collection::stream)
- .toList();
-
- if (pullAlways || images.stream().noneMatch(i -> tags.contains(image))) {
- var callback = new DockerPullCallback(LOGGER::info);
- try (PullImageCmd pullImageCmd = getDockerClientNotConnectedToRegistry().pullImageCmd(image)) {
- pullImageCmd.exec(callback);
- callback.awaitCompletion();
- }
- }
+ List<Image> images = getDockerClientNotConnectedToRegistry().listImagesCmd().withShowAll(true).exec();
+ if (pullAlways || images.stream().noneMatch(i -> Arrays.asList(i.getRepoTags()).contains(image))) {
+ var callback = new DockerPullCallback(LOGGER::info);
+ getDockerClientNotConnectedToRegistry().pullImageCmd(image).exec(callback);
+ callback.awaitCompletion();
}
}
public void pullImagesForProject(String projectId) throws InterruptedException {
if (!Objects.equals(registry, "registry:5000") && username.isPresent() && password.isPresent()) {
var repository = registry + "/" + group + "/" + projectId;
- try (PullImageCmd cmd = getDockerClient().pullImageCmd(repository)) {
- var callback = new DockerPullCallback(LOGGER::info);
- cmd.exec(callback);
- callback.awaitCompletion().onError(new Throwable("Error pulling images"));
- }
+ var callback = new DockerPullCallback(LOGGER::info);
+ getDockerClient().pullImageCmd(repository).exec(callback);
+ callback.awaitCompletion().onError(new Throwable("Error pulling images"));
}
}
private DockerClientConfig getDockerClientConfig(boolean connectedToRegistry) {
- LOGGER.info("Docker Client Configuring " + (connectedToRegistry ? "( connectedToRegistry)" : ""));
DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder();
- if (connectedToRegistry) {
- LOGGER.info("Docker Client Registry " + registry);
- LOGGER.info("Docker Client Username " + (username.isPresent() ? "is not empty " : "is empty"));
- LOGGER.info("Docker Client Password " + (password.isPresent() ? "is not empty " : "is empty"));
- if (!Objects.equals(registry, "registry:5000") && username.isPresent() && password.isPresent()) {
- builder.withRegistryUrl(registry);
- builder.withRegistryUsername(username.get());
- builder.withRegistryPassword(password.get());
- }
+ if (connectedToRegistry && !Objects.equals(registry, "registry:5000") && username.isPresent() && password.isPresent()) {
+ builder.withRegistryUrl(registry).withRegistryUsername(username.get()).withRegistryPassword(password.get());
}
return builder.build();
}
private DockerHttpClient getDockerHttpClient(DockerClientConfig config) {
- return new ZerodepDockerHttpClient.Builder()
+ return new ApacheDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.sslConfig(config.getSSLConfig())
.maxConnections(100)
+ .connectionTimeout(java.time.Duration.ofSeconds(10))
+ .responseTimeout(java.time.Duration.ofSeconds(45))
.build();
}
- public DockerClient getDockerClient() {
+ public synchronized DockerClient getDockerClient() {
+ try {
+ if (dockerClient != null) {
+ dockerClient.pingCmd().exec();
+ }
+ } catch (Exception e) {
+ LOGGER.error("Primary Docker client dead, resetting connection pool: " + e.getMessage());
+ shutdownClients(); // Close the broken pool
+ }
+
if (dockerClient == null) {
DockerClientConfig config = getDockerClientConfig(true);
- DockerHttpClient httpClient = getDockerHttpClient(config);
- dockerClient = DockerClientImpl.getInstance(config, httpClient);
+ dockerClient = DockerClientImpl.getInstance(config, getDockerHttpClient(config));
}
return dockerClient;
}
- public DockerClient getDockerClientNotConnectedToRegistry() {
+ public synchronized DockerClient getDockerClientNotConnectedToRegistry() {
if (dockerClientConnectedToRegistry == null) {
DockerClientConfig config = getDockerClientConfig(false);
- DockerHttpClient httpClient = getDockerHttpClient(config);
- dockerClientConnectedToRegistry = DockerClientImpl.getInstance(config, httpClient);
+ dockerClientConnectedToRegistry = DockerClientImpl.getInstance(config, getDockerHttpClient(config));
}
return dockerClientConnectedToRegistry;
}
- public int getMaxPortMapped(int port) {
- try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true)) {
- return cmd.exec().stream()
- .map(c -> List.of(c.ports))
- .flatMap(List::stream)
- .filter(p -> Objects.equals(p.getPrivatePort(), port))
- .map(ContainerPort::getPublicPort).filter(Objects::nonNull)
- .mapToInt(Integer::intValue)
- .max().orElse(port);
- }
- }
-
public List<ContainerImage> getImages() {
- try (ListImagesCmd cmd = getDockerClient().listImagesCmd().withShowAll(true)) {
- return cmd.exec().stream()
- .filter(image -> image != null && image.getRepoTags() != null && image.getRepoTags().length > 0)
- .map(image -> new ContainerImage(image.getId(), image.getRepoTags()[0], image.getCreated(), image.getSize()))
- .toList();
- }
+ return getDockerClient().listImagesCmd().withShowAll(true).exec().stream()
+ .filter(i -> i.getRepoTags() != null && i.getRepoTags().length > 0)
+ .map(i -> new ContainerImage(i.getId(), i.getRepoTags()[0], i.getCreated(), i.getSize()))
+ .toList();
}
public void deleteImage(String imageName) {
- try (ListImagesCmd listImagesCmd = getDockerClient().listImagesCmd().withShowAll(true)) {
- Optional<Image> image = listImagesCmd.exec().stream()
- .filter(i -> Arrays.asList(i.getRepoTags()).contains(imageName)).findFirst();
- if (image.isPresent()) {
- try (RemoveImageCmd removeImageCmd = getDockerClient().removeImageCmd(image.get().getId())) {
- removeImageCmd.exec();
- }
- }
+ Optional<Image> image = getDockerClient().listImagesCmd().withShowAll(true).exec().stream()
+ .filter(i -> Arrays.asList(i.getRepoTags()).contains(imageName)).findFirst();
+ if (image.isPresent()) {
+ getDockerClient().removeImageCmd(image.get().getId()).exec();
}
}
public void createConfig(String name, String config) {
- try (CreateConfigCmd cmd = getDockerClient().createConfigCmd()) {
- cmd.withName(name);
- cmd.withData(config.getBytes());
- cmd.exec();
- }
+ getDockerClient().createConfigCmd().withName(name).withData(config.getBytes()).exec();
}
@Override
public HealthCheckResponse call() {
if (!ConfigService.inKubernetes()) {
- if (checkDockerSwarm()) {
- return HealthCheckResponse.named("Docker Swarm Mode").up().build();
- } else if (checkDocker()) {
- return HealthCheckResponse.named("Docker").up().build();
- }
+ return checkDocker() ? HealthCheckResponse.named("Docker").up().build() : HealthCheckResponse.named("Docker").down().build();
}
- return HealthCheckResponse.named("Docker").down().build();
+ return HealthCheckResponse.named("Docker").up().build();
}
-}
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerUtils.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerUtils.java
index 153ea51e..037dc7b3 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerUtils.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerUtils.java
@@ -122,9 +122,7 @@ public class DockerUtils {
List<PodContainerStatus.Command> commands = getContainerCommand(container.getState());
ContainerType type = getContainerType(container.getLabels());
String created = Instant.ofEpochSecond(container.getCreated()).toString();
- String projectId = container.getLabels().containsKey(LABEL_INTEGRATION_NAME)
- ? container.getLabels().get(LABEL_INTEGRATION_NAME)
- : container.getLabels().getOrDefault(LABEL_PROJECT_ID, name);
+ String projectId = container.getLabels().getOrDefault(LABEL_PROJECT_ID, name);
String camelRuntime = container.getLabels().getOrDefault(LABEL_CAMEL_RUNTIME, "");
return PodContainerStatus.createWithId(projectId, name, environment, container.getId(), container.getImage(),
ports, type, commands, container.getState(), created, camelRuntime, container.getLabels());
@@ -141,9 +139,7 @@ public class DockerUtils {
List<PodContainerStatus.Command> commands = getContainerCommand(container.getState());
ContainerType type = getContainerType(container.getLabels());
String created = Instant.ofEpochSecond(container.getCreated()).toString();
- String projectId = container.getLabels().containsKey(LABEL_INTEGRATION_NAME)
- ? container.getLabels().get(LABEL_INTEGRATION_NAME)
- : container.getLabels().getOrDefault(LABEL_PROJECT_ID, service.getSpec().getName());
+ String projectId = container.getLabels().getOrDefault(LABEL_PROJECT_ID, service.getSpec().getName());
String camelRuntime = container.getLabels().getOrDefault(LABEL_CAMEL_RUNTIME, "");
return PodContainerStatus.createWithId(projectId, name, environment, container.getId(), container.getImage(),
ports, type, commands, container.getState(), created, camelRuntime, container.getLabels());
@@ -195,8 +191,6 @@ public class DockerUtils {
String type = labels.get(LABEL_TYPE);
if (Objects.equals(type, ContainerType.devmode.name())) {
return ContainerType.devmode;
- } else if (Objects.equals(type, ContainerType.devservice.name())) {
- return ContainerType.devservice;
} else if (Objects.equals(type, ContainerType.packaged.name())) {
return ContainerType.packaged;
} else if (Objects.equals(type, ContainerType.internal.name())) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
index b5934ad6..8e74fbbf 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
@@ -115,7 +115,7 @@ public class KubernetesService {
}
}
- public void runBuildProject(String projectId, String podFragment) {
+ public void runBuildProject(String projectId, String podFragment, Map<String, String> envVars) {
try (KubernetesClient client = kubernetesClient()) {
String containerName = projectId + BUILDER_SUFFIX;
Map<String, String> labels = getLabels(containerName, projectId, ContainerType.build);
@@ -126,7 +126,7 @@ public class KubernetesService {
client.resource(old).delete();
}
boolean hasDockerConfigSecret = hasDockerConfigSecret();
- Pod pod = getBuilderPod(containerName, labels, podFragment, hasDockerConfigSecret);
+ Pod pod = getBuilderPod(containerName, labels, podFragment, hasDockerConfigSecret, envVars);
Pod result = client.resource(pod).create();
LOGGER.info("Created pod " + result.getMetadata().getName());
@@ -140,7 +140,6 @@ public class KubernetesService {
labels.putAll(getPartOfLabels());
labels.put("app.kubernetes.io/name", name);
labels.put(LABEL_PROJECT_ID, projectId);
- labels.put(LABEL_INTEGRATION_NAME, projectId);
if (type != null) {
labels.put(LABEL_TYPE, type.name());
}
@@ -164,7 +163,7 @@ public class KubernetesService {
}
// TODO: Move all possible stuff to pod fragment
- private Pod getBuilderPod(String name, Map<String, String> labels, String configFragment, boolean hasDockerConfigSecret) {
+ private Pod getBuilderPod(String name, Map<String, String> labels, String configFragment, boolean hasDockerConfigSecret, Map<String, String> envVars) {
ObjectMeta meta = new ObjectMetaBuilder()
.withName(name)
.withLabels(labels)
@@ -189,14 +188,15 @@ public class KubernetesService {
Pod pod = Serialization.unmarshal(configFragment, Pod.class);
- pod.getSpec().getContainers().get(0).getEnv().add(new EnvVarBuilder().withName(RUN_IN_BUILD_MODE).withValue("true").build());
+ pod.getSpec().getContainers().getFirst().getEnv().add(new EnvVarBuilder().withName(ENV_VAR_RUN_IN_BUILD_MODE).withValue("true").build());
+ envVars.forEach((key, value) -> pod.getSpec().getContainers().getFirst().getEnv().add(new EnvVarBuilder().withName(key).withValue(value).build()));
Container container = new ContainerBuilder()
.withName(name)
.withImage(devmodeImage)
.withPorts(port)
.withImagePullPolicy(devmodeImagePullPolicy.orElse("IfNotPresent"))
- .withEnv(pod.getSpec().getContainers().get(0).getEnv())
+ .withEnv(pod.getSpec().getContainers().getFirst().getEnv())
.withCommand("/bin/sh", "-c", "/karavan/builder/build.sh")
.withVolumeMounts(volumeMounts)
.build();
@@ -410,7 +410,7 @@ public class KubernetesService {
}
List<VolumeMount> volumeMounts = new ArrayList<>();
try {
- volumeMounts = podSpec.getContainers().get(0).getVolumeMounts();
+ volumeMounts = podSpec.getContainers().getFirst().getVolumeMounts();
} catch (Exception ignored) {}
Map<String, String> containerResources = CodeService.DEFAULT_CONTAINER_RESOURCES;
@@ -430,7 +430,7 @@ public class KubernetesService {
List<EnvVar> environmentVariables = new ArrayList<>();
try {
- environmentVariables = new ArrayList<>(podSpec.getContainers().get(0).getEnv());
+ environmentVariables = new ArrayList<>(podSpec.getContainers().getFirst().getEnv());
} catch (Exception ignored) {}
for (Map.Entry<String, String> entry : envVars.entrySet()) {
@@ -442,7 +442,7 @@ public class KubernetesService {
environmentVariables.add(new EnvVarBuilder().withName(ENV_VAR_VERBOSE_OPTION_NAME).withValue(ENV_VAR_VERBOSE_OPTION_VALUE).build());
}
if (compile) {
- environmentVariables.add(new EnvVarBuilder().withName(RUN_IN_COMPILE_MODE).withValue("true").build());
+ environmentVariables.add(new EnvVarBuilder().withName(ENV_VAR_RUN_IN_COMPILE_MODE).withValue("true").build());
}
Container container = new ContainerBuilder()
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
index b1606bdb..3ec79859 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
@@ -91,7 +91,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
String deployment = pod.getMetadata().getLabels().get("app");
String projectId = deployment != null
? deployment
- : (pod.getMetadata().getLabels().containsKey(LABEL_INTEGRATION_NAME) ? pod.getMetadata().getLabels().get(LABEL_INTEGRATION_NAME) : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID));
+ : (pod.getMetadata().getLabels().get(LABEL_PROJECT_ID));
PodContainerStatus cs = new PodContainerStatus();
cs.setProjectId(projectId);
@@ -107,9 +107,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
public PodContainerStatus getPodStatus(Pod pod) {
String appName = pod.getMetadata().getLabels().get("app");
- String projectId = pod.getMetadata().getLabels().containsKey(LABEL_INTEGRATION_NAME)
- ? pod.getMetadata().getLabels().get(LABEL_INTEGRATION_NAME)
- : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
+ String projectId = pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
String camel = pod.getMetadata().getLabels().get(LABEL_KUBERNETES_RUNTIME);
String runtime = pod.getMetadata().getLabels().get(LABEL_CAMEL_RUNTIME);
String type = pod.getMetadata().getLabels().get(LABEL_TYPE);
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java b/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
index 2cef56bb..6cff2d7c 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
@@ -10,6 +10,7 @@ import org.apache.camel.karavan.cache.KaravanCache;
import org.apache.camel.karavan.model.ActivityCommand;
import org.apache.camel.karavan.model.ActivityContainer;
import org.apache.camel.karavan.model.ActivityProject;
+import org.apache.camel.karavan.model.ActivityUser;
import org.apache.camel.karavan.service.ConfigService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
@@ -37,12 +38,18 @@ public class ActivityListener {
@ConsumeEvent(value = ON_USER_ACTIVITY, ordered = true)
public void onUserActivity(JsonObject json) {
-// LOGGER.info("onUserActivity " + json.encodePrettily());
+ var activityUser = json.mapTo(ActivityUser.class);
+ if (Objects.isNull(activityUser)) {
+ } else if (ActivityUser.ActivityType.WORKING.equals(activityUser.getType())) {
+ karavanCache.saveUserWorking(activityUser);
+ } else {
+ karavanCache.saveUserHeartBeat(activityUser);
+ }
+
}
@ConsumeEvent(value = ON_PROJECT_ACTIVITY, ordered = true)
public void onProjectActivity(JsonObject json) {
-// LOGGER.info("onProjectActivity " + json.encodePrettily());
try {
var ap = json.mapTo(ActivityProject.class);
if (Objects.equals(ap.getCommand(), ActivityCommand.ADD)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/listener/CommitListener.java b/karavan-app/src/main/java/org/apache/camel/karavan/listener/CommitListener.java
index c0b7a3c4..dc9a4747 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/listener/CommitListener.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/listener/CommitListener.java
@@ -17,13 +17,15 @@
package org.apache.camel.karavan.listener;
import io.quarkus.vertx.ConsumeEvent;
-import io.smallrye.mutiny.tuples.Tuple2;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;
+import org.apache.camel.karavan.cache.KaravanCache;
import org.apache.camel.karavan.cache.ProjectFolder;
+import org.apache.camel.karavan.cache.SystemCommit;
+import org.apache.camel.karavan.model.CommitResult;
import org.apache.camel.karavan.service.ProjectService;
import org.jboss.logging.Logger;
@@ -40,6 +42,9 @@ public class CommitListener {
@Inject
ProjectService projectService;
+ @Inject
+ KaravanCache karavanCache;
+
@Inject
EventBus eventBus;
@@ -54,15 +59,17 @@ public class CommitListener {
String authorEmail = event.getString("authorEmail");
List<String> fileNames = event.containsKey("fileNames") ? List.of(event.getString("fileNames").split(",")) : List.of();
try {
- Tuple2<ProjectFolder, List<String>> result = projectService.commitAndPushProject(projectId, message, authorName, authorEmail, fileNames);
+ CommitResult result = projectService.commitAndPushProject(projectId, message, authorName, authorEmail, fileNames);
if (userId != null) {
eventBus.publish(COMMIT_HAPPENED, JsonObject.of(
"userId", userId,
"eventId", eventId,
- "messages", result.getItem2(),
- "project", JsonObject.mapFrom(result.getItem1()))
- );
+ "project", JsonObject.mapFrom(result.projectFolder()),
+ "statuses", result.statuses(),
+ "messages", result.messages()
+ ));
}
+ afterCommitHappened(result.commitId(), authorName, authorEmail, result.commitTime(), message, List.of(projectId));
} catch (Exception e) {
var error = e.getCause() != null ? e.getCause() : e;
LOGGER.error("Failed to commit event", error);
@@ -76,4 +83,9 @@ public class CommitListener {
}
}
}
+
+ public void afterCommitHappened(String id, String authorName, String authorEmail, Long commitTime, String message, List<String> projects) throws Exception {
+ karavanCache.saveSystemCommit(new SystemCommit(id, authorName, authorEmail, commitTime, message, projects));
+ }
+
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/listener/NotificationListener.java b/karavan-app/src/main/java/org/apache/camel/karavan/listener/NotificationListener.java
index 2a4f9c0c..5d3ba97c 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/listener/NotificationListener.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/listener/NotificationListener.java
@@ -82,7 +82,9 @@ public class NotificationListener {
public void onCommitHappened(JsonObject event) throws Exception {
JsonObject project = event.getJsonObject("project");
JsonArray messages = event.getJsonArray("messages");
+ JsonArray statuses = event.getJsonArray("statuses");
project.put("messages", messages);
+ project.put("statuses", statuses);
String eventId = event.getString("eventId");
String userId = event.getString("userId");
if (userId != null) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/ActivityUser.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/ActivityUser.java
index b834b8ff..182c262a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/ActivityUser.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/ActivityUser.java
@@ -4,19 +4,32 @@ import java.time.Instant;
public class ActivityUser {
+ public enum ActivityType{
+ HEARTBEAT, WORKING
+ }
+
private String userName;
- private Instant timeStamp;
+ private ActivityType type;
+ private Long timeStamp;
public ActivityUser() {
}
public ActivityUser(String userName) {
this.userName = userName;
- this.timeStamp = Instant.now();
+ this.type = ActivityType.HEARTBEAT;
+ this.timeStamp = Instant.now().getEpochSecond() * 1000L;
+ }
+
+ public ActivityUser(String userName, ActivityType type) {
+ this.userName = userName;
+ this.type = type;
+ this.timeStamp = Instant.now().getEpochSecond() * 1000L;
}
- public ActivityUser(String userName, Instant timeStamp) {
+ public ActivityUser(String userName, ActivityType type, Long timeStamp) {
this.userName = userName;
+ this.type = type;
this.timeStamp = timeStamp;
}
@@ -28,11 +41,19 @@ public class ActivityUser {
this.userName = userName;
}
- public Instant getTimeStamp() {
+ public ActivityType getType() {
+ return type;
+ }
+
+ public void setType(ActivityType type) {
+ this.type = type;
+ }
+
+ public Long getTimeStamp() {
return timeStamp;
}
- public void setTimeStamp(Instant timeStamp) {
+ public void setTimeStamp(Long timeStamp) {
this.timeStamp = timeStamp;
}
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/CamelStatusScheduler.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/CamelStatusScheduler.java
index 3d0d9758..351f1e90 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/CamelStatusScheduler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/CamelStatusScheduler.java
@@ -50,7 +50,7 @@ public class CamelStatusScheduler {
@Inject
EventBus eventBus;
- @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP, skipExecutionIf = KaravanSkipPredicate.class)
+ @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
public void collectCamelStatuses() {
LOGGER.debug("Collect Camel Statuses");
if (ConfigService.inKubernetes()) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java
index 086bac2d..88dc8b1e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java
@@ -28,6 +28,7 @@ import org.apache.camel.karavan.docker.DockerService;
import org.apache.camel.karavan.docker.DockerUtils;
import org.apache.camel.karavan.service.ConfigService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jboss.logging.Logger;
import java.util.ArrayList;
import java.util.List;
@@ -37,6 +38,8 @@ import static org.apache.camel.karavan.KaravanEvents.*;
@ApplicationScoped
public class DockerStatusScheduler {
+ private static final Logger LOGGER = Logger.getLogger(DockerStatusScheduler.class.getName());
+
@ConfigProperty(name = "karavan.environment", defaultValue = KaravanConstants.DEV)
String environment;
@@ -49,7 +52,7 @@ public class DockerStatusScheduler {
@Inject
EventBus eventBus;
- @Scheduled(every = "{karavan.container.statistics.interval:off}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP, skipExecutionIf = KaravanSkipPredicate.class)
+ @Scheduled(every = "{karavan.container.statistics.interval:off}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectContainersStatistics() {
if (!ConfigService.inKubernetes()) {
if (configService.inDockerSwarmMode()) {
@@ -67,20 +70,13 @@ public class DockerStatusScheduler {
}
}
- @Scheduled(every = "{karavan.container.status.interval:off}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP, skipExecutionIf = KaravanSkipPredicate.class)
+ @Scheduled(every = "{karavan.container.status.interval:off}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectContainersStatuses() {
if (!ConfigService.inKubernetes()) {
- if (configService.inDockerSwarmMode()) {
- List<PodContainerStatus> statusesInDocker = getServicesStatuses();
- statusesInDocker.forEach(containerStatus -> {
- eventBus.publish(POD_CONTAINER_UPDATED, JsonObject.mapFrom(containerStatus));
- });
- } else {
- List<PodContainerStatus> statusesInDocker = getContainersStatuses();
- statusesInDocker.forEach(containerStatus -> {
- eventBus.publish(POD_CONTAINER_UPDATED, JsonObject.mapFrom(containerStatus));
- });
- }
+ List<PodContainerStatus> statusesInDocker = getContainersStatuses();
+ statusesInDocker.forEach(containerStatus -> {
+ eventBus.publish(POD_CONTAINER_UPDATED, JsonObject.mapFrom(containerStatus));
+ });
eventBus.publish(CMD_CLEAN_STATUSES, "");
}
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/KaravanSkipPredicate.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/KaravanSkipPredicate.java
deleted file mode 100644
index 7778a1e0..00000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/KaravanSkipPredicate.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.apache.camel.karavan.scheduler;
-
-import io.quarkus.scheduler.Scheduled;
-import io.quarkus.scheduler.ScheduledExecution;
-import io.quarkus.vertx.ConsumeEvent;
-import jakarta.inject.Singleton;
-
-import static org.apache.camel.karavan.KaravanEvents.NOTIFICATION_PROJECTS_STARTED;
-
-
-@Singleton
-public class KaravanSkipPredicate implements Scheduled.SkipPredicate {
-
- private static boolean skip = true;
-
- @ConsumeEvent(value = NOTIFICATION_PROJECTS_STARTED)
- void getInfinispanNotificationStarted(String message) {
- skip = false;
- }
-
- @Override
- public boolean test(ScheduledExecution execution) {
- return skip;
- }
-}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
index 0a97ec30..49c7e305 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java
@@ -4,18 +4,14 @@ import com.google.common.base.Objects;
import io.quarkus.elytron.security.common.BcryptUtil;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
-import org.apache.camel.karavan.cache.AccessPassword;
-import org.apache.camel.karavan.cache.AccessRole;
-import org.apache.camel.karavan.cache.AccessUser;
-import org.apache.camel.karavan.cache.KaravanCache;
+import org.apache.camel.karavan.cache.*;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
+import java.security.SecureRandom;
import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
import java.util.stream.Collectors;
@Singleton
@@ -28,9 +24,13 @@ public class AuthService {
@ConfigProperty(name = "platform.password", defaultValue = "Pl@tf0rm")
String password;
+ static final SecureRandom RNG = new SecureRandom();
+ public static final int SESSION_MAX_AGE = 12 * 60 * 60;
+
public static final String ROLE_ADMIN = "platform-admin";
public static final String ROLE_DEVELOPER = "platform-developer";
public static final String ROLE_USER = "platform-user";
+ public static final String ROLE_SYSTEM_BUILDER = "platform-system-builder";
public static final String USER_ADMIN = "admin";
public static final String USER_DEVELOPER = "developer";
@@ -50,7 +50,7 @@ public class AuthService {
LOGGER.info("Creating default roles...");
for (String name : getAllRoles()) {
if (karavanCache.getRole(name) == null) {
- karavanCache.saveRole(new AccessRole(name, Arrays.stream(name.split("-")).map(this::capitalize).collect(Collectors.joining(" "))));
+ karavanCache.saveRole(new AccessRole(name, Arrays.stream(name.split("-")).map(this::capitalize).collect(Collectors.joining(" "))), true);
}
}
LOGGER.info("Creating default users...");
@@ -62,9 +62,9 @@ public class AuthService {
var currentUser = karavanCache.getUser(username);
if (currentUser == null) {
currentUser = new AccessUser(username, capitalize(username), capitalize(username), username + DEFAULT_EMAIL_SUFFIX, AccessUser.UserStatus.ACTIVE, roles);
- karavanCache.saveUser(currentUser);
+ karavanCache.saveUser(currentUser, true);
var pwdHash = BcryptUtil.bcryptHash(password, COST);
- karavanCache.savePassword(new AccessPassword(username, pwdHash));
+ karavanCache.savePassword(new AccessPassword(username, pwdHash), true);
} else {
LOGGER.info("User " + username + " already exists");
}
@@ -88,12 +88,12 @@ public class AuthService {
message = "Incorrect Username and/or Password!";
}
if (message != null) {
- karavanCache.savePassword(pwd);
+ karavanCache.savePassword(pwd, true);
throw new RuntimeException(message);
}
pwd.setLastLogin(System.currentTimeMillis());
pwd.setFailedAttempts(0);
- karavanCache.savePassword(pwd);
+ karavanCache.savePassword(pwd, true);
return user;
} else {
throw new RuntimeException("Incorrect Username and/or Password!");
@@ -117,7 +117,27 @@ public class AuthService {
pwd.setLockedUntil(0);
pwd.setPwdHash(BcryptUtil.bcryptHash(password, COST));
- karavanCache.savePassword(pwd);
+ karavanCache.savePassword(pwd, true);
+ }
+
+
+ public AccessSession createSession(String username) throws Exception {
+ String sessionId = random(32);
+ String csrf = random(16);
+ var createdAt = Instant.now();
+ return new AccessSession(sessionId, username, csrf, createdAt.toEpochMilli(), Instant.now().plus(SESSION_MAX_AGE, ChronoUnit.SECONDS));
+ }
+
+ public AccessSession createAndSaveSession(String username, boolean persist) throws Exception {
+ var session = createSession(username);
+ karavanCache.saveAccessSession(session, persist);
+ return session;
+ }
+
+ public String random(int bytes) {
+ byte[] b = new byte[bytes];
+ RNG.nextBytes(b);
+ return Base64.getUrlEncoder().withoutPadding().encodeToString(b);
}
private String capitalize(String s) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
index e478c880..2bc9c474 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/CodeService.java
@@ -29,8 +29,7 @@ import org.apache.camel.karavan.cache.ProjectFile;
import org.apache.camel.karavan.cache.ProjectFolder;
import org.apache.camel.karavan.docker.DockerComposeConverter;
import org.apache.camel.karavan.model.DockerComposeService;
-import org.apache.camel.karavan.model.GitRepo;
-import org.apache.camel.karavan.model.GitRepoFile;
+import org.apache.camel.karavan.model.PathCommitDetails;
import org.apache.commons.text.StringSubstitutor;
import org.apache.commons.text.lookup.StringLookup;
import org.eclipse.microprofile.config.ConfigProvider;
@@ -57,9 +56,7 @@ public class CodeService {
private static final Logger LOGGER = Logger.getLogger(CodeService.class.getName());
public static final String APPLICATION_PROPERTIES_FILENAME = "application.properties";
- public static final String BEAN_TEMPLATE_SUFFIX_FILENAME = "-bean-template.camel.yaml";
public static final String PROJECT_COMPOSE_FILENAME = "docker-compose.yaml";
- public static final String DEV_SERVICES_FILENAME = "docker-compose.yaml";
public static final String PROJECT_STACK_FILENAME = "docker-stack.yaml";
public static final String MARKDOWN_EXTENSION = ".md";
public static final String PROJECT_JKUBE_EXTENSION = ".jkube.yaml";
@@ -187,7 +184,7 @@ public class CodeService {
"projectName", projectFolder.getName(),
"packageSuffix", CodeService.getGavPackageSuffix(projectFolder.getProjectId())
));
- return new ProjectFile(APPLICATION_PROPERTIES_FILENAME, code, projectFolder.getProjectId(), Instant.now().toEpochMilli());
+ return new ProjectFile(APPLICATION_PROPERTIES_FILENAME, code, projectFolder.getProjectId(), Instant.now().getEpochSecond() * 1000L);
}
public String saveProjectFilesInTemp(Map<String, String> files) {
@@ -240,10 +237,12 @@ public class CodeService {
var path = "/" + projectId + (ConfigService.inKubernetes() ? KUBERNETES_FOLDER : DOCKER_FOLDER);
listResources(path).forEach(filename -> {
- String templatePath = path + filename;
- String templateText = getResourceFile(templatePath);
- if (templateText != null) {
- result.put(filename, templateText);
+ if (!filename.startsWith(".")) {
+ String templatePath = path + filename;
+ String templateText = getResourceFile(templatePath);
+ if (templateText != null) {
+ result.put(filename, templateText);
+ }
}
});
return result;
@@ -289,11 +288,11 @@ public class CodeService {
return mapper.convertValue(map, ObjectNode.class);
}
- public String getPropertiesFile(GitRepo repo) {
+ public String getPropertiesFile(List<PathCommitDetails> folderFiles) {
try {
- for (GitRepoFile e : repo.getFiles()){
- if (e.getName().equalsIgnoreCase(APPLICATION_PROPERTIES_FILENAME)) {
- return e.getBody();
+ for (PathCommitDetails e : folderFiles){
+ if (e.fileName().equalsIgnoreCase(APPLICATION_PROPERTIES_FILENAME)) {
+ return e.content();
}
}
} catch (Exception e) {
@@ -354,7 +353,7 @@ public class CodeService {
"projectPort", String.valueOf(nextAvailablePort),
"projectImage", projectFolder.getProjectId()
));
- return new ProjectFile(PROJECT_COMPOSE_FILENAME, code, projectFolder.getProjectId(), Instant.now().toEpochMilli());
+ return new ProjectFile(PROJECT_COMPOSE_FILENAME, code, projectFolder.getProjectId(), Instant.now().getEpochSecond() * 1000L);
}
public ProjectFile createInitialProjectStack(ProjectFolder projectFolder, int nextAvailablePort) {
@@ -364,12 +363,12 @@ public class CodeService {
"projectPort", String.valueOf(nextAvailablePort),
"projectImage", projectFolder.getProjectId()
));
- return new ProjectFile(PROJECT_STACK_FILENAME, code, projectFolder.getProjectId(), Instant.now().toEpochMilli());
+ return new ProjectFile(PROJECT_STACK_FILENAME, code, projectFolder.getProjectId(), Instant.now().getEpochSecond() * 1000L);
}
public ProjectFile createInitialDeployment(ProjectFolder projectFolder) {
String template = getTemplateText(PROJECT_DEPLOYMENT_JKUBE_FILENAME);
- return new ProjectFile(PROJECT_DEPLOYMENT_JKUBE_FILENAME, template, projectFolder.getProjectId(), Instant.now().toEpochMilli());
+ return new ProjectFile(PROJECT_DEPLOYMENT_JKUBE_FILENAME, template, projectFolder.getProjectId(), Instant.now().getEpochSecond() * 1000L);
}
public Integer getProjectPort(ProjectFile composeFile) {
@@ -418,7 +417,8 @@ public class CodeService {
service.setImage(imageName);
String code = DockerComposeConverter.toCode(service);
compose.setCode(code);
- karavanCache.saveProjectFile(compose, false);
+ compose.setLastUpdate(Instant.now().getEpochSecond() * 1000L);
+ karavanCache.saveProjectFile(compose, null, true);
}
}
@@ -469,27 +469,29 @@ public class CodeService {
public List<String> listResources(String resourceFolder) {
List<String> result = new ArrayList<>();
try {
- URI uri = Objects.requireNonNull(ConfigService.class.getResource(resourceFolder)).toURI();
- Path myPath;
- FileSystem fileSystem = null;
- if (uri.getScheme().equals("jar")) {
- fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
- myPath = fileSystem.getPath(resourceFolder);
- } else {
- myPath = Paths.get(uri);
- }
+ if (ConfigService.class.getResource(resourceFolder) != null) {
+ URI uri = ConfigService.class.getResource(resourceFolder).toURI();
+ Path myPath;
+ FileSystem fileSystem = null;
+ if (uri.getScheme().equals("jar")) {
+ fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
+ myPath = fileSystem.getPath(resourceFolder);
+ } else {
+ myPath = Paths.get(uri);
+ }
- try (var pathsStream = Files.walk(myPath, 10)) {
- pathsStream
- .filter(Files::isRegularFile)
- .map(path -> path.getFileName().toString())
- .forEach(result::add);
- } catch (IOException e) {
- var error = e.getCause() != null ? e.getCause() : e;
- LOGGER.error("IOException", error);
- }
- if (fileSystem != null) {
- fileSystem.close();
+ try (var pathsStream = Files.walk(myPath, 10)) {
+ pathsStream
+ .filter(Files::isRegularFile)
+ .map(path -> path.getFileName().toString())
+ .forEach(result::add);
+ } catch (IOException e) {
+ var error = e.getCause() != null ? e.getCause() : e;
+ LOGGER.error("IOException", error);
+ }
+ if (fileSystem != null) {
+ fileSystem.close();
+ }
}
} catch (URISyntaxException | IOException e) {
var error = e.getCause() != null ? e.getCause() : e;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/ComplexityService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/ComplexityService.java
index e07704d8..62bd2b72 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/ComplexityService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/ComplexityService.java
@@ -80,13 +80,22 @@ public class ComplexityService {
public List<ComplexityProject> getProjectComplexities() {
return karavanCache.getFolders().stream()
- .filter(p -> Objects.equals(p.getType(), ProjectFolder.Type.integration))
- .map(project -> getProjectComplexity(project.getProjectId())).toList();
+ .filter(p -> Objects.equals(p.getType(), ProjectFolder.Type.integration)
+ || Objects.equals(p.getType(), ProjectFolder.Type.templates)
+ || Objects.equals(p.getType(), ProjectFolder.Type.contracts))
+ .map(this::getProjectComplexity).toList();
}
public ComplexityProject getProjectComplexity(String projectId) {
+ var project = karavanCache.getProject(projectId);
+ return getProjectComplexity(project);
+ }
+
+ public ComplexityProject getProjectComplexity(ProjectFolder project) {
+ var projectId = project.getProjectId();
ComplexityProject complexityProject = new ComplexityProject();
complexityProject.setProjectId(projectId);
+ complexityProject.setType(project.getType().name());
try {
complexityProject.setLastUpdateDate(karavanCache.getProjectFiles(projectId).stream().mapToLong(ProjectFile::getLastUpdate).max().orElse(0));
List<ProjectFile> files = karavanCache.getProjectFiles(projectId);
@@ -99,6 +108,7 @@ public class ComplexityService {
if (file.getName().endsWith(CAMEL_YAML_EXTENSION)) {
complexityFile.setType(ComplexityFile.Type.camel);
+ complexityFile.setGenerated(file.getName().startsWith("_gen_"));
complexityFile.setBeans(getFileBeandCount(file.getCode()));
complexityFile.setRests(getFileRestCount(file.getCode()));
List<ComplexityRoute> routes1 = getRoutes(file.getCode(), file.getName());
@@ -119,6 +129,9 @@ public class ComplexityService {
complexityFile.setType(ComplexityFile.Type.kubernetes);
} else if (file.getName().endsWith(".java")) {
complexityFile.setType(ComplexityFile.Type.java);
+ } else if (file.getName().equals("openapi.json")) {
+ complexityFile.setType(ComplexityFile.Type.openapi);
+ complexityProject.setExposesOpenApi(true);
} else {
complexityFile.setType(ComplexityFile.Type.other);
}
@@ -334,6 +347,9 @@ public class ComplexityService {
var rt = element.getJsonObject("routeTemplate");
var r = rt.getJsonObject("route");
result.add(getRouteComplexity(r, fileName));
+ } else if (element.containsKey("templatedRoute")) {
+ var tr = element.getJsonObject("templatedRoute");
+ result.add(getTemplatedRouteComplexity(tr, fileName));
}
}
}
@@ -373,6 +389,20 @@ public class ComplexityService {
return complexity;
}
+ private ComplexityRoute getTemplatedRouteComplexity(JsonObject templatedRoute, String fileName) {
+ ComplexityRoute complexity = new ComplexityRoute();
+ complexity.setFileName(fileName);
+ try {
+ complexity.setRouteId(templatedRoute.getString("routeId"));
+ complexity.setRouteTemplateRef(templatedRoute.getString("routeTemplateRef"));
+ complexity.setTemplated(true);
+ complexity.setNodePrefixId(templatedRoute.getString("prefixId"));
+ } catch (Exception e) {
+ LOGGER.error(e);
+ }
+ return complexity;
+ }
+
private ComplexityRoute getStepsComplexity(ComplexityRoute complexity, JsonArray steps) {
try {
for (Object stepObject : steps) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
index e9d7ea2e..b035f915 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
@@ -20,23 +20,20 @@ import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import io.smallrye.mutiny.tuples.Tuple2;
+import io.smallrye.mutiny.tuples.Tuple3;
import io.vertx.core.Vertx;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.camel.karavan.cache.ProjectFile;
-import org.apache.camel.karavan.cache.ProjectFileCommitDiff;
import org.apache.camel.karavan.cache.ProjectFolder;
-import org.apache.camel.karavan.cache.ProjectFolderCommit;
import org.apache.camel.karavan.model.GitConfig;
-import org.apache.camel.karavan.model.GitRepo;
-import org.apache.camel.karavan.model.GitRepoFile;
+import org.apache.camel.karavan.model.PathCommitDetails;
import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.diff.DiffEntry;
-import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
@@ -44,15 +41,12 @@ import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.*;
import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
-import org.eclipse.jgit.treewalk.AbstractTreeIterator;
-import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.FS;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
@@ -62,7 +56,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;
-import java.util.stream.StreamSupport;
@ApplicationScoped
public class GitService {
@@ -130,7 +123,7 @@ public class GitService {
return new GitConfig(repository, username.orElse(null), password.orElse(null), branch, privateKeyPath.orElse(null));
}
- public Tuple2<RevCommit, List<String>> commitAndPushProject(ProjectFolder projectFolder, List<ProjectFile> files, String message, String authorName, String authorEmail, List<String> fileNames) throws GitAPIException, IOException, URISyntaxException {
+ public Tuple3<RevCommit, List<RemoteRefUpdate.Status>, List<String>> commitAndPushProject(ProjectFolder projectFolder, List<ProjectFile> files, String message, String authorName, String authorEmail, List<String> fileNames) throws GitAPIException, IOException, URISyntaxException {
LOGGER.info("Commit and push project " + projectFolder.getProjectId());
GitConfig gitConfig = getGitConfig();
String uuid = UUID.randomUUID().toString();
@@ -151,7 +144,7 @@ public class GitService {
return commitAddedAndPush(git, gitConfig.getBranch(), message, authorName, authorEmail, fileNames, projectFolder.getProjectId());
}
- public List<GitRepo> readProjectsToImport() {
+ public List<PathCommitDetails> readProjectsToImport() {
Git importGit = getGitForImport();
if (importGit != null) {
return readProjectsFromRepository(importGit, new String[0]);
@@ -159,36 +152,77 @@ public class GitService {
return new ArrayList<>(0);
}
- public GitRepo readProjectFromRepository(String projectId) throws GitAPIException, IOException, URISyntaxException {
+ public List<PathCommitDetails> readProjectFromRepository(String projectId) throws GitAPIException, IOException, URISyntaxException {
Git git = getGit(true, vertx.fileSystem().createTempDirectoryBlocking(UUID.randomUUID().toString()));
- return readProjectsFromRepository(git, projectId).get(0);
+ return readProjectsFromRepository(git, projectId).stream().filter(d -> Objects.equals(d.projectId(), projectId)).toList();
}
- public List<GitRepo> readAllProjectsFromRepository() throws GitAPIException, IOException, URISyntaxException {
+ public List<PathCommitDetails> readAllProjectsFromRepository() throws GitAPIException, IOException, URISyntaxException {
Git git = getGit(true, vertx.fileSystem().createTempDirectoryBlocking(UUID.randomUUID().toString()));
return readProjectsFromRepository(git);
}
- private List<GitRepo> readProjectsFromRepository(Git git, String... filter) {
- LOGGER.info("Read projects...");
- List<GitRepo> result = new ArrayList<>();
- try {
- String folder = git.getRepository().getDirectory().getAbsolutePath().replace("/.git", "");
- List<String> projects = readProjectsFromFolder(folder, filter);
- for (String project : projects) {
- Map<String, String> filesRead = readProjectFilesFromFolder(folder, project);
- List<GitRepoFile> files = new ArrayList<>(filesRead.size());
- for (Map.Entry<String, String> entry : filesRead.entrySet()) {
- String name = entry.getKey();
- String body = entry.getValue();
- Tuple2<String, Integer> fileCommit = lastCommit(git, project + File.separator + name);
- files.add(new GitRepoFile(name, fileCommit.getItem2().longValue() * 1000, body));
+ public List<PathCommitDetails> getLastCommitForEachFile(Git git) throws IOException, GitAPIException {
+ List<PathCommitDetails> pathCommitDetails = new ArrayList<>();
+ Repository repository = git.getRepository();
+
+ // 1. Resolve the HEAD commit (the current state of the branch)
+ ObjectId head = repository.resolve(Constants.HEAD);
+ if (head == null) {
+ throw new IllegalStateException("Repository has no HEAD. Is it an empty repository?");
+ }
+
+ try (RevWalk revWalk = new RevWalk(repository)) {
+ RevCommit headCommit = revWalk.parseCommit(head);
+ RevTree tree = headCommit.getTree();
+
+ // 2. Walk through the tree to find all files
+ try (TreeWalk treeWalk = new TreeWalk(repository)) {
+ treeWalk.addTree(tree);
+ treeWalk.setRecursive(false); // 1. Turn off automatic recursion so we don't skip folder nodes
+
+ // Iterate through every file found in the tree
+ while (treeWalk.next()) {
+ String path = treeWalk.getPathString();
+ // 2. Determine if the current item is a directory (Tree) or file (Blob)
+ boolean isFolder = treeWalk.isSubtree();
+ Iterable<RevCommit> commits = git.log().addPath(path).setMaxCount(1).call();
+
+ if (isFolder) {
+ for (RevCommit commit : commits) {
+ String commitId = commit.getName();
+ Long commitTime = Integer.valueOf(commit.getCommitTime()).longValue() * 1000;
+ pathCommitDetails.add(new PathCommitDetails(path, null, commitId, commitTime, null, true));
+ }
+ treeWalk.enterSubtree();
+ } else {
+ ObjectId blobId = treeWalk.getObjectId(0);
+ ObjectLoader loader = repository.open(blobId);
+ String content = new String(loader.getBytes(), StandardCharsets.UTF_8);
+
+ for (RevCommit commit : commits) {
+ String commitId = commit.getName(); // The SHA-1 hash
+ Long commitTime = Integer.valueOf(commit.getCommitTime()).longValue() * 1000;
+ String[] parts = path.split(Pattern.quote(File.separator));
+ if (parts.length == 2) {
+ var projectId = parts[0];
+ var fileName = parts[1];
+ pathCommitDetails.add(new PathCommitDetails(projectId, fileName, commitId, commitTime, content, false));
+ }
+ }
+ }
}
- Tuple2<String, Integer> commit = lastCommit(git, project);
- GitRepo repo = new GitRepo(project, commit.getItem1(), commit.getItem2().longValue() * 1000, files);
- result.add(repo);
}
- return result;
+ }
+
+ return pathCommitDetails;
+ }
+
+ private List<PathCommitDetails> readProjectsFromRepository(Git git, String... filter) {
+ LOGGER.info("Read projects...");
+ List<PathCommitDetails> result = new ArrayList<>();
+ try {
+ return getLastCommitForEachFile(git);
} catch (RefNotFoundException e) {
LOGGER.error("New repository");
return result;
@@ -294,7 +328,7 @@ public class GitService {
});
}
- public Tuple2<RevCommit, List<String>> commitAddedAndPush(Git git, String branch, String message, String authorName, String authorEmail, List<String> fileNames, String projectId) throws GitAPIException {
+ public Tuple3<RevCommit, List<RemoteRefUpdate.Status>, List<String>> commitAddedAndPush(Git git, String branch, String message, String authorName, String authorEmail, List<String> fileNames, String projectId) throws GitAPIException {
LOGGER.info("Commit and push changes to the branch " + branch);
AddCommand add = git.add();
for (String fileName : fileNames) {
@@ -303,20 +337,28 @@ public class GitService {
LOGGER.info("Git add: " + add.call());
RevCommit commit = git.commit().setMessage(message).setAuthor(new PersonIdent(authorName, authorEmail)).call();
List<String> messages = new ArrayList<>();
+ List<RemoteRefUpdate.Status> statuses = new ArrayList<>();
LOGGER.info("Git commit: " + commit);
if (!ephemeral) {
PushCommand pushCommand = git.push();
pushCommand.add(branch).setRemote("origin");
setCredentials(pushCommand);
- Iterable<PushResult> result = pushCommand.call();
- result.forEach(pushResult -> {
- if (pushResult != null) {
- messages.add(pushResult.getMessages());
- LOGGER.info("Git push result: " + pushResult.getMessages());
+ Iterable<PushResult> results = pushCommand.call();
+ for (PushResult pr : results) {
+ if (pr != null) {
+ LOGGER.info("Git push result: " + pr.getMessages());
+ for (RemoteRefUpdate rru : pr.getRemoteUpdates()) {
+ LOGGER.info("Git push: " + rru.getStatus() + ", " + rru.getMessage());
+ if (RemoteRefUpdate.Status.OK != rru.getStatus()) {
+ statuses.add(rru.getStatus());
+ messages.add(rru.getMessage());
+ }
+ }
+ messages.add(pr.getMessages());
}
- });
+ }
}
- return Tuple2.of(commit, messages);
+ return Tuple3.of(commit, statuses, messages);
}
public Git init(String dir, String uri, String branch) throws GitAPIException, IOException, URISyntaxException {
@@ -501,82 +543,4 @@ public class GitService {
}
return sshSessionFactory;
}
-
- public List<ProjectFolderCommit> getProjectCommits(String projectId) {
- List<ProjectFolderCommit> result = new ArrayList<>();
- try {
- Git pollGit = getGit(true, vertx.fileSystem().createTempDirectoryBlocking("commits"));
- if (pollGit != null) {
- StreamSupport.stream(pollGit.log().all().addPath(projectId).call().spliterator(), false)
- .sorted(Comparator.comparingInt(RevCommit::getCommitTime))
- .forEach(commit -> {
- var diffs = getProjectFileCommitDiffs(pollGit, commit);
- var projectCommit = new ProjectFolderCommit(commit.getId().getName(), projectId,
- commit.getAuthorIdent().getName(), commit.getAuthorIdent().getEmailAddress(),
- commit.getShortMessage(), diffs);
- result.add(projectCommit);
- });
- }
- } catch (Exception e) {
- LOGGER.error("Error", e);
- }
- return result;
- }
-
- private List<ProjectFileCommitDiff> getProjectFileCommitDiffs(Git git, RevCommit commit) {
- List<ProjectFileCommitDiff> result = new ArrayList<>();
- var repository = git.getRepository();
- try {
- try (RevWalk revWalk = new RevWalk(repository)) {
- if (commit.getParentCount() > 0) {
- RevCommit parentCommit = commit.getParent(0);
- revWalk.parseCommit(parentCommit);
-
- AbstractTreeIterator oldTreeIter = prepareTreeParser(repository, parentCommit);
- AbstractTreeIterator newTreeIter = prepareTreeParser(repository, commit);
-
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
- DiffFormatter diffFormatter = new DiffFormatter(baos)) {
- diffFormatter.setRepository(repository);
- List<DiffEntry> diffs = diffFormatter.scan(oldTreeIter, newTreeIter);
-
- for (DiffEntry diff : diffs) {
- diffFormatter.format(diff);
- var fileDiff = new ProjectFileCommitDiff(diff.getChangeType().name(), diff.getNewPath(), diff.getOldPath(), baos.toString(StandardCharsets.UTF_8));
- result.add(fileDiff);
- baos.reset(); // Clear the output stream for the next diff
- }
- }
- } else {
- try (TreeWalk treeWalk = new TreeWalk(repository)) {
- treeWalk.addTree(commit.getTree());
- treeWalk.setRecursive(true);
- while (treeWalk.next()) {
- // Get the object ID for the file (blob)
- ObjectId objectId = treeWalk.getObjectId(0);
- // Load the file content
- ObjectLoader loader = repository.open(objectId);
- byte[] content = loader.getBytes();
- var fileDiff = new ProjectFileCommitDiff(DiffEntry.ChangeType.ADD.name(), treeWalk.getPathString(), DiffEntry.DEV_NULL, new String(content, StandardCharsets.UTF_8));
- result.add(fileDiff);
- }
- }
- }
- }
- } catch (IOException e) {
- LOGGER.error("Error", e);
- }
- return result;
- }
-
- private static AbstractTreeIterator prepareTreeParser(Repository repository, RevCommit commit) throws IOException {
- try (RevWalk walk = new RevWalk(repository)) {
- RevTree tree = walk.parseTree(commit.getTree().getId());
- CanonicalTreeParser treeParser = new CanonicalTreeParser();
- try (ObjectReader reader = repository.newObjectReader()) {
- treeParser.reset(reader, tree.getId());
- }
- return treeParser;
- }
- }
}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index ac018de7..44eebaf9 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -16,7 +16,7 @@
*/
package org.apache.camel.karavan.service;
-import io.smallrye.mutiny.tuples.Tuple2;
+import io.smallrye.mutiny.tuples.Tuple3;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
import jakarta.enterprise.context.ApplicationScoped;
@@ -27,11 +27,13 @@ import org.apache.camel.karavan.docker.DockerComposeConverter;
import org.apache.camel.karavan.docker.DockerForKaravan;
import org.apache.camel.karavan.docker.DockerStackConverter;
import org.apache.camel.karavan.kubernetes.KubernetesService;
+import org.apache.camel.karavan.model.CommitResult;
import org.apache.camel.karavan.model.DockerComposeService;
import org.apache.camel.karavan.model.DockerStackService;
-import org.apache.camel.karavan.model.GitRepo;
+import org.apache.camel.karavan.model.PathCommitDetails;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
@@ -76,26 +78,42 @@ public class ProjectService {
@Inject
EventBus eventBus;
+ @Inject
+ AuthService authService;
+
+ public List<ProjectFolder> getAllProjects(String type) {
+ Map<String, Long> lastUpdates = karavanCache.getLatestUpdatePerProject();
+ return karavanCache.getFolders().stream()
+ .filter(p -> type == null || Objects.equals(p.getType().name(), type))
+ .sorted(Comparator.comparing(ProjectFolder::getProjectId))
+ .map(p -> {
+ Long lastUpdate = lastUpdates.getOrDefault(p.getProjectId(), p.getLastUpdate());
+ return new ProjectFolder(p.getProjectId(), p.getName(), lastUpdate, p.getType());
+ })
+ .collect(Collectors.toList());
+ }
- public Tuple2<ProjectFolder, List<String>> commitAndPushProject(String projectId, String message, List<String> fileNames) throws Exception {
+ public CommitResult commitAndPushProject(String projectId, String message, List<String> fileNames) throws Exception {
return commitAndPushProject(projectId, message, DEFAULT_AUTHOR_NAME, DEFAULT_AUTHOR_EMAIL, fileNames);
}
- public Tuple2<ProjectFolder, List<String>> commitAndPushProject(String projectId, String message, String authorName, String authorEmail, List<String> fileNames) throws Exception {
+ public CommitResult commitAndPushProject(String projectId, String message, String authorName, String authorEmail, List<String> fileNames) throws Exception {
if (Objects.equals(environment, DEV)) {
LOGGER.info("Commit project: " + projectId);
ProjectFolder p = karavanCache.getProject(projectId);
List<ProjectFile> files = karavanCache.getProjectFiles(projectId);
- Tuple2<RevCommit, List<String>> result = gitService.commitAndPushProject(p, files, message, authorName, authorEmail, fileNames);
+ Tuple3<RevCommit, List<RemoteRefUpdate.Status>, List<String>> result = gitService.commitAndPushProject(p, files, message, authorName, authorEmail, fileNames);
var commit = result.getItem1();
- var messages = result.getItem2();
- karavanCache.syncFilesCommited(projectId, fileNames);
- String commitId = commit.getId().getName();
- Long lastUpdate = commit.getCommitTime() * 1000L;
- p.setLastCommit(commitId);
- p.setLastCommitTimestamp(lastUpdate);
- karavanCache.saveProject(p);
- return Tuple2.of(p, messages);
+ var statuses = result.getItem2();
+ var messages = result.getItem3();
+ if (statuses.stream().noneMatch(status -> status != RemoteRefUpdate.Status.OK)) {
+ String commitId = commit.getId().getName();
+ Long lastUpdate = commit.getCommitTime() * 1000L;
+ importProject(projectId);
+ return new CommitResult(p, statuses, messages, commitId, lastUpdate);
+ } else {
+ return new CommitResult(p, statuses, messages, null, null);
+ }
} else {
throw new RuntimeException("Unsupported environment: " + environment);
}
@@ -135,65 +153,67 @@ public class ProjectService {
? tag
: Instant.now().toString().substring(0, 19).replace(":", "-");
var name = projectFolder.getProjectId() + "-builder";
+ var session = authService.createAndSaveSession(name, false);
if (ConfigService.inKubernetes()) {
String podFragment = codeService.getBuilderPodFragment();
podFragment = codeService.substituteVariables(podFragment, Map.of( "projectId", projectFolder.getProjectId(), "tag", tag));
- kubernetesService.runBuildProject(projectFolder.getProjectId(), podFragment);
+ kubernetesService.runBuildProject(projectFolder.getProjectId(), podFragment, Map.of(ENV_VAR_BUILDER_SESSION_ID, session.getSessionId()));
} else if (configService.inDockerSwarmMode()) {
String stackFragment = codeService.getBuilderStackFragment(projectFolder.getProjectId(), tag);
DockerStackService stack = DockerStackConverter.fromCode(stackFragment, name);
+ stack.addEnvironment(ENV_VAR_RUN_IN_BUILD_MODE, "true");
+ stack.addEnvironment(ENV_VAR_BUILDER_SESSION_ID, session.getSessionId());
dockerForKaravan.runBuildProject(projectFolder, stack, tag);
} else {
Map<String, String> sshFiles = codeService.getSshFiles();
String script = codeService.getBuilderScript();
String composeFragment = codeService.getBuilderComposeFragment(projectFolder.getProjectId(), tag);
DockerComposeService compose = DockerComposeConverter.fromCode(composeFragment, name);
+ compose.addEnvironment(ENV_VAR_RUN_IN_BUILD_MODE, "true");
+ compose.addEnvironment(ENV_VAR_BUILDER_SESSION_ID, session.getSessionId());
dockerForKaravan.runBuildProject(projectFolder, script, compose, sshFiles, tag);
}
}
public void importProject(String projectId) throws Exception {
LOGGER.info("Import project from Git " + projectId);
- GitRepo repo = gitService.readProjectFromRepository(projectId);
- importProjectFromRepo(repo);
+ List<PathCommitDetails> pathCommitDetails = gitService.readProjectFromRepository(projectId);
+ importProjectFromRepo(pathCommitDetails);
}
- private void importProjectFromRepo(GitRepo repo) {
- LOGGER.info("Import project from GitRepo " + repo.getName());
+ private void importProjectFromRepo(List<PathCommitDetails> pathCommitDetails) {
try {
- ProjectFolder projectFolder = getProjectFromRepo(repo);
- karavanCache.saveProject(projectFolder);
- repo.getFiles().forEach(repoFile -> {
- ProjectFile file = new ProjectFile(repoFile.getName(), repoFile.getBody(), repo.getName(), repoFile.getLastCommitTimestamp());
- karavanCache.saveProjectFile(file, true);
+ var folderDetails = pathCommitDetails.stream().filter(PathCommitDetails::isFolder).findFirst().orElse(null);
+ var filesDetails = pathCommitDetails.stream().filter(f -> !f.isFolder()).toList();
+ assert folderDetails != null;
+ LOGGER.info("Import project from GitRepo " + folderDetails.projectId());
+ ProjectFolder projectFolder = getProjectFromRepo(folderDetails, pathCommitDetails);
+ ProjectFolderCommited projectFolderCommited = getProjectCommitedFromRepo(folderDetails);
+ karavanCache.saveProject(projectFolder, false);
+ karavanCache.saveProjectCommited(projectFolderCommited);
+ karavanCache.deleteProjectFileCommited(projectFolder.getProjectId());
+ filesDetails.forEach(repoFile -> {
+ ProjectFile file = new ProjectFile(repoFile.fileName(), repoFile.content(), repoFile.projectId(), repoFile.commitTime());
+ karavanCache.saveProjectFile(file, repoFile.commitId(), false);
});
- karavanCache.syncFilesCommited(projectFolder.getProjectId(), karavanCache.getProjectFiles(projectFolder.getProjectId()).stream().map(ProjectFile::getName).collect(Collectors.toList()));
} catch (Exception e) {
LOGGER.error("Error during project import", e);
}
}
- public ProjectFolder getProjectFromRepo(GitRepo repo) {
- String folderName = repo.getName();
- String propertiesFile = codeService.getPropertiesFile(repo);
+ public ProjectFolder getProjectFromRepo(PathCommitDetails folderDetails, List<PathCommitDetails> folderFiles) {
+ String folderName = folderDetails.projectId();
+ String propertiesFile = codeService.getPropertiesFile(folderFiles);
if (propertiesFile != null) {
String projectName = codeService.getProjectName(propertiesFile);
- return new ProjectFolder(folderName, projectName, repo.getCommitId(), repo.getLastCommitTimestamp());
+ return new ProjectFolder(folderName, projectName, folderDetails.commitTime());
} else {
- return new ProjectFolder(folderName, folderName, repo.getCommitId(), repo.getLastCommitTimestamp());
+ return new ProjectFolder(folderName, folderName, folderDetails.commitTime());
}
}
- public String getDockerDevServiceCode() {
- List<ProjectFile> files = karavanCache.getProjectFiles(ProjectFolder.Type.services.name());
- Optional<ProjectFile> file = files.stream().filter(f -> f.getName().equals(DEV_SERVICES_FILENAME)).findFirst();
- return file.orElse(new ProjectFile()).getCode();
- }
-
- public String getKubernetesDevServiceCode(String name) {
- List<ProjectFile> files = karavanCache.getProjectFiles(ProjectFolder.Type.services.name());
- Optional<ProjectFile> file = files.stream().filter(f -> f.getName().equals(name + ".yaml")).findFirst();
- return file.orElse(new ProjectFile()).getCode();
+ public ProjectFolderCommited getProjectCommitedFromRepo(PathCommitDetails folderDetails) {
+ return new ProjectFolderCommited(folderDetails.projectId(), folderDetails.commitId(), folderDetails.commitTime());
}
public DockerComposeService getProjectDockerComposeService(String projectId) {
@@ -239,32 +259,25 @@ public class ProjectService {
}
}
- public List<ProjectFolder> getAllProjects(String type) {
- return karavanCache.getFolders().stream()
- .filter(p -> type == null || Objects.equals(p.getType().name(), type))
- .sorted(Comparator.comparing(ProjectFolder::getProjectId))
- .collect(Collectors.toList());
- }
-
public ProjectFolder create(ProjectFolder projectFolder) throws Exception {
boolean projectIdExists = karavanCache.getProject(projectFolder.getProjectId()) != null;
if (projectIdExists) {
throw new Exception("Project with id " + projectFolder.getProjectId() + " already exists");
} else {
- karavanCache.saveProject(projectFolder);
+ karavanCache.saveProject(projectFolder, true);
ProjectFile appProp = codeService.generateApplicationProperties(projectFolder);
- karavanCache.saveProjectFile(appProp, false);
+ karavanCache.saveProjectFile(appProp, null, true);
if (!ConfigService.inKubernetes()) {
var port = getMaxPortMappedInProjects() + 1;
ProjectFile projectCompose =
configService.inDockerSwarmMode()
? codeService.createInitialProjectStack(projectFolder, port)
: codeService.createInitialProjectCompose(projectFolder, port);
- karavanCache.saveProjectFile(projectCompose, false);
+ karavanCache.saveProjectFile(projectCompose, null, true);
} else {
ProjectFile projectDeployment = codeService.createInitialDeployment(projectFolder);
- karavanCache.saveProjectFile(projectDeployment, false);
+ karavanCache.saveProjectFile(projectDeployment, null, true);
}
}
return projectFolder;
@@ -280,7 +293,7 @@ public class ProjectService {
ProjectFolder sourceProjectFolder = karavanCache.getProject(sourceProjectId);
// Save project
- karavanCache.saveProject(projectFolder);
+ karavanCache.saveProject(projectFolder, true);
// Copy files from the source and make necessary modifications
Map<String, ProjectFile> filesMap = karavanCache.getProjectFiles(sourceProjectId).stream()
@@ -299,7 +312,7 @@ public class ProjectService {
})
);
- karavanCache.saveProjectFiles(filesMap);
+ karavanCache.saveProjectFiles(filesMap, true);
if (!ConfigService.inKubernetes()) {
ProjectFile projectCompose = null;
@@ -313,14 +326,14 @@ public class ProjectService {
service.setPorts(service.getPorts().stream().map(s -> s.endsWith(":" + INTERNAL_PORT) ? newPort + ":" + INTERNAL_PORT : s).collect(Collectors.toList()));
compose.getServices().put(projectFolder.getProjectId(), service);
compose.getServices().remove(sourceProjectId);
- projectCompose = new ProjectFile(PROJECT_COMPOSE_FILENAME, DockerComposeConverter.toCode(compose), projectFolder.getProjectId(), Instant.now().toEpochMilli());
+ projectCompose = new ProjectFile(PROJECT_COMPOSE_FILENAME, DockerComposeConverter.toCode(compose), projectFolder.getProjectId(), Instant.now().getEpochSecond() * 1000L);
} else {
projectCompose = codeService.createInitialProjectCompose(projectFolder, getMaxPortMappedInProjects() + 1);
}
- karavanCache.saveProjectFile(projectCompose, false);
+ karavanCache.saveProjectFile(projectCompose, null, true);
} else {
ProjectFile projectCompose = codeService.createInitialDeployment(projectFolder);
- karavanCache.saveProjectFile(projectCompose, false);
+ karavanCache.saveProjectFile(projectCompose, null, true);
}
return projectFolder;
@@ -346,6 +359,7 @@ public class ProjectService {
List<ProjectFile> files = karavanCache.getProjectFilesByName(PROJECT_COMPOSE_FILENAME).stream()
.filter(f -> !Objects.equals(f.getProjectId(), ProjectFolder.Type.templates.name()))
.filter(f -> !Objects.equals(f.getProjectId(), ProjectFolder.Type.kamelets.name()))
+ .filter(f -> !Objects.equals(f.getProjectId(), ProjectFolder.Type.contracts.name()))
.filter(f -> !Objects.equals(f.getProjectId(), ProjectFolder.Type.configuration.name()))
.toList();
if (!files.isEmpty()) {
@@ -364,33 +378,42 @@ public class ProjectService {
public void importProjects(boolean onlyNew) {
LOGGER.info("Import " +(onlyNew ? "Only New" : "")+ " projects from git: " + gitService.getGitConfig().getUri());
try {
- List<GitRepo> repos = onlyNew ? gitService.readAllProjectsFromRepository() : gitService.readProjectsToImport();
- repos.forEach(repo -> {
+ List<PathCommitDetails> pathCommitDetails = onlyNew ? gitService.readAllProjectsFromRepository() : gitService.readProjectsToImport();
+ List<PathCommitDetails> projectPaths = pathCommitDetails.stream().filter(PathCommitDetails::isFolder).toList();
+ projectPaths.forEach(folderDetails -> {
ProjectFolder projectFolder;
- String folderName = repo.getName();
+ ProjectFolderCommited projectFolderCommited;
+ String folderName = folderDetails.projectId();
+ var folderFiles = pathCommitDetails.stream().filter(d -> !d.isFolder() && Objects.equals(d.projectId(), folderName)).toList();
boolean needImport = !onlyNew || karavanCache.getProject(folderName) == null;
LOGGER.info("Project " + folderName + " " + (needImport ? "is loading!" : "skipped!"));
if (needImport) {
if (folderName.equals(ProjectFolder.Type.templates.name())) {
- projectFolder = new ProjectFolder(ProjectFolder.Type.templates.name(), "Templates", repo.getCommitId(), repo.getLastCommitTimestamp(), ProjectFolder.Type.templates);
+ projectFolder = new ProjectFolder(ProjectFolder.Type.templates.name(), "Templates", folderDetails.commitTime(), ProjectFolder.Type.templates);
} else if (folderName.equals(ProjectFolder.Type.kamelets.name())) {
- projectFolder = new ProjectFolder(ProjectFolder.Type.kamelets.name(), "Custom Kamelets", repo.getCommitId(), repo.getLastCommitTimestamp(), ProjectFolder.Type.kamelets);
+ projectFolder = new ProjectFolder(ProjectFolder.Type.kamelets.name(), "Custom Kamelets", folderDetails.commitTime(), ProjectFolder.Type.kamelets);
} else if (folderName.equals(ProjectFolder.Type.configuration.name())) {
- projectFolder = new ProjectFolder(ProjectFolder.Type.configuration.name(), "Configuration", repo.getCommitId(), repo.getLastCommitTimestamp(), ProjectFolder.Type.configuration);
- } else if (folderName.equals(ProjectFolder.Type.services.name())) {
- projectFolder = new ProjectFolder(ProjectFolder.Type.services.name(), "Dev Services", repo.getCommitId(), repo.getLastCommitTimestamp(), ProjectFolder.Type.services);
+ projectFolder = new ProjectFolder(ProjectFolder.Type.configuration.name(), "Configuration", folderDetails.commitTime(), ProjectFolder.Type.configuration);
} else if (folderName.equals(ProjectFolder.Type.documentation.name())) {
- projectFolder = new ProjectFolder(ProjectFolder.Type.documentation.name(), "Documentation", repo.getCommitId(), repo.getLastCommitTimestamp(), ProjectFolder.Type.documentation);
+ projectFolder = new ProjectFolder(ProjectFolder.Type.documentation.name(), "Documentation", folderDetails.commitTime(), ProjectFolder.Type.documentation);
} else {
- projectFolder = getProjectFromRepo(repo);
+ projectFolder = getProjectFromRepo(folderDetails, folderFiles);
}
- karavanCache.saveProject(projectFolder);
-
- repo.getFiles().forEach(repoFile -> {
- ProjectFile file = new ProjectFile(repoFile.getName(), repoFile.getBody(), folderName, repoFile.getLastCommitTimestamp());
- karavanCache.saveProjectFile(file, true);
+ karavanCache.saveProject(projectFolder, true);
+ projectFolderCommited = new ProjectFolderCommited(projectFolder.getProjectId(), folderDetails.commitId(), folderDetails.commitTime());
+ karavanCache.saveProjectCommited(projectFolderCommited);
+
+
+ folderFiles.forEach(fileDetails -> {
+ var file = new ProjectFile(fileDetails.fileName(), fileDetails.content(), folderName, fileDetails.commitTime());
+ var commitedFile = ProjectFileCommited.fromFile(file, fileDetails.commitId());
+ karavanCache.saveProjectFileCommited(commitedFile);
+ var fileInCache = karavanCache.getProjectFile(file.getProjectId(), file.getName());
+ if (fileInCache == null || fileInCache.getLastUpdate() < file.getLastUpdate()) {
+ karavanCache.saveProjectFile(file, null, false);
+ }
});
}
});
(camel-karavan) 29/33: Fron-end fixes for 4.18.0
Posted by ma...@apache.org.
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 6d7f93af69bdf2cc259afeafa959eecad7067a39
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:54:13 2026 -0500
Fron-end fixes for 4.18.0
---
karavan-app/Dockerfile.dockerignore | 2 +-
.../src/main/resources/application.properties | 4 +-
.../webui/src/karavan-core/api/TopologyUtils.ts | 3 +-
.../src/main/webui/src/karavan-core/contants.ts | 2 +
.../features/diagnostics/camel/CamelStatusRow.tsx | 53 -
.../diagnostics/camel/CamelStatusesTable.tsx | 52 -
.../features/integration/ContainerLogTab.tsx | 69 -
.../features/integration/DesignerSwitch.css | 23 -
.../features/integration/DesignerToggle.tsx | 57 -
.../features/integration/FileSearchToolbarItem.tsx | 53 -
.../features/integration/ImageDownloadToolbar.tsx | 61 -
.../karavan/features/integration/Project.types.ts | 21 -
.../integration/ProjectContainerContextToolbar.tsx | 67 -
.../ProjectContainersContextProvider.tsx | 81 -
.../features/integration/ProjectContext.tsx | 29 -
.../karavan/features/integration/ProjectPage.css | 299 ----
.../karavan/features/integration/ProjectPage.tsx | 110 --
.../features/integration/ProjectPageNavigation.tsx | 144 --
.../karavan/features/integration/ProjectPanel.tsx | 102 --
.../karavan/features/integration/ProjectTitle.tsx | 70 -
.../features/integration/RenameFileModal.tsx | 110 --
.../integration/beans/BeanFilesDropdown.tsx | 78 -
.../features/integration/beans/BeanWizard.tsx | 242 ---
.../features/integration/designer/CodeStore.ts | 14 -
.../features/integration/designer/DesignerStore.ts | 382 ----
.../integration/designer/ErrorBoundaryWrapper.tsx | 35 -
.../integration/designer/KaravanDesigner.css | 41 -
.../integration/designer/KaravanDesigner.tsx | 208 ---
.../designer/KaravanDesignerViewSwitch.tsx | 73 -
.../integration/designer/beans/BeanCard.tsx | 61 -
.../integration/designer/beans/BeansDesigner.tsx | 115 --
.../features/integration/designer/beans/bean.css | 102 --
.../integration/designer/editor/CodeEditor.tsx | 69 -
.../integration/designer/icons/ComponentIcons.tsx | 1833 --------------------
.../integration/designer/icons/EipIcons.tsx | 293 ----
.../integration/designer/icons/KaravanIcons.tsx | 716 --------
.../integration/designer/icons/OtherIcons.tsx | 36 -
.../designer/kamelet/KameletAnnotationsPanel.tsx | 84 -
.../kamelet/KameletDefinitionPropertyCard.tsx | 299 ----
.../designer/kamelet/KameletDefinitionsPanel.tsx | 126 --
.../designer/kamelet/KameletDependenciesCard.tsx | 105 --
.../designer/kamelet/KameletDesigner.tsx | 36 -
.../integration/designer/kamelet/KameletInput.tsx | 139 --
.../designer/kamelet/KameletTypesOutCard.tsx | 105 --
.../integration/designer/kamelet/kamelet.css | 48 -
.../features/integration/designer/karavan.css | 456 -----
.../designer/property/DslProperties.css | 406 -----
.../designer/property/DslProperties.tsx | 268 ---
.../designer/property/MainPropertiesPanel.tsx | 88 -
.../designer/property/PropertiesHeader.tsx | 358 ----
.../integration/designer/property/PropertyStore.ts | 48 -
.../property/expression/ExpressionBottomPanel.tsx | 80 -
.../property/expression/ExpressionContextModel.tsx | 193 ---
.../property/expression/ExpressionEditor.css | 75 -
.../property/expression/ExpressionEditor.tsx | 75 -
.../designer/property/property/BeanProperties.css | 39 -
.../designer/property/property/BeanProperties.tsx | 345 ----
.../property/property/ComponentPropertyField.css | 47 -
.../property/property/ComponentPropertyField.tsx | 512 ------
.../property/ConfigurationSelectorModal.css | 19 -
.../property/ConfigurationSelectorModal.tsx | 366 ----
.../designer/property/property/DataFormatField.tsx | 161 --
.../property/property/DslPropertyField.css | 55 -
.../property/property/DslPropertyField.tsx | 1057 -----------
.../property/property/DslPropertyFieldSelect.tsx | 81 -
.../property/DslPropertyFieldSelectScrollable.tsx | 126 --
.../designer/property/property/ExpressionField.tsx | 182 --
.../property/property/FileReferenceDropdown.css | 48 -
.../property/property/FileReferenceDropdown.tsx | 293 ----
.../property/property/KameletPropertyField.css | 47 -
.../property/property/KameletPropertyField.tsx | 293 ----
.../designer/property/property/ObjectField.tsx | 89 -
.../property/PropertyPlaceholderDropdown.css | 42 -
.../property/PropertyPlaceholderDropdown.tsx | 196 ---
.../designer/property/property/PropertyUtil.tsx | 42 -
.../property/property/VariablesDropdown.css | 37 -
.../property/property/VariablesDropdown.tsx | 301 ----
.../designer/property/usePropertiesHook.tsx | 246 ---
.../integration/designer/rest/RestCard.tsx | 109 --
.../designer/rest/RestConfigurationCard.tsx | 60 -
.../integration/designer/rest/RestDesigner.tsx | 225 ---
.../integration/designer/rest/RestMethodCard.tsx | 68 -
.../designer/rest/RestMethodSelector.tsx | 68 -
.../features/integration/designer/rest/rest.css | 286 ---
.../designer/route/DeleteConfirmation.tsx | 48 -
.../integration/designer/route/DslConnections.css | 124 --
.../integration/designer/route/DslConnections.tsx | 509 ------
.../integration/designer/route/RouteDesigner.css | 164 --
.../integration/designer/route/RouteDesigner.tsx | 195 ---
.../designer/route/element/DslElement.css | 322 ----
.../designer/route/element/DslElement.tsx | 330 ----
.../designer/route/element/DslElementHeader.tsx | 449 -----
.../designer/route/element/DslElementMoveModal.tsx | 89 -
.../route/element/RouteTemplateElement.css | 52 -
.../route/element/RouteTemplateElement.tsx | 106 --
.../designer/route/useResizeObserver.tsx | 40 -
.../designer/route/useRouteDesignerHook.tsx | 381 ----
.../integration/designer/selector/DslCard.tsx | 110 --
.../integration/designer/selector/DslFastCard.tsx | 59 -
.../designer/selector/DslPreferences.tsx | 89 -
.../integration/designer/selector/DslSelector.css | 218 ---
.../integration/designer/selector/DslSelector.tsx | 422 -----
.../designer/utils/CamelDefaultStepProperty.tsx | 38 -
.../integration/designer/utils/CamelUi.tsx | 1064 ------------
.../integration/designer/utils/DslMetaModel.ts | 83 -
.../integration/designer/utils/ElementIcon.css | 40 -
.../integration/designer/utils/ElementIcons.tsx | 118 --
.../integration/designer/utils/EventBus.ts | 121 --
.../designer/utils/InfrastructureAPI.ts | 71 -
.../designer/utils/IntegrationHeader.tsx | 44 -
.../integration/designer/utils/MediaTypes.ts | 1525 ----------------
.../integration/designer/utils/Notification.tsx | 56 -
.../integration/designer/utils/ValidatorUtils.ts | 87 -
.../features/integration/developer/CodeEditor.tsx | 48 -
.../features/integration/developer/DataEditor.css | 39 -
.../integration/developer/DesignerEditor.tsx | 137 --
.../integration/developer/DeveloperEditor.tsx | 54 -
.../integration/developer/DeveloperManager.css | 181 --
.../integration/developer/DeveloperManager.tsx | 53 -
.../integration/developer/DeveloperToolbar.tsx | 22 -
.../features/integration/developer/EditorConfig.ts | 26 -
.../developer/EditorErrorBoundaryWrapper.tsx | 66 -
.../integration/developer/EditorOverlayWidget.css | 12 -
.../integration/developer/EditorOverlayWidget.tsx | 29 -
.../integration/developer/EditorToolbar.tsx | 58 -
.../integration/developer/MonacoEditorWrapper.tsx | 195 ---
.../developer/MonacoEditorWrapperStateless.tsx | 97 --
.../src/karavan/features/integration/devmode.css | 56 -
.../features/integration/files/CreateFileModal.tsx | 118 --
.../integration/files/CreateIntegrationModal.tsx | 185 --
.../features/integration/files/DeleteFileModal.tsx | 67 -
.../features/integration/files/DiffFileModal.css | 20 -
.../features/integration/files/DiffFileModal.tsx | 96 -
.../features/integration/files/FileComplexity.tsx | 134 --
.../integration/files/FileCopyForEnvModal.tsx | 79 -
.../integration/files/FilesTabWithComplexity.tsx | 481 -----
.../features/integration/files/FilesToolbar.tsx | 236 ---
.../features/integration/files/UploadFileModal.tsx | 148 --
.../integration/integration-build/BuildTab.tsx | 32 -
.../integration-containers/ContainerButtons.tsx | 148 --
.../ContainerEnvironmentPanel.tsx | 115 --
.../integration-containers/ContainersTab.tsx | 34 -
.../integration-containers/ContainersTable.tsx | 54 -
.../integration-containers/ContainersTableRow.tsx | 73 -
.../integration-containers/ContainersToolbar.tsx | 34 -
.../integration-containers/DeploymentButtons.tsx | 164 --
.../integration-containers/DeploymentPanel.tsx | 54 -
.../integration-containers/ImagesPanel.tsx | 293 ----
.../integration-containers/PodEventsLogTable.tsx | 61 -
.../CustomComponentFactory.tsx | 87 -
.../integration-topology/CustomEdge.tsx | 40 -
.../integration-topology/CustomGroup.tsx | 35 -
.../integration-topology/CustomNode.tsx | 145 --
.../integration-topology/GetCustomMenu.tsx | 67 -
.../integration-topology/TopologyApi.tsx | 657 -------
.../integration-topology/TopologyBeans.css | 52 -
.../integration-topology/TopologyBeans.tsx | 77 -
.../integration-topology/TopologyLegend.css | 68 -
.../integration-topology/TopologyLegend.tsx | 38 -
.../integration-topology/TopologyStore.ts | 182 --
.../integration-topology/TopologyTab.tsx | 209 ---
.../integration-topology/TopologyToolbar.tsx | 134 --
.../graph/TopologyDagreLayout.ts | 98 --
.../integration-topology/graph/TopologyGroup.ts | 3 -
.../integration-topology/graph/TopologyLink.ts | 72 -
.../integration-topology/graph/TopologyNode.ts | 4 -
.../integration/integration-topology/topology.css | 214 ---
.../integration-topology/useTopologyHook.tsx | 128 --
.../features/integration/readme/ReadmeTab.tsx | 31 -
.../features/integration/toolbar/BuildToolbar.tsx | 184 --
.../integration/toolbar/DevModeToolbar.css | 39 -
.../integration/toolbar/DevModeToolbar.tsx | 163 --
.../integration/toolbar/ProjectToolbar.tsx | 48 -
.../features/integration/useProjectHook.tsx | 173 --
.../karavan/features/integrations/Complexity.css | 57 -
.../features/integrations/ComplexityApi.tsx | 40 -
.../features/integrations/ComplexityModels.ts | 67 -
.../features/integrations/CreateProjectModal.tsx | 150 --
.../features/integrations/DeleteProjectModal.tsx | 69 -
.../features/integrations/IntegrationsPage.tsx | 95 -
.../features/integrations/ProjectStatusLabel.tsx | 85 -
.../features/integrations/ProjectZipApi.tsx | 39 -
.../karavan/features/integrations/ProjectsTab.tsx | 132 --
.../features/integrations/ProjectsTableRow.tsx | 162 --
.../integrations/ProjectsTableRowActivity.tsx | 19 -
.../integrations/ProjectsTableRowComplexity.tsx | 40 -
.../features/integrations/ProjectsToolbar.tsx | 125 --
.../features/integrations/SettingsToolbar.tsx | 59 -
.../features/integrations/UploadProjectModal.tsx | 99 --
.../src/karavan/features/settings/SettingsPage.tsx | 110 ++
.../src/karavan/features/system/SystemPage.tsx | 79 +-
.../system/containers/ContainerTableRow.tsx | 8 +-
.../features/system/containers/ContainersTable.tsx | 9 +-
.../webui/src/karavan/shared/icons/application.svg | 14 +-
.../main/webui/src/karavan/shared/icons/groovy.svg | 34 +-
.../main/webui/src/karavan/shared/icons/logout.svg | 23 -
.../main/webui/src/karavan/shared/monaco-setup.ts | 4 -
.../webui/src/karavan/shared/ui/MainToolbar.tsx | 6 +-
.../webui/src/karavan/shared/ui/PlatformLogos.tsx | 20 +-
.../main/webui/src/karavan/stores/ProjectStore.ts | 10 +-
karavan-generator/dependency-reduced-pom.xml | 82 -
karavan-generator/pom.xml | 6 +-
202 files changed, 210 insertions(+), 29173 deletions(-)
diff --git a/karavan-app/Dockerfile.dockerignore b/karavan-app/Dockerfile.dockerignore
index bd129012..f90221ba 100644
--- a/karavan-app/Dockerfile.dockerignore
+++ b/karavan-app/Dockerfile.dockerignore
@@ -18,4 +18,4 @@
!target/*-runner.jar
!target/lib/*
!target/quarkus-app/*
-src/*
\ No newline at end of file
+src/*
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index 22675323..a1eff6fa 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -73,7 +73,6 @@ quarkus.oidc.application-type=service
quarkus.oidc.roles.source=accesstoken
# Quarkus configuration
-quarkus.quinoa.enable-spa-routing=true
quarkus.http.enable-compression=true
quarkus.log.level=INFO
quarkus.banner.enabled=false
@@ -91,10 +90,11 @@ quarkus.kubernetes-client.devservices.enabled=false
%public.quarkus.swagger-ui.always-include=true
+quarkus.quinoa.enable-spa-routing=true
quarkus.quinoa.ci=false
quarkus.quinoa.package-manager-install=true
quarkus.quinoa.package-manager-install.node-version=24.11.1
-quarkus.quinoa.dev-server.port=3008
+quarkus.quinoa.dev-server.port=3003
quarkus.quinoa.dev-server.check-timeout=60000
quarkus.quinoa.ignored-path-prefixes=/ui,/public,/api/,/auth
quarkus.quinoa.package-manager-command.build-env.NODE_OPTIONS=--max-old-space-size=4096
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts b/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
index 7b9c1005..a2ba5024 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
@@ -45,8 +45,7 @@ import {ComponentApi, INTERNAL_COMPONENTS} from './ComponentApi';
import {CamelDefinitionApiExt} from './CamelDefinitionApiExt';
import {CamelDisplayUtil} from './CamelDisplayUtil';
import {CamelUtil} from './CamelUtil';
-import {LANDSCAPE_FILE_NAME_JSON, OPENAPI_FILE_NAME_JSON} from '../contants';
-import {X_APPLICATION_ID} from "@models/CatalogModels";
+import {LANDSCAPE_FILE_NAME_JSON, OPENAPI_FILE_NAME_JSON, X_APPLICATION_ID} from '../contants';
const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', 'PollEnrichDefinition', 'EnrichDefinition', 'WireTapDefinition', 'SagaDefinition', 'PollDefinition'];
diff --git a/karavan-app/src/main/webui/src/karavan-core/contants.ts b/karavan-app/src/main/webui/src/karavan-core/contants.ts
index adda84ce..b0f7f97f 100644
--- a/karavan-app/src/main/webui/src/karavan-core/contants.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/contants.ts
@@ -22,5 +22,7 @@ export const FILE_WORDS_SEPARATOR = '-'
export const OPENAPI_FILE_NAME_JSON = 'openapi.json';
export const OPENAPI_FILE_NAME_YAML = 'openapi.yaml';
export const JSON_SCHEMA_EXTENSION = ".schema.json";
+export const LANDSCAPE_FILE_NAME_JSON = "";
+export const X_APPLICATION_ID = "x-application-id";
export const WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX = "wizard-bean-";
diff --git a/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusRow.tsx b/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusRow.tsx
deleted file mode 100644
index 24fdd49c..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusRow.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React, {useState} from 'react';
-import {CodeBlock, CodeBlockCode, Label, Tab, Tabs,} from '@patternfly/react-core';
-import {Tbody, Td, Tr} from '@patternfly/react-table';
-import {CamelStatus} from "@models/ProjectModels";
-
-export interface Props {
- index: number
- camel: CamelStatus
-}
-
-export function CamelStatusRow(props: Props) {
-
- const [isExpanded, setIsExpanded] = useState<boolean>(false);
- const [tab, setTab] = useState<string | number>('context');
-
- const {index, camel} = props;
- // const isRunning = container.state === 'running';
- // const color = isRunning ? "green" : "grey";
- return (
- <Tbody>
- <Tr className='camelstatus-data'>
- <Td noPadding isActionCell expand={{
- rowIndex: props.index,
- isExpanded: isExpanded,
- onToggle: () => setIsExpanded(!isExpanded),
- expandId: 'composable-expandable-example'
- }} modifier={"fitContent"}/>
- <Td noPadding modifier={"nowrap"}>
- {camel.projectId}
- </Td>
- <Td noPadding modifier={"nowrap"}>
- {camel.containerName}
- </Td>
- <Td noPadding>
- <Label color={'green'}>{camel.env}</Label>
- </Td>
- </Tr>
- <Tr isExpanded={isExpanded} className='fields-data'>
- <Td/>
- <Td colSpan={3}>
- <Tabs activeKey={tab} onSelect={(event, tabIndex) => setTab(tabIndex)}>
- {camel.statuses.map(statusValue => (
- <Tab eventKey={statusValue.name} title={statusValue.name}/>
- ))}
- </Tabs>
- <CodeBlock>
- <CodeBlockCode id="code-content">{camel.statuses.filter(s => s.name === tab).at(0)?.status}</CodeBlockCode>
- </CodeBlock>
- </Td>
- </Tr>
- </Tbody>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusesTable.tsx b/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusesTable.tsx
deleted file mode 100644
index 6311e959..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/diagnostics/camel/CamelStatusesTable.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, {useEffect} from 'react';
-import {Bullseye, EmptyState, Spinner} from '@patternfly/react-core';
-import {InnerScrollContainer, OuterScrollContainer, Table, Td, Th, Thead, Tr} from '@patternfly/react-table';
-import {shallow} from "zustand/shallow";
-import {useStatusesStore} from "@stores/ProjectStore";
-import {CamelStatusRow} from "./CamelStatusRow";
-
-export function CamelStatusesTable() {
-
- const [camels] = useStatusesStore((state) => [state.camelContexts], shallow);
-
- useEffect(() => {
- }, []);
-
- function getTableBody() {
- return (
- camels.map((camel, index) => (
- <CamelStatusRow key={index} index={index} camel={camel}/>
- ))
- )
- }
-
- function getTableEmpty() {
- return (
- <Tr>
- <Td colSpan={15}>
- <Bullseye>
- <EmptyState icon={Spinner}/>
- </Bullseye>
- </Td>
- </Tr>
- )
- }
-
- return (
- <OuterScrollContainer>
- <InnerScrollContainer>
- <Table variant='compact' borders={false} isStickyHeader>
- <Thead>
- <Tr>
- <Th/>
- <Th key='name'>Project ID</Th>
- <Th key='key' modifier={"fitContent"}>Container Name</Th>
- <Th key='value' modifier={"fitContent"}>Environment</Th>
- </Tr>
- </Thead>
- {camels && camels.length > 0 ? getTableBody() : getTableEmpty()}
- </Table>
- </InnerScrollContainer>
- </OuterScrollContainer>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ContainerLogTab.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ContainerLogTab.tsx
deleted file mode 100644
index 61674a5c..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ContainerLogTab.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, {useEffect, useState} from 'react';
-import {useLogStore, useSelectedContainerStore} from "@stores/ProjectStore";
-import {shallow} from "zustand/shallow";
-import {LogWatchApi} from "@api/LogWatchApi";
-import {LogViewer, LogViewerSearch} from '@patternfly/react-log-viewer';
-import {Button, Checkbox, Tooltip, TooltipPosition} from "@patternfly/react-core";
-import {ProjectEventBus} from "@bus/ProjectEventBus";
-import {TrashAltIcon} from "@patternfly/react-icons";
-import {ProjectContainerContextToolbar} from "@features/integration/ProjectContainerContextToolbar";
-
-export function ContainerLogTab() {
-
- const [selectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName]);
- const [logViewerRef] = useState(React.createRef());
- const [data, currentLine, setData] = useLogStore((state) => [state.data, state.currentLine, state.setData], shallow);
-
- const [isTextWrapped, setIsTextWrapped] = useState(true);
- const [autoScroll, setAutoScroll] = useState(true);
- const [controller, setController] = React.useState(new AbortController());
- const showLogger = selectedContainerName !== undefined && selectedContainerName !== null;
-
- useEffect(() => {
- setData('');
- controller.abort()
- const c = new AbortController();
- setController(c);
- if (selectedContainerName) {
- const f = LogWatchApi.fetchData('container', selectedContainerName, c).then(_ => {
-
- });
- }
- return () => {
- c.abort();
- };
- }, [selectedContainerName]);
-
- function getToolbar() {
- return (
- <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '8px', paddingRight: '16px'}}>
- <LogViewerSearch placeholder={'search'} minSearchChars={4} style={{width: "400px"}}/>
- <Tooltip content={"Clean log"} position={TooltipPosition.bottom}>
- <Button variant="plain" onClick={() => ProjectEventBus.sendLog('set', '')} icon={<TrashAltIcon/>}/>
- </Tooltip>
- <Checkbox label="Wrap text" aria-label="wrap text checkbox" isChecked={isTextWrapped}
- id="wrap-text-checkbox"
- onChange={(_, checked) => setIsTextWrapped(checked)}/>
- <Checkbox label="Autoscroll" aria-label="autoscroll checkbox" isChecked={autoScroll}
- id="autoscroll-checkbox"
- onChange={(_, checked) => setAutoScroll(checked)}/>
- </div>
- );
- }
-
- return (
- <div className="project-log-tab">
- <LogViewer
- isTextWrapped={isTextWrapped}
- innerRef={logViewerRef}
- hasLineNumbers={false}
- loadingContent={"Loading..."}
- height={"100vh"}
- data={showLogger && data.length > 0 ? data : "........."}
- scrollToRow={autoScroll ? currentLine : undefined}
- theme={'dark'}
- toolbar={<ProjectContainerContextToolbar additionalTools={getToolbar()}/>}
- />
- </div>
- );
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/DesignerSwitch.css b/karavan-app/src/main/webui/src/karavan/features/integration/DesignerSwitch.css
deleted file mode 100644
index 500215c1..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/DesignerSwitch.css
+++ /dev/null
@@ -1,23 +0,0 @@
-.designer-switch {
- --pf-v6-c-tabs__link--BackgroundColor: var(--pf-v6-c-tabs__link--hover--BackgroundColor);
- .pf-v6-c-tabs__item {
- padding-left: 2px;
- padding-right: 2px;
- }
- .pf-v6-c-tabs__link::before {
- /*content: "";*/
- /*position: absolute;*/
- /*right: 0;*/
- /*bottom: 0;*/
- /*left: 0;*/
- /*border: solid;*/
- /*border-bottom-color: var(--pf-t--global--border--color--default);*/
- }
- .switch-selected .pf-v6-c-tabs__link {
- color: var(--pf-t--global--color--brand--default);
- border: 1px solid var(--pf-t--global--color--brand--default);
- }
-}
-.designer-switch::before {
- display: none;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/DesignerToggle.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/DesignerToggle.tsx
deleted file mode 100644
index 44b2b187..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/DesignerToggle.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 {ToggleGroup, ToggleGroupItem,} from '@patternfly/react-core';
-import './DesignerSwitch.css';
-import {useFileStore} from "@stores/ProjectStore";
-import {shallow} from "zustand/shallow";
-import {useDesignerStore} from "@features/integration/designer/DesignerStore";
-import {getProjectFileTypeByName} from "@models/ProjectModels";
-import {CodeIcon} from "@patternfly/react-icons/dist/esm/icons";
-import {DeploymentPattern} from "@carbon/icons-react";
-
-export function DesignerToggle() {
-
- const [file] = useFileStore((s) => [s.file], shallow);
- const [setDesignerSwitch, designerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch, s.designerSwitch], shallow)
-
- const fileType = getProjectFileTypeByName(file?.name || "");
- const showDesignerSwitch = fileType.filter(ft => ['INTEGRATION', 'KAMELET', 'OPENAPI' , 'ASYNCAPI'].includes(ft.name)).length > 0;
-
- return (
- <ToggleGroup aria-label="DesignerToggle">
- <ToggleGroupItem
- icon={<DeploymentPattern className='carbon'/>}
- aria-label="designer"
- text='Designer'
- buttonId="toggle-group-icons-1"
- isSelected={designerSwitch}
- isDisabled={!showDesignerSwitch}
- onChange={(_, __) => setDesignerSwitch(true)}
- />
- <ToggleGroupItem
- icon={<CodeIcon/>}
- text='Code'
- aria-label="code"
- buttonId="toggle-group-icons-2"
- isSelected={!designerSwitch}
- onChange={(_, __) => setDesignerSwitch(false)}
- />
- </ToggleGroup>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/FileSearchToolbarItem.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/FileSearchToolbarItem.tsx
deleted file mode 100644
index 8cd0e8c9..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/FileSearchToolbarItem.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React, {useEffect} from 'react';
-import {Button, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities} from '@patternfly/react-core';
-import {shallow} from "zustand/shallow";
-import {useSearchStore} from "@stores/SearchStore";
-import {SearchApi} from "@api/SearchApi";
-import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
-import {useDebounceValue} from "usehooks-ts";
-
-export function FileSearchToolbarItem() {
-
- const [search, setSearch, setSearchResults] = useSearchStore((s) => [s.search, s.setSearch, s.setSearchResults], shallow)
- const [debouncedSearch] = useDebounceValue(search, 300);
-
- useEffect(() => {
- if (search !== undefined && search !== '') {
- SearchApi.searchAll(search, response => {
- if (response) {
- setSearchResults(response);
- }
- })
- } else {
- setSearchResults([])
- }
- }, [debouncedSearch]);
-
- function searchInput() {
- return (
- <TextInputGroup style={{ width: "300px" }}>
- <TextInputGroupMain
- id="search-input"
- value={search}
- placeholder='Search'
- type="text"
- autoComplete={"off"}
- autoFocus={true}
- onChange={(_event, value) => {
- setSearch(value);
- }}
- aria-label="text input example"
- />
- <TextInputGroupUtilities>
- <Button variant="plain" onClick={_ => {
- setSearch('');
- }}>
- <TimesIcon aria-hidden={true}/>
- </Button>
- </TextInputGroupUtilities>
- </TextInputGroup>
- )
- }
-
- return (searchInput())
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ImageDownloadToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ImageDownloadToolbar.tsx
deleted file mode 100644
index 69af5be6..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ImageDownloadToolbar.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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, {useEffect} from 'react';
-import {FlexItem, Toolbar, ToolbarContent,} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-
-import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {useFileStore, useProjectStore} from "../../stores/ProjectStore";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
-import {shallow} from "zustand/shallow";
-
-export function ImageDownloadToolbar() {
-
- const [project] = useProjectStore((s) => [s.project], shallow)
- const [file] = useFileStore((state) => [state.file], shallow)
-
- useEffect(() => {
- }, [file]);
-
- function isYaml(): boolean {
- return file !== undefined && file.name.endsWith("yaml");
- }
-
- function isIntegration(): boolean {
- return isYaml() && file?.code !== undefined && CamelDefinitionYaml.yamlIsIntegration(file.code) !== 'none';
- }
-
- function downloadImage() {
- EventBus.sendCommand("downloadImage");
- }
-
- return (
- <Toolbar id="toolbar-group-types">
- <ToolbarContent>
- {isIntegration() &&
- <FlexItem>
- {/*<Tooltip content="Download image" position={"bottom-end"}>*/}
- {/* <Button size="sm" variant="control" icon={<DownloadImageIcon/>}*/}
- {/* onClick={e => downloadImage()}/>*/}
- {/*</Tooltip>*/}
- </FlexItem>
- }
- </ToolbarContent>
- </Toolbar>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/Project.types.ts b/karavan-app/src/main/webui/src/karavan/features/integration/Project.types.ts
deleted file mode 100644
index 2630a6d4..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/Project.types.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import {DslMetaModel} from "@features/integration/designer/utils/DslMetaModel";
-import {Project} from "@models/ProjectModels";
-
-export type ProjectFunctions = {
- createNewRouteFile: (dsl: DslMetaModel, parentId: string, position?: number | undefined, fileName?: string) => void;
- createOpenApiRestFile: () => void;
- createNewBean: () => void;
- createNewKamelet: () => void;
- createRouteConfiguration: () => void;
- createOpenApi: () => void;
- createAsyncApi: () => void;
- createNewRestFile: () => void;
- refreshData: () => void;
- refreshSharedData: () => void;
- isOpenApiExists: () => boolean;
- isAsyncApiExists: () => boolean;
- project: Project
-};
-
-// 2. Define the hook FUNCTION'S signature
-export type UseProjectHook = () => ProjectFunctions;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainerContextToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainerContextToolbar.tsx
deleted file mode 100644
index de60c80b..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainerContextToolbar.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, {ReactElement} from 'react';
-import {ProjectTitle} from "@features/integration/ProjectTitle";
-import {ProjectContainersContext} from "@features/integration/ProjectContainersContextProvider";
-import {ToggleGroup, ToggleGroupItem} from "@patternfly/react-core";
-import {useProjectStore, useSelectedContainerStore} from "@stores/ProjectStore";
-import {BuildIcon, CogIcon, RunningIcon} from "@patternfly/react-icons";
-import {ContainerStatus} from "@models/ProjectModels";
-
-interface Props {
- additionalTools?: ReactElement;
- hideContainersToggle?: boolean;
-}
-
-export function ProjectContainerContextToolbar(props: Props): ReactElement {
-
- const {additionalTools, hideContainersToggle} = props;
- const context = React.useContext(ProjectContainersContext);
- // if (!context) throw new Error("ProjectContainersContext not found!");
- // const {containerStatuses} = context ? context : undefined;
- const [selectedContainerName, setSelectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName, s.setSelectedContainerName]);
- const [tabIndex] = useProjectStore((s) => [s.tabIndex]);
-
- function getIcon(status: ContainerStatus) {
- if (status.type === "devmode") {
- const className = status.state === "running" ? 'project-container-devmode' : ''
- return <CogIcon className={className}/>
- } else if (status.type === "packaged") {
- const className = status.state === "running" ? 'project-container-package' : ''
- return <RunningIcon className={className}/>
- } else if (status.type === "build") {
- const className = status.state === "running" ? 'project-container-build' : ''
- return <BuildIcon className={className}/>
- }
- }
-
- function getContainers() {
- if (tabIndex !== 'build') {
- return context?.containerStatuses?.filter( cs => cs.type !== 'build') ?? [];
- } else {
- return context?.containerStatuses?.filter( cs => cs.type === 'build') ?? [];
- }
- }
-
- return (
- <div className="topology-toolbar">
- <div className="group-switch">
- <ProjectTitle/>
- </div>
- {additionalTools}
- {context && !hideContainersToggle && <div>
- <ToggleGroup aria-label="Default with single selectable">
- {getContainers().map(status => (
- <ToggleGroupItem
- key={status.containerName}
- icon={getIcon(status)}
- text={status.containerName}
- buttonId={status.containerName}
- isSelected={selectedContainerName === status.containerName}
- onChange={_ => setSelectedContainerName(status.containerName)}
- />
- ))}
- </ToggleGroup>
- </div>
- }
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainersContextProvider.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainersContextProvider.tsx
deleted file mode 100644
index 8204b175..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContainersContextProvider.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import React from 'react';
-import {useAppConfigStore, useProjectStore, useStatusesStore} from "@stores/ProjectStore";
-import {shallow} from "zustand/shallow";
-import {ContainerStatus} from "@models/ProjectModels";
-import {Label, Tooltip} from "@patternfly/react-core";
-import {CogIcon, PackageIcon} from "@patternfly/react-icons";
-import DevIcon from "@patternfly/react-icons/dist/esm/icons/dev-icon";
-
-type ProjectContainersContextType = {
- containerStatuses: ContainerStatus[]
- packagedContainerStatuses: ContainerStatus[]
- devModeContainerStatus?: ContainerStatus
- devModeIsRunning: boolean;
- packagedIsRunning: boolean;
- buildIsRunning: boolean;
- origin: string;
- camelContext: any,
- containersStatusIcons: React.ReactElement<any>,
-};
-
-export const ProjectContainersContext = React.createContext<ProjectContainersContextType | undefined>(undefined);
-
-type ProjectContainersContextEnvelopeProps = {
- children: React.ReactNode
-};
-
-export function ProjectContainersContextProvider({children}: ProjectContainersContextEnvelopeProps) {
-
- const [config] = useAppConfigStore((s) => [s.config], shallow);
- const [project, camelStatuses] = useProjectStore((s) => [s.project, s.camelStatuses], shallow);
- const [containers] = useStatusesStore((s) => [s.containers], shallow);
-
- const containerStatuses = containers.filter(c => c.projectId === project.projectId) || [];
- const packagedContainerStatuses = containerStatuses.filter(c => c.type === 'packaged') || [];
- const isProjectContainer = packagedContainerStatuses.length > 0;
- const packagedIsRunning = isProjectContainer && (packagedContainerStatuses.filter(c => c.state === 'running').length === packagedContainerStatuses.length);
-
- const devModeContainerStatus = containerStatuses.filter(c => c.type === 'devmode').at(0);
- const devModeIsRunning = devModeContainerStatus?.state === 'running';
-
- const buildContainerStatus = containerStatuses.filter(c => c.type === 'build').at(0);
- const buildIsRunning = buildContainerStatus?.state === 'running';
-
- const isKubernetes = config.infrastructure === 'kubernetes'
-
- const runningContainer = devModeIsRunning ? devModeContainerStatus : packagedContainerStatuses.find(c => c.state === 'running');
-
- const origin = 'http://' + (isKubernetes
- ? runningContainer?.podId + ':8080'
- : runningContainer?.containerName + ':8080'
- );
-
- const camelStatus = camelStatuses.filter(s => s.projectId === project.projectId).at(0);
- const contextValue = camelStatus?.statuses?.filter(x => x.name === 'context').at(0);
- const camelContext = contextValue ? JSON.parse(contextValue?.status || '') : {};
-
- const isRunning = packagedIsRunning || devModeIsRunning;
- const className = isRunning ? 'rotated-run' : ''
- const tooltip = devModeIsRunning ? 'Running dev mode' : 'Running packaged'
- const containersStatusIcons = (
- <div style={{flex: 2, display: 'flex', flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center'}}>
- {isRunning &&
- <Tooltip content={tooltip} position='left'>
- <Label variant='outline'>
- <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', gap: '3px'}}>
- <CogIcon className={`${className} rotated-run-forward`}/>
- {devModeIsRunning && <DevIcon className={className} width={32} height={32}/>}
- {packagedIsRunning && <PackageIcon className={className} width={32} height={32}/>}
- </div>
- </Label>
- </Tooltip>
- }
- </div>
- )
-
- return (
- <ProjectContainersContext.Provider value={{containerStatuses, packagedContainerStatuses, devModeContainerStatus, devModeIsRunning, packagedIsRunning, origin, buildIsRunning, camelContext, containersStatusIcons}}>
- {children}
- </ProjectContainersContext.Provider>
- );
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContext.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContext.tsx
deleted file mode 100644
index 830f672d..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectContext.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import React, {createContext, useContext} from 'react';
-import {ProjectFunctions, UseProjectHook} from './Project.types';
-
-const ProjectContext = createContext<ProjectFunctions | null>(null);
-
-export const useProjectFunctions = () => {
- const context = useContext(ProjectContext);
- if (context === null) {
- throw new Error('UseProjectHook must be used within a ProjectProvider');
- }
- return context;
-};
-
-interface ProjectProviderProps {
- children: React.ReactNode;
- useProjectHook: UseProjectHook;
-}
-
-export const ProjectProvider: React.FC<ProjectProviderProps> = ({
- children,
- useProjectHook,
- }) => {
- const api = useProjectHook();
- return (
- <ProjectContext.Provider value={api}>
- {children}
- </ProjectContext.Provider>
- );
-};
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.css b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.css
deleted file mode 100644
index 42e64a03..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.css
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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.
- */
-.karavan .project-page {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.karavan .project-page .scrollable-out {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.karavan .project-page .scrollable-in {
- overflow: auto;
- flex-shrink: unset;
- flex-grow: 1;
- margin-bottom: 100px;
-}
-
-.karavan .project-title {
- flex: 1;
- .pf-v6-l-flex.pf-m-column > * {
- margin-bottom: 0;
- }
- .pf-v6-c-clipboard-copy {
- width: fit-content;
- .pf-v6-c-button {
- padding: 0;
- }
- }
-}
-
-.karavan .project-page .tools-section {
- border-bottom: 1px solid #eee;
-}
-
-.karavan .project-page .project-tabs {
- background-color: white;
-}
-
-.karavan .project-page .description-align-center .pf-v6-c-description-list__group {
- min-height: 30px;
- align-items: center;
-}
-
-.karavan .project-page .pf-v6-c-tabs__link,
-.karavan .project-page .pf-m-link {
- font-size: 14px;
-}
-
-.karavan .project-page .project-button {
- width: 100px;
-}
-
-.karavan .project-page .badge-env-up {
- background-color: rgb(56, 129, 47);
- color: white;
-}
-
-.karavan .project-page .env-chart {
- font-size: 18px;
-}
-
-.karavan .project-page .replicas-ready {
- background-color: rgb(56, 129, 47);
- color: white;
-}
-
-.karavan .project-page .health-up {
- background-color: rgb(56, 129, 47);
- color: white;
-}
-
-.karavan .project-page .project-properties .delete-cell {
- padding: 0;
- margin: 0;
- min-width: 0;
-}
-.karavan .project-page .project-properties .delete-button {
- padding: 0 0 0 0;
- margin: 0 16px 0 0;
-}
-
-.karavan .project-page .pf-v6-c-label__icon {
- height: 16px;
-}
-
-.karavan .project-page .pf-v6-c-label__icon svg {
- height: 16px;
-}
-
-.karavan .project-page .badge {
- font-size: 14px;
- font-weight: 400;
- padding: 4px 8px 4px 8px;
- min-width: 70px;
-}
-
-.karavan .project-files-toolbar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 8px;
- padding: 8px 16px 8px 16px;
- position: relative;
-}
-
-.karavan .project-files-toolbar::before {
- position: absolute;
- inset: 0;
- pointer-events: none;
- content: "";
- border-bottom: var(--pf-t--global--border--color--default) solid var(--pf-t--global--border--width--box--default);
- border-radius: inherit;
-}
-
-.karavan .project-page .runtime-tab {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- padding: 16px;
- gap: 16px;
-
- .runtime-element {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 8px;
- }
-}
-
-.karavan .project-page-navigation {
- gap: 16px;
- .pf-v6-c-nav__link {
- align-items: center;
- .pf-v6-c-nav__link-icon {
- display: flex;
- align-items: center;
- /*width: 20px;*/
- /*height: 20px;*/
- }
- }
-
- .jvm-svg-steam-on {
- height: 20px;
- width: 20px;
- filter: brightness(1.3) contrast(1.3) saturate(2) drop-shadow(0 0 6px #4cc3ff);
- .steam {
- fill: #FF8C26;
- transform-origin: center;
- animation: steam-movement 4s infinite, /* Combined scale and translate */ steam-opacity 4s infinite; /* Opacity */
- }
- }
-
- .jvm-svg-steam-off {
- height: 20px;
- width: 20px;
- filter: brightness(2) saturate(0);
- animation: none !important;
- }
-
- .camel-paused {
- filter: saturate(0);
- }
-
- .rotated-run {
- width: 16px;
- height: 16px;
- color: var(--pf-t--color--green--40);
- /*animation: icon-flashing 1.5s linear infinite;*/
- }
- .rotated-run-forward {
- animation: rotate-icon-forward 1.5s linear infinite
- }
-
- .rotated-run-backward {
- animation: rotate-icon-backward 1.5s linear infinite,
- icon-flashing 1.5s linear infinite
- }
-
- .containers-run {
- color: var(--pf-t--global--color--status--success--100);
- animation: icon-flashing 1.5s linear infinite,
- scale-icon 1.5s linear infinite;
- }
-}
-
-@keyframes icon-flashing {
- 0% {
- color: var(--pf-t--color--green--20);
- border-color: var(--pf-t--global--color--status--success--100);
- }
- 50% {
- color: var(--pf-t--color--green--40);
- border-color: var(--pf-t--global--color--status--success--200);
- }
- 100% {
- color: var(--pf-t--color--green--60);
- border-color: var(--pf-t--global--icon--color--status--success--default);
- }
-}
-
-@keyframes scale-icon {
- from {
- transform: scale(1);
- }
- to {
- transform: scale(1.1);
- }
-}
-
-@keyframes rotate-icon-forward {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-@keyframes rotate-icon-backward {
- from {
- transform: rotate(360deg);
- }
- to {
- transform: rotate(0deg);
- }
-}
-
-@keyframes logline {
- 0% { opacity: 0; transform: translateX(-2px); }
- 20% { opacity: 1; transform: translateX(0); }
- 80% { opacity: 1; }
- 100% { opacity: 0; }
-}
-
-@keyframes steam-movement {
- 0% {
- transform: translate(0, 0) scale(1, 1);
- }
- 25% {
- transform: translate(0.5px, -1.5px) scale(1.1, 1.3);
- }
- 50% {
- transform: translate(-0.3px, -2.2px) scale(0.95, 1.1);
- }
- 75% {
- transform: translate(0.1px, -3px) scale(1.25, 1.15);
- }
- 100% {
- transform: translate(0, 0) scale(1, 1);
- }
-}
-
-@keyframes steam-opacity {
- 0% { opacity: 0.7; }
- 25% { opacity: 1; }
- 50% { opacity: 0.85; }
- 75% { opacity: 1; }
- 100% { opacity: 0.7; }
-}
-
-.popover-file-validation {
- .pf-v6-c-popover__content {
- padding-right: 0;
-
- .pf-v6-c-popover__body {
- max-height: 50vh;
- overflow-y: auto;
-
- .pf-v6-c-alert {
- border-width: 1px;
- padding: 6px;
- }
- }
-
- .pf-v6-c-popover__body > div {
- height: 100%; /* Make the inner div fill the body's space */
- display: flex; /* Keep original display properties for inner layout */
- flex-direction: column;
- }
- }
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.tsx
deleted file mode 100644
index 4fcb0ef8..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPage.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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, {JSX, useEffect, useState} from 'react';
-import './ProjectPage.css';
-import {shallow} from "zustand/shallow";
-import {useNavigate, useParams} from "react-router-dom";
-import {useFilesStore, useFileStore, useProjectsStore, useProjectStore} from '@stores/ProjectStore';
-import {BUILD_IN_PROJECTS, Project} from '@models/ProjectModels';
-import {RightPanel} from "@shared/ui/RightPanel";
-import {ROUTES} from "@app/navigation/Routes";
-import {useProjectFunctions} from './ProjectContext';
-import {ProjectPageNavigation} from "@features/integration/ProjectPageNavigation";
-import {ProjectContainersContextProvider} from "@features/integration/ProjectContainersContextProvider";
-import {Content} from "@patternfly/react-core";
-import {ProjectToolbar} from "@features/integration/toolbar/ProjectToolbar";
-import {ProjectPanel} from "@features/integration/ProjectPanel";
-
-interface ProjectPageProps {
- developerManager: JSX.Element;
-}
-
-function ProjectPage(props: ProjectPageProps): JSX.Element {
-
- const {developerManager} = props;
- const [files] = useFilesStore((s) => [s.files], shallow);
- const [projects] = useProjectsStore((state) => [state.projects], shallow)
- const [project, setProject, tabIndex, setTabIndex, refreshTrace] =
- useProjectStore((s) => [s.project, s.setProject, s.tabIndex, s.setTabIndex, s.refreshTrace], shallow);
- const [file, operation, setFile] = useFileStore((s) => [s.file, s.operation, s.setFile], shallow);
- const showFilePanel = file !== undefined && operation === 'select';
- const [urlFileName, setUrlFileName] = useState<string>();
- const {refreshData} = useProjectFunctions();
- const isBuildIn = BUILD_IN_PROJECTS.includes(project.projectId);
-
- let {projectId, fileName} = useParams();
- const navigate = useNavigate();
-
- useEffect(() => {
- setUrlFileName(fileName)
- window.history.replaceState({}, "", `${ROUTES.INTEGRATIONS}/${projectId}`);
- const p = projects.filter(project => project.projectId === projectId).at(0);
- if (p) {
- setProject(p, "select");
- if (!BUILD_IN_PROJECTS.includes(p.projectId)) {
- setTabIndex('topology');
- }
- } else {
- navigate('/');
- }
- return () => {
- setProject(new Project(), "none");
- setTabIndex('topology');
- }
- }, []);
-
- useEffect(() => {
- if (urlFileName !== undefined) {
- const file = files
- .filter(f => f.projectId === projectId && f.name === urlFileName)?.at(0);
- if (file) {
- setFile('select', file);
- setTabIndex('topology');
- setUrlFileName(undefined);
- }
- }
- }, [files]);
-
- useEffect(() => {
- const interval = setInterval(() => refreshData(), 700)
- return () => clearInterval(interval);
- }, [tabIndex, refreshTrace, project]);
-
- function title() {
- return (<Content component="h2">Integration</Content>)
- }
-
- return (
- <RightPanel
- title={title()}
- toolsStart={
- <ProjectContainersContextProvider>
- <ProjectPageNavigation/>
- </ProjectContainersContextProvider>
- }
- tools={<ProjectToolbar/>}
- mainPanel={
- <div className="right-panel-card">
- {showFilePanel && developerManager}
- {!showFilePanel && <ProjectPanel/>}
- </div>
- }
- />
- )
-}
-
-export default ProjectPage
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPageNavigation.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPageNavigation.tsx
deleted file mode 100644
index a6eeeb0d..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPageNavigation.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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, {JSX, useEffect, useState} from 'react';
-import {capitalize, Nav, NavItem, NavList,} from '@patternfly/react-core';
-import './ProjectPage.css';
-import {ProjectMenu, ProjectMenus, ProjectRuntimeMenu, ProjectRuntimeMenus, useFilesStore, useFileStore, useProjectStore, useSelectedContainerStore} from '@stores/ProjectStore';
-import {BUILD_IN_PROJECTS} from '@models/ProjectModels';
-import {ProjectContainersContext} from "@features/integration/ProjectContainersContextProvider";
-
-export function ProjectPageNavigation(): JSX.Element {
-
- const context = React.useContext(ProjectContainersContext);
- if (!context) throw new Error("ProjectContainersContext not found!");
-
- const [selectedContainerName, setSelectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName, s.setSelectedContainerName]);
-
- const {devModeIsRunning, packagedIsRunning, buildIsRunning, containerStatuses, devModeContainerStatus, camelContext, containersStatusIcons} = context;
- const hasContainers = containerStatuses?.length > 0;
- const devContainer = containerStatuses.filter(c => c.type === 'devmode')?.at(0)
- const hasDevmodeContainers = devContainer !== undefined;
- const buildContainer = containerStatuses.filter(c => c.type === 'build')?.at(0)
- const hasBuildContainers = buildContainer !== undefined;
-
- const [files] = useFilesStore((s) => [s.files]);
- const [project, tabIndex, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex]);
- const [setFile] = useFileStore((s) => [s.setFile]);
-
- const [buildContainerId, setBuildContainerId] = useState<string>('');
- const [hasDevMode, setHasDevMode] = useState<boolean>(false);
-
- useEffect(() => {
- selectName();
- }, [tabIndex, hasDevmodeContainers, hasBuildContainers, buildContainer?.containerId, buildContainerId])
-
- function selectName(){
- const selectedContainers = containerStatuses.filter(c => c.containerName === selectedContainerName) || [];
- const names = containerStatuses
- ?.filter(cs => {
- if (tabIndex === "build") {
- return cs.type === 'build'
- } else {
- return ['devmode', 'packaged'].includes(cs.type)
- }
- })
- ?.map(cs => cs.containerName);
- const name = names?.at(0);
- if (tabIndex === "build" && buildContainer?.containerId && buildContainerId !== buildContainer?.containerId) {
- setSelectedContainerName(undefined);
- setBuildContainerId(buildContainer?.containerId);
- } else if (tabIndex === "build" && buildContainerId === buildContainer?.containerId && selectedContainerName === undefined) {
- setSelectedContainerName(buildContainer.containerName);
- } else if (!hasDevmodeContainers && hasDevMode) {
- setHasDevMode(false);
- setTabIndex(0);
- setSelectedContainerName(undefined);
- } else if (hasDevmodeContainers && !hasDevMode) {
- setHasDevMode(true);
- setTabIndex('log');
- setSelectedContainerName(devModeContainerStatus?.containerName);
- } else if (selectedContainers.length === 0 && selectedContainerName !== undefined) {
- setSelectedContainerName(undefined);
- } else if (selectedContainerName === undefined || !names?.includes(selectedContainerName) && name) {
- setSelectedContainerName(name);
- } else if (!names?.includes(selectedContainerName)) {
- setSelectedContainerName(undefined);
- }
- }
-
- function isBuildIn(): boolean {
- return BUILD_IN_PROJECTS.includes(project.projectId);
- }
-
- function hasReadme(): boolean {
- return files.map(f => f.name).findIndex(f => f.toLowerCase() === 'readme.md') !== -1;
- }
-
- const onNavSelect = (_: any, selectedItem: {
- groupId: number | string;
- itemId: number | string;
- to: string;
- }
- ) => {
- setTabIndex(selectedItem.itemId as ProjectMenu);
- setFile('none', undefined);
- };
-
- function getProjectMenu(): ProjectMenu[] {
- let menu: ProjectMenu[] = []
- if (isBuildIn()) {
- menu.push('files');
- } else {
- menu.push(...ProjectMenus);
- }
- if (!hasReadme()) {
- menu = menu.filter(m => m !== 'readme')
- }
- return menu;
- }
-
- function getProjectRuntimeMenusMenu(): ProjectRuntimeMenu[] {
- let menu: (ProjectRuntimeMenu)[] = []
- if ((devModeIsRunning || packagedIsRunning || devModeContainerStatus) && tabIndex !== "build") {
- menu.push(...ProjectRuntimeMenus);
- }
- return menu;
- }
-
- const projectRuntimeMenus = getProjectRuntimeMenusMenu();
- return (
- <Nav onSelect={onNavSelect} aria-label="Nav1" variant="horizontal" className="project-page-navigation">
- <NavList>
- {getProjectMenu().map((item, i) =>
- <NavItem key={item} preventDefault itemId={item} isActive={tabIndex === item} to="#">
- {capitalize(item)}
- </NavItem>
- )}
- </NavList>
- {containersStatusIcons}
- {projectRuntimeMenus.length > 0 &&
- <NavList>
- {getProjectRuntimeMenusMenu().map((item, i) =>
- <NavItem key={item} preventDefault itemId={item} isActive={tabIndex === item} to="#">
- {capitalize(item)}
- </NavItem>
- )}
- </NavList>
- }
- </Nav>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPanel.tsx
deleted file mode 100644
index 5d81a65b..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectPanel.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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, {useEffect} from 'react';
-import {shallow} from "zustand/shallow";
-import {IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
-import {useAppConfigStore, useFilesStore, useProjectStore} from '@stores/ProjectStore';
-import {useSelectorStore} from '@features/integration/designer/DesignerStore';
-import {ProjectService} from '@services/ProjectService';
-import {BUILD_IN_PROJECTS, ProjectType} from '@models/ProjectModels';
-import {TopologyTab} from '@features/integration/integration-topology/TopologyTab';
-import {CreateIntegrationModal} from '@features/integration/files/CreateIntegrationModal';
-import {DslSelector} from '@features/integration/designer/selector/DslSelector';
-import {BeanWizard} from '@features/integration/beans/BeanWizard';
-import {BuildTab} from '@features/integration/integration-build/BuildTab';
-import {ReadmeTab} from "@features/integration/readme/ReadmeTab";
-import {FilesTabWithComplexity} from '@features/integration/files/FilesTabWithComplexity';
-import {useSearchStore} from "@stores/SearchStore";
-import {ASYNCAPI_FILE_NAME_JSON, OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
-import {useProjectFunctions} from "@features/integration/ProjectContext";
-import {ContainerLogTab} from "@features/integration/ContainerLogTab";
-import {ProjectContainersContextProvider} from "@features/integration/ProjectContainersContextProvider";
-import {ContainersTab} from "@features/integration/integration-containers/ContainersTab";
-
-export function ProjectPanel() {
-
- const [config] = useAppConfigStore((state) => [state.config], shallow)
- const [project, tab, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex], shallow);
- const [files, setFiles, setSelectedFileNames] = useFilesStore((s) => [s.files, s.setFiles, s.setSelectedFileNames], shallow);
- const [search, searchResults] = useSearchStore((s) => [s.search, s.searchResults], shallow)
- const [showSelector] = useSelectorStore((s) => [s.showSelector], shallow)
-
- const {createNewRouteFile} = useProjectFunctions();
-
- const filedFound = searchResults.filter(s => s.projectId === project.projectId)?.at(0)?.files || [];
- const iFiles = files
- .filter(f => f.name.endsWith('.camel.yaml'))
- .filter(f => search === '' || filedFound.includes(f.name))
- .map(f => new IntegrationFile(f.name, f.code));
- const openApiFile = files.filter(f => f.name === OPENAPI_FILE_NAME_JSON)?.at(0);
- const openApiJson = openApiFile?.code;
- const asyncApiFile = files.filter(f => f.name === ASYNCAPI_FILE_NAME_JSON)?.at(0);
- const asyncApiJson = asyncApiFile?.code;
-
- useEffect(() => {
- onRefresh();
- }, [project]);
-
- function onRefresh() {
- if (project.projectId) {
- setFiles([]);
- setSelectedFileNames([]);
- ProjectService.refreshProjectData(project.projectId);
- setTabIndex(project.type !== ProjectType.integration ? 'files' : tab);
- }
- }
-
- function isBuildIn(): boolean {
- return BUILD_IN_PROJECTS.includes(project.projectId);
- }
-
- const buildIn = isBuildIn();
- const isTopology = tab === 'topology';
-
- return isTopology
- ? (<>
- <TopologyTab openApiJson={openApiJson}
- asyncApiJson={asyncApiJson}
- hideToolbar={false}
- files={iFiles}
- />
- <CreateIntegrationModal/>
- {showSelector && <DslSelector onDslSelect={createNewRouteFile} showFileNameInput={true}/>}
- <BeanWizard/>
- </>
- )
- : (
- <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
- {tab === 'files' && <FilesTabWithComplexity/>}
- {!buildIn && tab === "build" && <BuildTab/>}
- {/*{!buildIn && tab === "build" && config.infrastructure !== 'kubernetes' && <ImagesPanel/>}*/}
- {!buildIn && tab === 'readme' && <ReadmeTab/>}
- {!buildIn && tab === 'log' && <ProjectContainersContextProvider><ContainerLogTab/></ProjectContainersContextProvider>}
- {!buildIn && tab === 'containers' && <ProjectContainersContextProvider><ContainersTab/></ProjectContainersContextProvider>}
- </div>
- )
-}
-
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectTitle.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/ProjectTitle.tsx
deleted file mode 100644
index ae1eb011..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/ProjectTitle.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 {ClipboardCopy, Content, Flex, FlexItem,} from '@patternfly/react-core';
-import './ProjectPage.css';
-import {useFileStore, useProjectStore} from "@stores/ProjectStore";
-import {shallow} from "zustand/shallow";
-
-export function ProjectTitle() {
-
- const [project, tabIndex, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex], shallow);
- const [file, setFile, operation] = useFileStore((s) => [s.file, s.setFile, s.operation], shallow);
-
- const isFile = file !== undefined && operation !== 'delete';
- const isLog = file !== undefined && file.name.endsWith("log");
- const filename = file ? file.name.substring(0, file.name.lastIndexOf('.')) : "";
-
- function getProjectTitle() {
- return (
- <Flex direction={{default: "column"}} gap={{default: 'gapNone'}}>
- <FlexItem>
- <Content component="h3">{project?.name}</Content>
- </FlexItem>
- <FlexItem>
- <ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact">
- {project?.projectId}
- </ClipboardCopy>
- </FlexItem>
- </Flex>
- )
- }
-
- function getFileTitle() {
- return (isFile ?
- <Flex direction={{default: "column"}} gap={{default: 'gapNone'}}>
- <FlexItem>
- <Content component="h3">{project?.name}</Content>
- </FlexItem>
- <FlexItem>
- <ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact">
- {isLog ? filename : file.name}
- </ClipboardCopy>
- </FlexItem>
- </Flex>
- : <></>
- )
- }
-
- return (
- <div className="dsl-title project-title">
- {isFile && getFileTitle()}
- {!isFile && getProjectTitle()}
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/RenameFileModal.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/RenameFileModal.tsx
deleted file mode 100644
index 160382e3..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/RenameFileModal.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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, {useEffect} from 'react';
-import {Button, Form, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant} from '@patternfly/react-core';
-import {useFileStore, useProjectStore} from "@stores/ProjectStore";
-import {RESERVED_WORDS} from "@models/ProjectModels";
-import {shallow} from "zustand/shallow";
-import {SubmitHandler, useForm} from "react-hook-form";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
-import {isValidFileName} from "@util/StringUtils";
-import {useFormUtil} from "@util/useFormUtil";
-import {KaravanApi} from "@api/KaravanApi";
-
-type FormValues = {
- newName: string;
-};
-
-interface RenameFileModalProps {
- show: boolean,
- onRename: () => void
- onClose: () => void
-}
-
-export function RenameFileModal({show, onClose, onRename}: RenameFileModalProps) {
-
- const [project] = useProjectStore((s) => [s.project], shallow);
- const [file] = useFileStore((s) => [s.file], shallow);
- const formContext = useForm<FormValues>({
- mode: "onChange",
- defaultValues: { newName: file?.name },
- });
- const {getTextField} = useFormUtil(formContext);
- const {
- register,
- handleSubmit,
- formState: { errors, isSubmitting },
- reset,
- } = formContext;
-
- useEffect(() => {
- reset({ newName: file?.name || "" });
- }, [file, reset]);
-
- function closeModal() {
- onClose();
- }
-
- const onSubmit: SubmitHandler<FormValues> = (data) => {
- if (file) {
- KaravanApi.renameProjectFile(project.projectId, file?.name, data.newName, (result: boolean, err?: Error | undefined) => {
- if (result) {
- onRename();
- } else {
- EventBus.sendAlert("Error", err?.message ?? "Error copying file!", "warning");
- }
- })
- }
- }
-
- function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {
- if (event.key === 'Enter') {
- event.preventDefault();
- event.stopPropagation();
- handleSubmit(onSubmit)();
- }
- }
-
- return (
- <Modal
- variant={ModalVariant.small}
- isOpen={show}
- onClose={closeModal}
- onKeyDown={onKeyDown}
- >
- <ModalHeader title='Rename file'/>
- <ModalBody>
- <Form autoComplete="off" isHorizontal className="create-file-form">
- {getTextField('newName', 'Name', {
- regex: v => isValidFileName(v) || 'Not a valid filename',
- length: v => v.length > 5 || 'File name should be longer that 5 characters',
- name: v => !(RESERVED_WORDS.concat(file?.name ?? '')).includes(v) || "Reserved word",
- })}
- </Form>
- </ModalBody>
- <ModalFooter>
- <Button key="confirm" variant="primary" onClick={handleSubmit(onSubmit)}
- isDisabled={Object.getOwnPropertyNames(errors).length > 0}
- >
- Save
- </Button>
- <Button key="cancel" variant="secondary" onClick={closeModal}>Cancel</Button>
- </ModalFooter>
- </Modal>
- )
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanFilesDropdown.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanFilesDropdown.tsx
deleted file mode 100644
index 11abdffe..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanFilesDropdown.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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, {useState} from 'react';
-import {Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement} from '@patternfly/react-core';
-import {shallow} from "zustand/shallow";
-import EllipsisVIcon from "@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon";
-import {useFilesStore} from "@stores/ProjectStore";
-
-const CAMEL_YAML_EXT = ".camel.yaml";
-
-interface Props {
- onSelect: (filename: string, event?: React.MouseEvent<Element, MouseEvent>) => void;
-}
-
-export function BeanFilesDropdown(props: Props) {
-
- const [files] = useFilesStore((s) => [s.files], shallow);
- const [isOpenDropdown, setIsOpenDropdown] = useState<boolean>(false);
-
- function onMenuToggleClick() {
- setIsOpenDropdown(!isOpenDropdown)
- }
-
- function getToggle(toggleRef: React.Ref<MenuToggleElement>) {
- return (
- <MenuToggle className="bean-wizard-toggle"
- id={'popoverId'}
- ref={toggleRef}
- aria-label="placeholder menu"
- variant="default"
- onClick={() => onMenuToggleClick()}
- isExpanded={isOpenDropdown}
- >
- <EllipsisVIcon/>
- </MenuToggle>
- )
- }
-
- const camelYamlFiles = files.filter(f => f.name.endsWith(CAMEL_YAML_EXT)).map(f => f.name);
-
- return (
- (files && files.length > 0 ) ?
- <Dropdown
- popperProps={{position: "end"}}
- isOpen={isOpenDropdown}
- onSelect={(e, value) => {
- if (value) {
- props.onSelect(value?.toString().replace(CAMEL_YAML_EXT, ''), e);
- }
- setIsOpenDropdown(false);
- }}
- onOpenChange={(isOpen: boolean) => setIsOpenDropdown(isOpen)}
- toggle={(toggleRef: React.Ref<MenuToggleElement>) => getToggle(toggleRef)}
- shouldFocusToggleOnSelect
- >
- <DropdownList>
- {camelYamlFiles.map((pp, index) =>
- <DropdownItem value={pp} key={index}>{pp}</DropdownItem>
- )}
- </DropdownList>
- </Dropdown>
- : <></>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanWizard.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanWizard.tsx
deleted file mode 100644
index 59a783ad..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/beans/BeanWizard.tsx
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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, {useEffect, useMemo, useState} from 'react';
-import {
- Alert,
- capitalize,
- Content,
- Flex,
- Form,
- FormAlert,
- FormGroup,
- InputGroup,
- InputGroupItem,
- Modal,
- ModalBody,
- ModalHeader,
- ModalVariant,
- Radio,
- TextInput,
- Wizard,
- WizardStep
-} from '@patternfly/react-core';
-import {KaravanApi} from "@api/KaravanApi";
-import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
-import {CodeUtils} from "@util/CodeUtils";
-import {ProjectFile} from "@models/ProjectModels";
-import {useFilesStore, useFileStore, useProjectStore, useWizardStore} from "@stores/ProjectStore";
-import {shallow} from "zustand/shallow";
-import {ProjectService} from "@services/ProjectService";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
-import {Integration} from "@karavan-core/model/IntegrationDefinition";
-import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {BeanFilesDropdown} from "./BeanFilesDropdown";
-import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
-
-const CAMEL_YAML_EXT = ".camel.yaml";
-const EMPTY_BEAN = "empty";
-const BEAN_TEMPLATE_SUFFIX_FILENAME = "-bean-template.camel.yaml";
-
-export function BeanWizard() {
-
-
- const [project] = useProjectStore((s) => [s.project], shallow);
- const [setFile, designerTab] = useFileStore((s) => [s.setFile, s.designerTab], shallow);
- const [files] = useFilesStore((s) => [s.files], shallow);
- const [showWizard, setShowWizard] = useWizardStore((s) => [s.showWizard, s.setShowWizard], shallow)
- const [templateFiles, setTemplateFiles] = useState<ProjectFile[]>([]);
- const [templateNames, setTemplateNames] = useState<string[]>([]);
- const [templateName, setTemplateName] = useState<string>('');
- const [templateBeanName, setTemplateBeanName] = useState<string>('');
- const [bean, setBean] = useState<BeanFactoryDefinition | undefined>();
- const [filename, setFilename] = useState<string>('');
- const [backendError, setBackendError] = React.useState<string>();
-
- function handleOnFormSubmitSuccess(file: ProjectFile) {
- const message = "File successfully created.";
- EventBus.sendAlert("Success", message, "success");
- ProjectService.refreshProjectData(file.projectId);
- setFile('select', file, designerTab);
- setShowWizard(false);
- }
-
- function handleFormSubmit() {
- const file = files.filter(f=> f.name === (filename + CAMEL_YAML_EXT)).at(0);
- if (file && bean !== undefined) {
- const i = CamelDefinitionYaml.yamlToIntegration(file.name, file.code);
- const i2 = CamelDefinitionApiExt.addBeanToIntegration(i, bean);
- const file2 = {...file} as ProjectFile;
- file2.code = CamelDefinitionYaml.integrationToYaml(i2);
- ProjectService.updateFile(file2, false);
- handleOnFormSubmitSuccess(file2);
- } else {
- let code = '{}';
- if (bean !== undefined && templateName !== EMPTY_BEAN) {
- const i = Integration.createNew("temp");
- const i2 = CamelDefinitionApiExt.addBeanToIntegration(i, bean);
- code = CamelDefinitionYaml.integrationToYaml(i2);
- }
- const fullFileName = filename + CAMEL_YAML_EXT;
- const file = new ProjectFile(fullFileName, project.projectId, code, Date.now());
- KaravanApi.saveProjectFile(file, (result, file) => {
- if (result) {
- handleOnFormSubmitSuccess(file);
- } else {
- setBackendError(file?.response?.data);
- }
- })
- }
- }
-
- useEffect(() => {
- if (showWizard) {
- setBackendError(undefined);
- setFilename('')
- setTemplateName('');
- setTemplateBeanName('');
- setBean(undefined);
- KaravanApi.getBeanTemplatesFiles(files => {
- const templateNames = files.map(file => file.name.replace(BEAN_TEMPLATE_SUFFIX_FILENAME, ''));
- setTemplateFiles(prevState => {
- return [...files];
- });
- setTemplateNames(prevState => {
- return [...templateNames];
- });
- });
- }
- }, [showWizard]);
-
- useEffect(() => {
- getBeans.filter(b => b.name === templateBeanName).forEach(b => {
- setBean(new BeanFactoryDefinition({...b}))
- });
- }, [templateBeanName]);
-
-
- function getBeanFactoryDefinitions(): BeanFactoryDefinition[] {
- const fs = templateFiles
- .filter(f => f.name === templateName.concat(BEAN_TEMPLATE_SUFFIX_FILENAME));
- return CodeUtils.getBeans(fs);
- }
-
- const getBeans = useMemo(() => getBeanFactoryDefinitions(), [templateName]);
-
- return (
- <Modal onClose={_ => setShowWizard(false)}
- variant={ModalVariant.medium} isOpen={showWizard} onEscapePress={() => setShowWizard(false)}>
- <ModalHeader title="Bean Wizard"/>
- <ModalBody>
- <Wizard className="bean-wizard" height={600} onClose={() => setShowWizard(false)} onSubmit={event => handleFormSubmit()}>
- <WizardStep name={"Type"} id="type"
- footer={{isNextDisabled: !templateNames.includes(templateName) && templateName !== EMPTY_BEAN}}
- >
- <Flex direction={{default: "column"}} gap={{default: 'gapLg'}}>
- <Radio key={EMPTY_BEAN} id={EMPTY_BEAN} label={capitalize(EMPTY_BEAN)} name={EMPTY_BEAN}
- isChecked={EMPTY_BEAN === templateName} onChange={_ => setTemplateName(EMPTY_BEAN)}/>
- {templateNames.map(n => <Radio key={n} id={n} label={capitalize(n)} name={n}
- isChecked={n === templateName}
- onChange={_ => setTemplateName(n)}/>)}
- </Flex>
- </WizardStep>
- <WizardStep name={"Template"} id="template"
- isHidden={templateName === EMPTY_BEAN}
- isDisabled={templateName.length === 0}
- footer={{isNextDisabled: !getBeans.map(b => b.name).includes(templateBeanName)}}
- >
- <Flex direction={{default: "column"}} gap={{default: 'gapLg'}}>
- {getBeans.map(b => <Radio key={b.name} id={b.name} label={b.name} name={b.name}
- isChecked={b.name === templateBeanName}
- onChange={_ => setTemplateBeanName(b.name)}/>)}
- </Flex>
- </WizardStep>
- <WizardStep name="Properties" id="properties"
- isHidden={templateName === EMPTY_BEAN}
- isDisabled={templateName.length == 0 || templateBeanName.length == 0}
- >
- <Form autoComplete="off">
- <FormGroup key={"beanName"} label={"Name"} fieldId={"beanName"}>
- <TextInput
- value={bean?.name}
- id={"beanName"}
- aria-describedby={'beanName'}
- onChange={(_, value) => {
- const b = new BeanFactoryDefinition({...bean});
- b.name = value;
- setBean(b);
- }}
- />
- </FormGroup>
- <FormGroup label="Properties:" fieldId="properties"/>
- {getBeans.filter(b => b.name === templateBeanName).map(b => (
- <div key={b.name}>
- {Object.getOwnPropertyNames(b.properties).map(prop => (
- <FormGroup key={prop} label={prop} fieldId={prop}>
- <TextInput
- value={bean?.properties[prop] || ''}
- id={prop}
- aria-describedby={prop}
- onChange={(_, value) => {
- const b = new BeanFactoryDefinition({...bean});
- b.properties[prop] = value;
- setBean(b);
- }}
- />
- </FormGroup>
- ))}
- </div>
- ))}
- </Form>
- </WizardStep>
- <WizardStep name={"File"} id={"file"}
- footer={{nextButtonText: 'Save', onNext: event => handleFormSubmit()}}
- isDisabled={(templateName.length === 0 || templateBeanName.length === 0) && templateName !== EMPTY_BEAN}
- >
- <Form autoComplete="off">
- <FormGroup label="Filename" fieldId="filename" isRequired>
- <InputGroup>
- <InputGroupItem isFill>
- <TextInput className="text-field" type="text" id="filename"
- aria-label="filename"
- value={filename}
- customIcon={<Content component="p">{CAMEL_YAML_EXT}</Content>}
- onChange={(e, value) => {
- setFilename(value);
- }}
- />
- </InputGroupItem>
- {templateName !== EMPTY_BEAN && <InputGroupItem>
- <BeanFilesDropdown
- onSelect={(fn, event) => {
- setFilename(fn);
- }}
- />
- </InputGroupItem>}
- </InputGroup>
- {backendError &&
- <FormAlert>
- <Alert variant="danger" title={backendError} aria-live="polite" isInline/>
- </FormAlert>
- }
- </FormGroup>
- </Form>
- </WizardStep>
- </Wizard>
- </ModalBody>
- </Modal>
- )
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/CodeStore.ts b/karavan-app/src/main/webui/src/karavan/features/integration/designer/CodeStore.ts
deleted file mode 100644
index 78e88133..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/CodeStore.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import {createWithEqualityFn} from "zustand/traditional";
-import {shallow} from "zustand/shallow";
-
-interface CodeState {
- code: string;
- setCode: (code: string) => void;
-}
-
-export const useCodeStore = createWithEqualityFn<CodeState>((set) => ({
- code: '',
- setCode: (code: string) => {
- set({code: code});
- },
-}), shallow)
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/DesignerStore.ts b/karavan-app/src/main/webui/src/karavan/features/integration/designer/DesignerStore.ts
deleted file mode 100644
index d940206d..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/DesignerStore.ts
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * 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 {CamelElement, Integration, IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
-import {DslPosition, EventBus} from "./utils/EventBus";
-import {createWithEqualityFn} from "zustand/traditional";
-import {shallow} from "zustand/shallow";
-import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
-import {DslMetaModel} from "@features/integration/designer/utils/DslMetaModel";
-
-interface IntegrationState {
- integration: Integration;
- json: string;
- setIntegration: (integration: Integration, propertyOnly: boolean) => void;
- propertyOnly: boolean;
- reset: () => void;
- files: IntegrationFile []
- setFiles: (files: IntegrationFile []) => void
- resetFiles: (files: IntegrationFile []) => void
- variables: string[],
- setVariables: (variables: string[]) => void;
- key: string;
- setKey: (key: string) => void;
-}
-
-export const useIntegrationStore = createWithEqualityFn<IntegrationState>((set, get) => ({
- integration: Integration.createNew("demo", "plain"),
- propertyOnly: false,
- json: '{}',
- key: '',
- setIntegration: (integration: Integration, propertyOnly: boolean) => {
- set((state: IntegrationState) => {
- const json = JSON.stringify(integration);
- if (state.json === json) {
- return {integration: state.integration, propertyOnly: state.propertyOnly, json: state.json};
- } else {
- EventBus.sendIntegrationUpdate(integration, propertyOnly);
- return {integration: integration, propertyOnly: propertyOnly, json: json};
- }
- })
- },
- reset: () => {
- set({integration: Integration.createNew("demo", "plain"), json: '{}', propertyOnly: false});
- },
- files: [],
- setFiles: (files: IntegrationFile []) => {
- set((state: IntegrationState) => {
- return {files: files};
- });
- },
- resetFiles: (files: IntegrationFile []) => {
- set((state: IntegrationState) => {
- return {files: [...files]};
- });
- },
- variables: [],
- setVariables: (variables: string[]) => {
- set((state: IntegrationState) => {
- return {variables: [...variables]};
- })
- },
- setKey: (key: string) => {
- set({key: key});
- },
-}), shallow)
-
-
-interface SelectorStateState {
- showSelector: boolean;
- setShowSelector: (showSelector: boolean) => void;
- showProperties: boolean;
- setShowProperties: (showProperties: boolean) => void;
- selectedDsl?: DslMetaModel;
- setSelectedDsl: (selectedDsl?: DslMetaModel) => void;
- showSteps: boolean;
- setShowSteps: (showSteps: boolean) => void;
- parentDsl?: string;
- setParentDsl: (parentDsl?: string) => void;
- parentId: string;
- setParentId: (parentId: string) => void;
- selectorTabIndex?: string | number
- setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
- selectedPosition?: number;
- setSelectedPosition: (selectedPosition?: number) => void;
- selectedToggles: string [];
- addSelectedToggle: (label: string) => void;
- deleteSelectedToggle: (label: string) => void;
- routeId?: string;
- setRouteId: (routeId: string) => void;
- isRouteTemplate?: boolean;
- setIsRouteTemplate: (isRouteTemplate: boolean) => void;
-}
-
-export const useSelectorStore = createWithEqualityFn<SelectorStateState>((set) => ({
- showSelector: false,
- showProperties: false,
- deleteMessage: '',
- parentId: '',
- showSteps: true,
- isRouteTemplate: false,
- selectedToggles: ['eip', 'components', 'kamelets'],
- addSelectedToggle: (toggle: string) => {
- set(state => ({
- selectedToggles: [...state.selectedToggles, toggle]
- }))
- },
- deleteSelectedToggle: (toggle: string) => {
- set(state => ({
- selectedToggles: [...state.selectedToggles.filter(x => x !== toggle)]
- }))
- },
- setSelectorTabIndex: (selectorTabIndex?: string | number) => {
- set({selectorTabIndex: selectorTabIndex})
- },
- setParentDsl: (parentDsl?: string) => {
- set({parentDsl: parentDsl})
- },
- setSelectedDsl: (selectedDsl?: DslMetaModel) => {
- set(state => ({
- selectedDsl: selectedDsl,
- showProperties: selectedDsl ? state.showProperties : false
- }))
- },
- setShowSelector: (showSelector: boolean) => {
- set({showSelector: showSelector})
- },
- setShowProperties: (showProperties: boolean) => {
- set({showProperties: showProperties})
- },
- setShowSteps: (showSteps: boolean) => {
- set({showSteps: showSteps})
- },
- setParentId: (parentId: string) => {
- set({parentId: parentId})
- },
- setSelectedPosition: (selectedPosition?: number) => {
- set({selectedPosition: selectedPosition})
- },
- setRouteId: (routeId: string) => {
- set({routeId: routeId})
- },
- setIsRouteTemplate: (isRouteTemplate: boolean) => {
- set({isRouteTemplate: isRouteTemplate})
- },
-}), shallow)
-
-
-interface ConnectionsState {
- steps: Map<string, DslPosition>;
- addStep: (uuid: string, position: DslPosition) => void;
- deleteStep: (uuid: string) => void;
- clearSteps: () => void;
- setSteps: (steps: Map<string, DslPosition>) => void;
-}
-
-export const useConnectionsStore = createWithEqualityFn<ConnectionsState>((set) => ({
- steps: new Map<string, DslPosition>(),
- addStep: (uuid: string, position: DslPosition) => {
- set(state => ({
- steps: new Map(state.steps).set(uuid, position),
- }))
- },
- deleteStep: (uuid: string) => {
- set((state: ConnectionsState) => {
- // state.steps.clear();
- Array.from(state.steps.entries())
- .filter(value => value[1]?.parent?.uuid !== uuid)
- .filter(value => value[1]?.prevStep?.uuid !== uuid)
- .filter(value => value[1]?.nextstep?.uuid !== uuid)
- .forEach(value => state.steps.set(value[0], value[1]));
- state.steps.delete(uuid)
- return state;
- })
- },
- clearSteps: () => {
- set((state: ConnectionsState) => {
- state.steps.clear();
- return state;
- })
- },
- setSteps: (steps: Map<string, DslPosition>) => {
- set({steps: steps})
- }
-}), shallow)
-
-type DesignerState = {
- designerSwitch: boolean
- isDebugging: boolean
- notificationBadge: boolean
- notificationMessage: [string, string]
- shiftKeyPressed: boolean
- showDeleteConfirmation: boolean
- showMoveConfirmation: boolean
- deleteMessage: string
- selectedStep?: CamelElement
- selectedUuids: string[]
- passedNodeIds: string[]
- passedRouteId?: string
- failedRouteId?: string
- suspendedNodeId?: string
- failed: boolean
- clipboardSteps: CamelElement[]
- width: number
- height: number
- top: number
- left: number
- moveElements: [string | undefined, string | undefined]
- propertyPlaceholders: [string, string][]
- parameterPlaceholders: [string, string][], // route template parameters
- beans: BeanFactoryDefinition[],
- tab?: "routes" | "rest" | "beans" | "kamelet",
- stepDoubleClicked: boolean,
-}
-
-const designerState: DesignerState = {
- designerSwitch: true,
- isDebugging: false,
- notificationBadge: false,
- notificationMessage: ['', ''],
- shiftKeyPressed: false,
- showDeleteConfirmation: false,
- showMoveConfirmation: false,
- deleteMessage: '',
- selectedUuids: [],
- passedNodeIds: [],
- passedRouteId: undefined,
- failedRouteId: undefined,
- suspendedNodeId: undefined,
- failed: false,
- clipboardSteps: [],
- width: 0,
- height: 0,
- top: 0,
- left: 0,
- moveElements: [undefined, undefined],
- propertyPlaceholders: [],
- parameterPlaceholders: [],
- beans: [],
- stepDoubleClicked: false,
-};
-
-type DesignerAction = {
- setDebugging: (isDebugging: boolean) => void;
- setShiftKeyPressed: (shiftKeyPressed: boolean) => void;
- setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => void;
- setShowMoveConfirmation: (showMoveConfirmation: boolean) => void;
- setDeleteMessage: (deleteMessage: string) => void;
- setSelectedStep: (selectedStep?: CamelElement) => void;
- setSelectedUuids: (selectedUuids: string[]) => void;
- setPassedNodeIds: (passedNodeIds: string[]) => void;
- setPassedRouteId: (passedRouteId?: string) => void;
- setFailedRouteId: (failedRouteId?: string) => void;
- setSuspendedNodeId: (suspendedNodeId?: string) => void;
- setFailed: (failed: boolean) => void;
- setClipboardSteps: (clipboardSteps: CamelElement[]) => void;
- setPosition: (width: number, height: number, top: number, left: number) => void;
- reset: () => void;
- setNotification: (notificationBadge: boolean, notificationMessage: [string, string]) => void;
- setMoveElements: (moveElements: [string | undefined, string | undefined]) => void;
- setPropertyPlaceholders: (propertyPlaceholders: [string, string][]) => void;
- setParameterPlaceholders: (parameterPlaceholders: [string, string][]) => void;
- setBeans: (beans: BeanFactoryDefinition[]) => void;
- setTab: (tab?: "routes" | "rest" | "beans" | "kamelet") => void;
- setDesignerSwitch: (designerSwitch: boolean) => void;
- setStepDoubleClicked: (stepDoubleClicked: boolean) => void;
-}
-
-export const useDesignerStore = createWithEqualityFn<DesignerState & DesignerAction>((set) => ({
- ...designerState,
- setDebugging: (isDebugging: boolean) => {
- set({isDebugging: isDebugging})
- },
- setFailed: (failed: boolean) => {
- set({failed: failed})
- },
- setShiftKeyPressed: (shiftKeyPressed: boolean) => {
- set({shiftKeyPressed: shiftKeyPressed})
- },
- setSelectedStep: (selectedStep?: CamelElement) => {
- set({selectedStep: selectedStep})
- },
- setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => {
- set({showDeleteConfirmation: showDeleteConfirmation})
- },
- setShowMoveConfirmation: (showMoveConfirmation: boolean) => {
- set({showMoveConfirmation: showMoveConfirmation})
- },
- setDeleteMessage: (deleteMessage: string) => {
- set({deleteMessage: deleteMessage})
- },
- setSelectedUuids: (selectedUuids: string[]) => {
- set((state: DesignerState) => {
- state.selectedUuids.length = 0;
- state.selectedUuids.push(...selectedUuids);
- return state;
- })
- },
- setPassedNodeIds: (passedNodeIds: string[]) => {
- set((state: DesignerState) => {
- state.passedNodeIds.length = 0;
- state.passedNodeIds.push(...passedNodeIds);
- return state;
- })
- },
- setPassedRouteId: (passedRouteId?: string) => {
- set({passedRouteId: passedRouteId})
- },
- setFailedRouteId: (failedRouteId?: string) => {
- set({failedRouteId: failedRouteId})
- },
- setSuspendedNodeId: (suspendedNodeId?: string) => {
- set({suspendedNodeId: suspendedNodeId})
- },
- setClipboardSteps: (clipboardSteps: CamelElement[]) => {
- set((state: DesignerState) => {
- state.clipboardSteps.length = 0;
- state.clipboardSteps.push(...clipboardSteps);
- return state;
- })
- },
- width: 100,
- height: 100,
- top: 0,
- left: 0,
- setPosition: (width: number, height: number, top: number, left: number) => {
- set({width: width, height: height, top: top, left: left})
- },
- reset: () => {
- set(state => {
- designerState.designerSwitch = state.designerSwitch;
- return designerState;
- });
- },
- setNotification: (notificationBadge: boolean, notificationMessage: [string, string]) => {
- set({notificationBadge: notificationBadge, notificationMessage: notificationMessage})
- },
- setMoveElements: (moveElements: [string | undefined, string | undefined]) => {
- set({moveElements: moveElements})
- },
- setPropertyPlaceholders: (propertyPlaceholders: [string, string][]) => {
- set((state: DesignerState) => {
- state.propertyPlaceholders.length = 0;
- state.propertyPlaceholders.push(...propertyPlaceholders);
- return state;
- })
- },
- setParameterPlaceholders: (parameterPlaceholders: [string, string][]) => {
- set((state: DesignerState) => {
- state.parameterPlaceholders.length = 0;
- state.parameterPlaceholders.push(...parameterPlaceholders);
- return state;
- })
- },
- setBeans: (beans: BeanFactoryDefinition[]) => {
- set((state: DesignerState) => {
- return {beans: [...beans]};
- })
- },
- setTab: (tab?: "routes" | "rest" | "beans" | "kamelet") => {
- set({tab: tab})
- },
- setDesignerSwitch: (designerSwitch: boolean) => {
- set({designerSwitch: designerSwitch})
- },
- setStepDoubleClicked: (stepDoubleClicked: boolean) => {
- set({stepDoubleClicked: stepDoubleClicked})
- },
-}), shallow)
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/ErrorBoundaryWrapper.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/ErrorBoundaryWrapper.tsx
deleted file mode 100644
index 36ac98dc..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/ErrorBoundaryWrapper.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, {ReactNode} from "react";
-
-export interface ErrorBoundaryState {
- hasError: boolean;
- error: Error | null;
-}
-
-interface ErrorBoundaryProps {
- children: ReactNode;
- onError: (error: Error) => void;
-}
-
-export class ErrorBoundaryWrapper extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
- constructor(props: ErrorBoundaryProps) {
- super(props);
- this.state = { hasError: false, error: null };
- }
-
- static getDerivedStateFromError(error: Error): ErrorBoundaryState {
- return { hasError: true, error };
- }
-
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
- // Handle error (logging, etc.)
- console.error("Error caught in ErrorBoundary:", error, errorInfo);
- this.props.onError(error);
- }
-
- render() {
- if (this.state.hasError) {
- return <div style={{ color: "red" }}>Something went wrong: {this.state.error?.message}</div>;
- }
- return this.props.children;
- }
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.css
deleted file mode 100644
index eb7b3e34..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.css
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-.karavan .karavan-designer-page {
- height: 100vh;
- width: 100%;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- position: relative;
-}
-
-.karavan .karavan-designer-view-switcher {
- position: absolute;
- right: 0;
- top: 0;
- padding-right: 8px;
- z-index: 100;
-}
-
-.karavan-designer-view-switcher-dropdown button {
- padding: 0 12px 0 8px;
-}
-
-.karavan-designer-view-switcher-dropdown .pf-v6-c-menu__item-icon {
- transform: scale(0.5);
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.tsx
deleted file mode 100644
index e22e29a5..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesigner.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import './KaravanDesigner.css';
-import {RouteDesigner} from "./route/RouteDesigner";
-import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {Integration, IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {CamelUi} from "./utils/CamelUi";
-import {useDesignerStore, useIntegrationStore} from "./DesignerStore";
-import {shallow} from "zustand/shallow";
-import {InfrastructureAPI} from "./utils/InfrastructureAPI";
-import {EventBus, IntegrationUpdate} from "./utils/EventBus";
-import {RestDesigner} from "./rest/RestDesigner";
-import {BeansDesigner} from "./beans/BeansDesigner";
-import {KameletDesigner} from "./kamelet/KameletDesigner";
-import {BeanFactoryDefinition, RouteDefinition, RouteTemplateDefinition} from "@karavan-core/model/CamelDefinition";
-import {ErrorBoundaryState, ErrorBoundaryWrapper} from "./ErrorBoundaryWrapper";
-import {Panel, PanelGroup, PanelResizeHandle} from 'react-resizable-panels';
-import {MainPropertiesPanel} from "./property/MainPropertiesPanel";
-import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
-import {KaravanDesignerViewSwitch} from "@features/integration/designer/KaravanDesignerViewSwitch";
-
-interface Props {
- onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
- onSaveCustomCode: (name: string, code: string, active: boolean) => void
- onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>
- onSavePropertyPlaceholder: (key: string, value: string) => void
- onInternalConsumerClick: (uri?: string, name?: string, routeId?: string, fileName?: string) => void
- onCreateNewRoute: (componentName: string, propertyName: string, propertyValue: string) => void
- onCreateNewFile: (fileName: string, code: string, open: boolean) => void
- filename: string
- yaml: string
- showCodeTab: boolean
- tab?: "routes" | "rest" | "beans" | "kamelet"
- propertyPlaceholders: [string, string][]
- beans: BeanFactoryDefinition[]
- files: IntegrationFile[]
- mainRightPanel?: React.ReactNode
-}
-
-export function KaravanDesigner(props: Props) {
-
- const [setSelectedStep, reset, badge, message, setPropertyPlaceholders, setBeans, tab, setTab, selectedStep, setSelectedUuids, setDesignerSwitch] =
- useDesignerStore((s) =>
- [s.setSelectedStep, s.reset, s.notificationBadge, s.notificationMessage, s.setPropertyPlaceholders, s.setBeans, s.tab, s.setTab,
- s.selectedStep, s.setSelectedUuids, s.setDesignerSwitch], shallow)
- const [integration, setIntegration, resetFiles] = useIntegrationStore((s) =>
- [s.integration, s.setIntegration, s.resetFiles], shallow)
-
- useEffect(() => {
- const sub = EventBus.onIntegrationUpdate()?.subscribe((update: IntegrationUpdate) =>
- save(update.integration, update.propertyOnly));
- try {
- resetErrorBoundary();
- InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
- InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
- InfrastructureAPI.setOnSave(props.onSave);
- InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder);
- InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick);
- InfrastructureAPI.setOnCreateNewRoute(props.onCreateNewRoute);
- InfrastructureAPI.setOnCreateNewFile(props.onCreateNewFile);
-
- 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();
- setPropertyPlaceholders(props.propertyPlaceholders)
- setBeans(props.beans)
- resetFiles(props.files)
- resolveSelectedStep(i);
- } catch (e: any) {
- console.error(e)
- EventBus.sendAlert(' ' + e?.name, '' + e?.message, 'danger');
- }
- return () => {
- sub?.unsubscribe();
- setSelectedStep(undefined);
- reset();
- resetErrorBoundary();
- setIntegration(Integration.createNew("demo"), false);
- };
- }, []);
-
- function resolveSelectedStep(i: Integration) {
- try {
- if (selectedStep) {
- const step = CamelDefinitionApiExt.findElementById(i, (selectedStep as any).id)
- if (step) {
- setSelectedStep(step);
- setSelectedUuids([step?.uuid])
- }
- } else {
- const r = CamelDefinitionApiExt.getFlowsOfTypes(integration, ['RouteDefinition', 'RouteTemplateDefinition'])?.at(0);
- if (r) {
- const step = r?.dslName === 'RouteDefinition' ? (r as RouteDefinition).from : (r as RouteTemplateDefinition).route?.from;
- if (step) {
- setSelectedStep(step);
- setSelectedUuids([step?.uuid])
- }
- }
- }
- } catch (error) {
- console.error(error);
- }
- }
-
- function makeIntegration(yaml: string, filename: string): Integration {
- try {
- const type = CamelDefinitionYaml.yamlIsIntegration(yaml);
- if (yaml && type !== 'none') {
- const i = CamelDefinitionYaml.yamlToIntegration(props.filename, props.yaml)
- return i;
- } else {
- return Integration.createNew(filename, 'plain');
- }
- } catch (e) {
- console.error(e)
- EventBus.sendAlert("Error parsing YAML", (e as Error).message, 'danger')
- return Integration.createNew(filename, 'plain');
- }
- }
-
- function save(integration: Integration, propertyOnly: boolean): void {
- const code = getCode(integration);
- props.onSave(props.filename, code, propertyOnly);
- }
-
- function getCode(integration: Integration): string {
- try {
- const clone = CamelUtil.cloneIntegration(integration);
- return CamelDefinitionYaml.integrationToYaml(clone);
- } catch (e) {
- console.error(e)
- EventBus.sendAlert('Error parsing Yaml', (e as Error).message, 'danger');
- return '';
- }
- }
-
- const [state, setState] = useState<ErrorBoundaryState>({hasError: false, error: null});
-
- const resetErrorBoundary = () => {
- setState({hasError: false, error: null});
- };
-
- // Mimic `getDerivedStateFromError`
- const handleError = (error: Error) => {
- setState({hasError: true, error});
- setDesignerSwitch(false)
- }
-
- useEffect(() => {
- if (state.hasError && state.error) {
- EventBus.sendAlert(state.error.message, state.error?.stack?.toString()?.substring(0, 300) || '', 'danger');
- }
- }, [state]);
-
- function getMainPart() {
- return (
- <div className="karavan-designer-page">
- <KaravanDesignerViewSwitch/>
- <ErrorBoundaryWrapper onError={handleError}>
- {tab === 'kamelet' && <KameletDesigner/>}
- {tab === 'routes' && <RouteDesigner/>}
- {tab === 'rest' && <RestDesigner/>}
- {tab === 'beans' && <BeansDesigner/>}
- </ErrorBoundaryWrapper>
- </div>
- )
- }
-
- return (
- (tab !== 'kamelet')
- ? <PanelGroup direction="horizontal">
- <Panel minSize={10} defaultSize={70}>
- {getMainPart()}
- </Panel>
- <PanelResizeHandle className='resize-handler'/>
- <Panel minSize={10} defaultSize={30}>
- {props.mainRightPanel || <MainPropertiesPanel/>}
- </Panel>
- </PanelGroup>
- : <PanelGroup direction="horizontal">
- {getMainPart()}
- </PanelGroup>
- )
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesignerViewSwitch.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesignerViewSwitch.tsx
deleted file mode 100644
index e3350c59..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/KaravanDesignerViewSwitch.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import React from 'react';
-import {Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement} from '@patternfly/react-core';
-import EllipsisVIcon from "@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon";
-import {useDesignerStore, useIntegrationStore} from "@features/integration/designer/DesignerStore";
-import {shallow} from "zustand/shallow";
-import {getDesignerIcon} from "@features/integration/designer/icons/KaravanIcons";
-
-export function KaravanDesignerViewSwitch() {
-
- const [setSelectedStep, setTab] = useDesignerStore((s) => [s.setSelectedStep, s.setTab], shallow)
- const [integration] = useIntegrationStore((s) => [s.integration], shallow)
- const isKamelet = integration.type === 'kamelet';
-
- const [isToggleOpen, setIsToggleOpen] = React.useState(false);
-
- const onToggleClick = () => {
- setIsToggleOpen(!isToggleOpen);
- };
-
- const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, value: string | number | undefined) => {
- // eslint-disable-next-line no-console
- setIsToggleOpen(false);
- };
-
- function selectTab(tab: "routes" | "rest" | "beans" | "kamelet") {
- if (["routes", "rest", "beans", "kamelet"].includes(tab)) {
- setTab(tab);
- } else {
- setTab(undefined); // Handle unexpected values
- }
- setSelectedStep(undefined);
- }
-
- return (
- <div className="karavan-designer-view-switcher">
- <Dropdown
- onSelect={onSelect}
- popperProps={{position: 'right'}}
- toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
- <MenuToggle
- ref={toggleRef}
- onClick={onToggleClick}
- variant="plain"
- isExpanded={isToggleOpen}
- aria-label="Action list single group kebab"
- icon={<EllipsisVIcon/>}
- />
- )}
- isOpen={isToggleOpen}
- onOpenChange={(isOpen: boolean) => setIsToggleOpen(isOpen)}
- >
- <DropdownList className="karavan-designer-view-switcher-dropdown">
- {isKamelet &&
- <DropdownItem value={0} key="kamelet" icon={getDesignerIcon('kamelet')} onClick={(ev) => selectTab('kamelet')}>
- Kamelet Definitions
- </DropdownItem>
- }
- <DropdownItem value={1} key="routes" icon={getDesignerIcon('routes')} onClick={(ev) => selectTab('routes')}>
- Routes
- </DropdownItem>
- {!isKamelet &&
- <DropdownItem value={2} key="rest" icon={getDesignerIcon('rest')} onClick={(ev) => selectTab('rest')}>
- REST
- </DropdownItem>
- }
- <DropdownItem value={3} key="beans" icon={getDesignerIcon('beans')} onClick={(ev) => selectTab('beans')}>
- Beans
- </DropdownItem>
- </DropdownList>
- </Dropdown>
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeanCard.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeanCard.tsx
deleted file mode 100644
index 1400b213..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeanCard.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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, Flex, FlexItem
-} from '@patternfly/react-core';
-import './bean.css';
-import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
-import {DeleteElementIcon} from "../utils/ElementIcons";
-import {CamelElement} from "@karavan-core/model/IntegrationDefinition";
-
-interface Props {
- bean: BeanFactoryDefinition
- selectedStep?: CamelElement
- selectElement: (element: BeanFactoryDefinition) => void
- deleteElement: (element: BeanFactoryDefinition) => void
-}
-
-export function BeanCard (props: Props) {
-
- function selectElement (evt: React.MouseEvent) {
- evt.stopPropagation();
- props.selectElement(props.bean);
- }
-
- function onDelete (evt: React.MouseEvent) {
- evt.stopPropagation();
- props.deleteElement(props.bean);
- }
-
- const bean = props.bean;
- return (
- <Flex direction={{default: "row"}}
- className={props.selectedStep?.uuid === bean.uuid ? "bean-card bean-card-selected" : "bean-card bean-card-unselected"}
- onClick={e => selectElement(e)}
- >
- <FlexItem flex={{default:"flex_1"}} className="title">Bean</FlexItem>
- <FlexItem flex={{default:"flex_2"}} className="title">{bean.name}</FlexItem>
- <FlexItem flex={{default:"flex_3"}} align={{default: "alignRight"}} className="description">{bean.type}</FlexItem>
- <FlexItem>
- <Button variant="link" className="delete-button" onClick={e => onDelete(e)}>
- {DeleteElementIcon()}
- </Button>
- </FlexItem>
- </Flex>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeansDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeansDesigner.tsx
deleted file mode 100644
index 5cd1a6bf..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/BeansDesigner.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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, {useEffect} from 'react';
-import {Button, Flex, FlexItem, Gallery, GalleryItem, PageSection} from '@patternfly/react-core';
-import './bean.css';
-import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
-import {CamelUi} from "../utils/CamelUi";
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {BeanCard} from "./BeanCard";
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
-
-export function BeansDesigner() {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
- const [selectedStep, showDeleteConfirmation, setShowDeleteConfirmation, setSelectedStep, setNotification]
- = useDesignerStore((s) =>
- [s.selectedStep, s.showDeleteConfirmation, s.setShowDeleteConfirmation, s.setSelectedStep, s.setNotification], shallow)
-
- useEffect(() => {
- return () => {
- setNotification(false, ['', '']);
- }
- }, []);
-
- function onShowDeleteConfirmation(bean: BeanFactoryDefinition) {
- setSelectedStep(bean);
- setShowDeleteConfirmation(true);
- }
-
- function deleteBean() {
- const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep as BeanFactoryDefinition);
- setIntegration(i, false);
- setShowDeleteConfirmation(false);
- setSelectedStep(undefined);
- }
-
- function selectBean(bean?: BeanFactoryDefinition) {
- setSelectedStep(bean);
- }
-
- function unselectBean(evt: React.MouseEvent<HTMLDivElement, MouseEvent>) {
- if ((evt.target as any).dataset.click === 'BEANS') {
- evt.stopPropagation()
- setSelectedStep(undefined);
- }
- }
-
- function createBean() {
- const bean = new BeanFactoryDefinition();
- const clone = CamelUtil.cloneIntegration(integration);
- const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
- setIntegration(i, false);
- setSelectedStep(bean);
- }
-
- const beans = CamelUi.getBeans(integration);
- return (
- <PageSection hasBodyWrapper={false} className="bean-designer" isFilled padding={{default: 'noPadding'}}>
- <Gallery className="gallery"
- hasGutter
- maxWidths={{
- default: '100%',
- }}
- >
- {beans?.map((bean, index) => (
- <GalleryItem key={bean.uuid + index}>
- <BeanCard bean={bean}
- selectedStep={selectedStep}
- selectElement={selectBean}
- deleteElement={onShowDeleteConfirmation}
- />
- </GalleryItem>
- ))}
- <GalleryItem>
- <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentCenter"}}>
- <FlexItem>
- <Button
- variant={beans?.length === 0 ? "primary" : "secondary"}
- data-click="ADD_REST"
- icon={<PlusIcon/>}
- onClick={e => createBean()}>Create bean
- </Button>
- </FlexItem>
- </Flex>
- </GalleryItem>
- </Gallery>
- <ModalConfirmation
- isOpen={showDeleteConfirmation}
- message='Delete bean from integration?'
- btnConfirm='Delete'
- btnConfirmVariant='danger'
- onConfirm={() => deleteBean()}
- onCancel={() => setShowDeleteConfirmation(false)}
- />
- </PageSection>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/bean.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/bean.css
deleted file mode 100644
index c6a4b43b..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/beans/bean.css
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.
- */
-
-.karavan .bean-card {
- /*max-width: 800px;*/
- border-style: dashed;
- border-radius: 42px;
- border-width: 1px;
- padding: 16px 6px 16px 16px;
- margin-right: 80px;
- margin-left: 80px;
- position: relative;
-}
-
-.karavan .bean-card-unselected {
- border-color: var(--pf-t--global--color--brand--200);
- background-color: transparent;
-}
-
-.karavan .bean-card-selected {
- border-color: var(--pf-t--global--color--brand--100);
-}
-
-.karavan .bean-card .title {
- margin: auto 0 auto 0;
- font-weight: bold;
- white-space: nowrap;
-}
-
-.karavan .bean-card .description {
- margin: auto 0 auto 0;
- min-width: 200px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.karavan .bean-card .delete-button {
- position: relative;
- right: 6px;
- line-height: 1;
- border: 0;
- padding: 0;
- margin: 0;
- background: transparent;
- color: #909090;
- visibility: hidden;
- z-index: 100;
-}
-
-.karavan .bean-card:hover .delete-button {
- visibility: visible;
-}
-
-/*.karavan .bean-designer {*/
-/* display: block;*/
-/* height: 100vh;*/
-/* width: 100%;*/
-/* overflow-y: auto;*/
-/* padding-bottom: 106px;*/
-/*}*/
-
-.karavan .bean-designer .gallery {
- padding-top: 16px;
- padding-bottom: 16px;
-}
-
-.karavan .bean-designer .properties {
- padding: 10px 10px 10px 10px;
- background: transparent;
- width: 100%;
- height: 100%;
- overflow: auto;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-/*Beans*/
-.karavan .bean-designer .properties .bean-property {
- display: flex;
- flex-direction: row;
- gap: 3px;
-}
-
-.karavan .bean-designer .properties .bean-property .delete-button {
- padding: 3px;
- color: #b1b1b7;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/editor/CodeEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/editor/CodeEditor.tsx
deleted file mode 100644
index 3be551c9..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/editor/CodeEditor.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import '@shared/monaco-setup';
-import Editor from "@monaco-editor/react";
-import {shallow} from "zustand/shallow";
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
-import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-
-export function CodeEditor () {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow);
- const [setNotification, badge] = useDesignerStore((s) => [s.setNotification, s.notificationBadge], shallow)
- const [code, setCode] = useState<string>('');
-
- useEffect(() => {
- try {
- const clone = CamelUtil.cloneIntegration(integration);
- const c = CamelDefinitionYaml.integrationToYaml(clone);
- setCode(c);
- } catch (e: any) {
- const message: string = e?.message ? e.message : e.reason;
- setNotification(true, ['Error in YAML, Integration can not be saved!', message]);
- }
- return () => {
- setNotification(false, ['', '']);
- }
- }, []);
-
- function onChange(value: string | undefined) {
- if (value) {
- try {
- const i = CamelDefinitionYaml.yamlToIntegration(integration.metadata.name, value);
- setIntegration(i, false);
- setNotification(false, ['', '']);
- } catch (e: any) {
- const message: string = e?.message ? e.message : e.reason;
- setNotification(true, ['Error in YAML, Integration can not be saved!' ,message]);
- }
- }
- }
-
- return (
- <Editor
- height="100vh"
- defaultLanguage={'yaml'}
- theme={'light'}
- value={code}
- className={'code-editor'}
- defaultValue={code}
- onChange={(value, ev) => onChange(value)}
- />
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/ComponentIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/ComponentIcons.tsx
deleted file mode 100644
index 92998a43..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/ComponentIcons.tsx
+++ /dev/null
@@ -1,1833 +0,0 @@
-/*
- * 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';
-
-export function AmqpIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 116 115"
- width="32px" height="32px"
- className="icon"
- >
- <g>
- <path
- fill="#000"
- d="m.027 110.87.02-19.535c0-2.731 0-5.461.006-8.198 0-.212.033-.43.053-.729h1.405c26.904 0 53.808-.006 80.712 0 .543 0 1.087.1 1.623.153 1.803 1.875 3.565 3.797 5.414 5.626 2.989 2.949 6.044 5.825 9.046 8.747 1.06 1.034 2.041 2.154 3.108 3.187 2.133 2.068 4.307 4.096 6.441 6.157 2.551 2.465 5.082 4.943 7.627 7.421l.47.53.02.285-.02-.046-.046.013-.252.04c-.113.053-.225.113-.331.166l-.504.079c.007-.04.013-.079.02-.112-.272-.603-1.173-.67-1.67-.133-.987.02-1.975.04-2.969.066 [...]
- />
- <path
- fill="#c9cbce"
- d="M115.488 113.699c-2.538-2.471-5.076-4.956-7.627-7.422-2.14-2.06-4.314-4.088-6.441-6.156-1.067-1.033-2.04-2.153-3.108-3.187-3.008-2.929-6.063-5.805-9.045-8.747-1.849-1.829-3.611-3.744-5.414-5.626V.166c.146-.02.225-.047.245-.027.71.862 1.657.915 2.69.915 9.192-.027 18.383-.014 27.574-.014 1.299 0 1.299 0 1.299 1.279v107.232c0 .497.006.994.013 1.491 0 .384-.013.775-.02 1.16-.053.503-.113 1.007-.166 1.504z"
- />
- <path
- fill="#002485"
- d="M74.59 73.231c0 .119.006.331-.014.338-.272.039-.55.066-.822.066H1.36c-.219 0-.444.013-.663.02H.18c-.046-.259-.132-.517-.132-.775-.007-10.239-.014-20.477 0-30.715 0-.278.199-.55.305-.828.178.02.364.04.543.053.046 0 .086.013.113.053 0 .848.583.848 1.199.848h38.328c.272 0 .537-.026.908-.04v-.868l.636.04c.219.206.438.411.65.616l13.233 13.075c3.254 3.214 6.514 6.427 9.774 9.635 2.611 2.571 5.229 5.135 7.84 7.7.337.265.669.53 1.007.795z"
- />
- <path
- fill="#a1afd9"
- d="M73.582 72.435c-2.61-2.564-5.228-5.129-7.84-7.7A6480.73 6480.73 0 0 1 55.97 55.1c-4.414-4.353-8.82-8.714-13.234-13.074-.212-.212-.43-.411-.65-.616 0-5.567.014-11.14.02-16.706V0c.743.331 1.366.616 1.989.895.086.086.159.238.252.245 1.186.112 2.379.278 3.571.291 5.189.034 10.378.027 15.566.02 3.161-.006 6.322-.046 9.483-.099.325 0 .643-.219.96-.338.113.331.22.669.332 1.001.04.669.073 1.338.113 2.001-.007.159-.02.324-.027.483-.702.073-.417.623-.417.968-.014 20.304-.014 40. [...]
- />
- <path
- fill="#000"
- d="M31.987 31.536c.205.239.417.477.749.862H29.74c-9.356 0-18.707.013-28.063.013H1.43C.491 32.428.02 31.945.02 30.96c.013-9.795.027-19.589.053-29.383 0-.397.066-.795.113-1.312.662.583 1.16 1.014 1.656 1.451.146.219.265.471.45.656 2.512 2.512 5.024 5.03 7.562 7.522 1.213 1.186 2.498 2.299 3.698 3.492 2.266 2.246 4.472 4.546 6.739 6.785 1.955 1.929 3.956 3.804 5.924 5.719 1.928 1.876 3.843 3.764 5.765 5.646z"
- />
- <path
- fill="#c9cbce"
- d="M31.986 31.536c-1.921-1.882-3.836-3.77-5.765-5.646-1.968-1.915-3.976-3.79-5.924-5.718-2.266-2.24-4.48-4.54-6.74-6.786-1.205-1.193-2.49-2.306-3.697-3.492-2.538-2.492-5.05-5.01-7.56-7.522-.186-.185-.299-.437-.451-.656.642-.835 1.623-.622 2.432-.642 3.498-.08 7.004-.04 10.51-.04h16.3c1.16 0 1.247.086 1.247 1.213 0 9.211 0 18.422-.02 27.632 0 .551-.212 1.101-.318 1.657z"
- />
- </g>
- </svg>
- )
-}
-
-export function SalesforceIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- viewBox="0 0 273 191"
- width="32px" height="32px"
- className="icon"
- >
- <defs>
- <path id="a" d="M.06.5h272v190H.06z" />
- </defs>
- <g fillRule="evenodd">
- <path
- fill="#00A1E0"
- d="M113 21.3c8.78-9.14 21-14.8 34.5-14.8 18 0 33.6 10 42 24.9a58 58 0 0 1 23.7-5.05c32.4 0 58.7 26.5 58.7 59.2s-26.3 59.2-58.7 59.2c-3.96 0-7.82-.398-11.6-1.15-7.35 13.1-21.4 22-37.4 22a42.7 42.7 0 0 1-18.8-4.32c-7.45 17.5-24.8 29.8-45 29.8-21.1 0-39-13.3-45.9-32a45.1 45.1 0 0 1-9.34.972c-25.1 0-45.4-20.6-45.4-45.9 0-17 9.14-31.8 22.7-39.8a52.6 52.6 0 0 1-4.35-21c0-29.2 23.7-52.8 52.9-52.8 17.1 0 32.4 8.15 42 20.8"
- mask="url(#b)"
- />
- <path
- fill="#FFFFFE"
- d="M39.4 99.3c-.171.446.061.539.116.618.511.37 1.03.638 1.55.939 2.78 1.47 5.4 1.9 8.14 1.9 5.58 0 9.05-2.97 9.05-7.75v-.094c0-4.42-3.92-6.03-7.58-7.18l-.479-.155c-2.77-.898-5.16-1.68-5.16-3.5v-.093c0-1.56 1.4-2.71 3.56-2.71 2.4 0 5.26.799 7.09 1.81 0 0 .542.35.739-.173.107-.283 1.04-2.78 1.14-3.06.106-.293-.08-.514-.271-.628-2.1-1.28-5-2.15-8-2.15l-.557.002c-5.11 0-8.68 3.09-8.68 7.51v.095c0 4.66 3.94 6.18 7.62 7.23l.592.184c2.68.824 5 1.54 5 3.42v.094c0 1.73-1.5 [...]
- />
- <path
- fill="#FFFFFE"
- d="M162.201 67.548a13.258 13.258 0 0 0-1.559-.37 12.217 12.217 0 0 0-2.144-.166c-2.853 0-5.102.806-6.681 2.398-1.568 1.58-2.635 3.987-3.17 7.154l-.193 1.069h-3.581s-.437-.018-.529.459l-.588 3.28c-.041.314.094.51.514.508h3.486l-3.537 19.743c-.277 1.59-.594 2.898-.945 3.889-.346.978-.684 1.711-1.1 2.243-.403.515-.785.894-1.444 1.115-.544.183-1.17.267-1.856.267-.382 0-.89-.064-1.265-.139-.375-.074-.57-.158-.851-.276 0 0-.409-.156-.57.254-.131.335-1.06 2.89-1.17 3.206 [...]
- />
- </g>
- </svg>
- )
-}
-export function SlackIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127 127" width={32} height={32} className="icon">
- <g fill="none">
- <path
- fill="#E01E5A"
- d="M27.2 80c0 7.3-5.9 13.2-13.2 13.2C6.7 93.2.8 87.3.8 80c0-7.3 5.9-13.2 13.2-13.2h13.2V80zm6.6 0c0-7.3 5.9-13.2 13.2-13.2 7.3 0 13.2 5.9 13.2 13.2v33c0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V80z"
- />
- <path
- fill="#36C5F0"
- d="M47 27c-7.3 0-13.2-5.9-13.2-13.2C33.8 6.5 39.7.6 47 .6c7.3 0 13.2 5.9 13.2 13.2V27H47zm0 6.7c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H13.9C6.6 60.1.7 54.2.7 46.9c0-7.3 5.9-13.2 13.2-13.2H47z"
- />
- <path
- fill="#2EB67D"
- d="M99.9 46.9c0-7.3 5.9-13.2 13.2-13.2 7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H99.9V46.9zm-6.6 0c0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V13.8C66.9 6.5 72.8.6 80.1.6c7.3 0 13.2 5.9 13.2 13.2v33.1z"
- />
- <path
- fill="#ECB22E"
- d="M80.1 99.8c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2-7.3 0-13.2-5.9-13.2-13.2V99.8h13.2zm0-6.6c-7.3 0-13.2-5.9-13.2-13.2 0-7.3 5.9-13.2 13.2-13.2h33.1c7.3 0 13.2 5.9 13.2 13.2 0 7.3-5.9 13.2-13.2 13.2H80.1z"
- />
- </g>
- </svg>
- )
-}
-
-export function VertXIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- id="svg8"
- x={0}
- y={0}
- viewBox="0 0 114.3 114.3"
- className="icon" width="32px" height="32px">
- <style>{".st3{fill:#fff}"}</style>
- <path
- id="rect4446"
- d="M15.9 2.7h82.4c7.3 0 13.3 5.1 13.3 11.3v86.3c0 6.2-5.9 11.3-13.3 11.3H15.9c-7.3 0-13.3-5.1-13.3-11.3V14c.1-6.3 6-11.3 13.3-11.3z"
- style={{
- fill: "#782a90",
- stroke: "#782a90",
- strokeWidth: 5.383,
- strokeLinejoin: "round",
- strokeMiterlimit: 11.3386,
- }}
- />
- <path
- id="path4436"
- d="M-6.7 20.8h18.6l18.4 42.4 19.2-41.9h17.8L35.1 92.1H24.9L-6.7 20.8z"
- style={{
- fillRule: "evenodd",
- clipRule: "evenodd",
- fill: "#fff",
- }}
- />
- <circle
- id="circle4442"
- cx={42.5}
- cy={91.8}
- r={13.2}
- style={{
- fill: "#fff",
- stroke: "#782a90",
- strokeWidth: 6.3269,
- strokeLinejoin: "round",
- strokeMiterlimit: 11.3386,
- }}
- />
- <path
- d="M100.2 61.8 89.6 77.9l7.6 13.7h21.9zM96.3 21.3l-12.2 19-10.4-19H52.1L74 56.1 56.8 83.3c1.5 2.4 2.3 5.3 2.4 8.3H72l46-70.3H96.3z"
- className="st3"
- />
- </svg>
- )
-}
-
-export function SmooksIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 90 79"
- className="icon" width="32px" height="32px">
- <path fill="#FDFEFE" d="M0 0h90v79H0V0Z"/>
- <path
- fill="#795EAA"
- d="M28 9c3.944.589 6.824 1.786 10.25 3.813.871.5 1.743 1.002 2.64 1.519C43.279 16.22 43.595 17.062 44 20l1 1.938c1.13 2.332 1.575 4.515 2 7.062l3.875-.125c2.18-.07 2.18-.07 4.125.125 2 2 2 2 2.195 4.82l-.07 3.305-.055 3.32L57 43c-5.573-.76-5.573-.76-8-2.125-2.895-1.267-4.892-.44-8 .125-3.668.096-7.331.059-11 0l.063 2.875C30 47 30 47 29 49c-3.911-.674-6.871-2.543-10.25-4.563l-3.266-1.94L13 41l.95-1.875C15.01 36.979 15.775 35.388 16 33c-1.392-2.133-1.392-2.133-3-4v-2c-.957- [...]
- />
- <path
- fill="#136C2B"
- d="M47 42v3c6.26 1.163 6.26 1.163 12-1 3.253.105 4.262 1.232 6.75 3.438C68 50 68 50 68 52l-2.082.48c-5.657 1.283-5.657 1.283-9.793 5.02L55 60c-2.188 1.813-2.188 1.813-4 3l1 2.313C53 68 53 68 53 71l-15 2v-7c-5.472-1.243-5.472-1.243-10.5.438L26 68c-3.82-1.556-6.26-3.956-9-7v-2c3.62-1.316 6.096-2 10-2l.25-2.25C28 52 28 52 30.063 50c2.215-1.868 2.215-1.868 2.187-4.75L32 43c5.07-.712 9.882-1.107 15-1Z"
- />
- <path
- fill="#5D76B5"
- d="M60 10c1.437-.027 2.875-.046 4.313-.063l2.425-.035C69 10 69 10 72 11v3c3.292 1.254 5.64 2.021 9.188 1.813L84 16c2.311 2.85 3 4.314 3 8l-1.758.078c-5.37.39-9.18 1.069-13.242 4.922v6H60c-1-3-1-3 0-6-2.802-1.793-4.083-1.996-7.5-1.813C49 27 49 27 46.562 24.625 45 22 45 22 45 20l3.813-.25c3.465-.378 3.465-.378 6-2.75L56 15l3-1c.733-2.015.733-2.015 1-4Z"
- />
- <path
- fill="#E4EAE9"
- d="M57 38h1l1 7c-3.67 1.573-5.443 2.144-9.375 1.125L47 45v-3l-13 1v-2c8.909-2.395 14.505-1.369 23 2v-5Z"
- />
- <path
- fill="#D1D4E8"
- d="m44 17 1 2h8v1h-8c2.88 4.577 2.88 4.577 7 8l-5 1c-1.524-2.983-2.94-5.818-4-9l1-3Z"
- />
- <path fill="#F6F6F9" d="M30 41h4v2h-2l1 5-4 3-2-2h2l1-8Z" />
- </svg>
- )
-}
-export function DHIS2Icon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- id="Layer_1"
- viewBox="0 0 195 175"
- className="icon" width="32px" height="32px"
- data-name="Layer 1"
- >
- <defs id="defs1">
- <style id="style1">{".cls-1{fill:#0080d4}"}</style>
- </defs>
- <path
- id="path1"
- d="m189.415 56.477-82.74-53.66a19.75 19.75 0 0 0-20.33 0l-80.35 52.09a12 12 0 0 0-.25 20.63l80.54 54.94a19.39 19.39 0 0 0 20.38.25l82.75-53.65a11.87 11.87 0 0 0 0-20.59zm-91 61.45a4.29 4.29 0 0 1-3.49-.05l-77-52.49 76.71-49.78a4.76 4.76 0 0 1 3.74 0l78.91 51.15z"
- className="cls-1"
- />
- <path
- id="path2"
- d="m86.345 44.297-43.56 28.24 13.62 9.33 38.23-24.78a4.76 4.76 0 0 1 3.74 0l39.37 25.52 14-9.06-45.07-29.25a19.78 19.78 0 0 0-20.33 0z"
- className="cls-1"
- />
- <path
- id="path3"
- d="m189.415 97.937-8.62-5.59-14 9.06 10.52 6.83-78.91 51.15a4.37 4.37 0 0 1-3.49 0l-77-52.5 10-6.47-13.67-9.37-8.25 5.34a12 12 0 0 0-.25 20.63l80.54 54.92a19.36 19.36 0 0 0 20.38.24l82.74-53.65a11.87 11.87 0 0 0 0-20.59z"
- className="cls-1"
- />
- </svg>
- );
-}
-
-export function DirectIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px"
- >
- <path
- d="M25 11a5.008 5.008 0 0 0-4.899 4H11.9a5 5 0 1 0 0 2H20.1A5 5 0 1 0 25 11Zm0 8a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function SpringIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <g fill="none" fillRule="evenodd">
- <path d="M0 0h32v32H0z"></path>
- <path
- fill="#70AD51"
- d="M5.466 27.993a1.364 1.364 0 10-.087-.076l-.266-.234C1.972 24.762 0 20.597 0 15.978 0 7.168 7.168 0 15.98 0c4.48 0 8.53 1.857 11.435 4.836a14.681 14.681 0 001.7-3.015c2.036 6.118 3.233 11.26 2.795 15.31-.592 8.274-7.508 14.83-15.93 14.83a15.903 15.903 0 01-10.276-3.757l-.238-.21zm23.58-4.982c4.01-5.336 1.775-13.965-.085-19.48-1.657 3.453-5.738 6.094-9.262 6.93-3.303.788-6.226.142-9.283 1.318-6.97 2.68-6.86 10.992-3.02 12.86.002 0 .23.124.227.12 0-.002 5.644-1.122 8. [...]
- ></path>
- </g>
- </svg>
- );
-}
-
-export function QuarkusIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="-0.5 0 257 257"
- className="icon" width="32px" height="32px">
- <path
- fill="#4695EB"
- d="M213.554 0c23.418.08 42.377 19.052 42.443 42.47v171.084c-.066 23.428-19.042 42.404-42.47 42.47h-25.439l-11.661-28.318h37.127c7.774-.1 14.051-6.378 14.152-14.152V42.47c-.1-7.774-6.378-14.051-14.152-14.152H42.47c-7.774.1-14.051 6.378-14.152 14.152v171.084c.1 7.774 6.378 14.051 14.152 14.152h62.607l22.935-48.494 31.625 76.812H42.47C19.042 255.958.066 236.982 0 213.554V42.47C.066 19.042 19.042.066 42.47 0h171.084zm-43.983 139.727v45.51l-39.417-22.748 39.417-22.762zM86.453 [...]
- ></path>
- <path
- fill="#FF004A"
- d="M86.453 139.727l39.417 22.762-39.417 22.748v-45.51zm83.118-45.509l39.418 22.748-39.418 22.761V94.218zM88.595 44.987l39.417 22.748-39.417 22.761V44.987z"
- ></path>
- <path
- fill="#091313"
- d="M86.453 94.218l39.417 22.748v45.523l-39.417-22.762V94.218zm83.118 0v45.51l-39.417 22.76v-45.522l39.417-22.748zm-41.559-26.483l39.417 22.761-39.417 22.761-39.417-22.76 39.417-22.762z"
- ></path>
- </svg>
- );
-}
-
-export function DatabaseIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- className="icon" width="32px" height="32px">
- <path
- fillRule="evenodd"
- d="M12 1.25c-2.487 0-4.774.402-6.466 1.079-.844.337-1.577.758-2.112 1.264C2.886 4.1 2.5 4.744 2.5 5.5v12.987l.026.013H2.5c0 .756.386 1.4.922 1.907.535.506 1.268.927 2.112 1.264 1.692.677 3.979 1.079 6.466 1.079s4.773-.402 6.466-1.079c.844-.337 1.577-.758 2.112-1.264.536-.507.922-1.151.922-1.907h-.026l.026-.013V5.5c0-.756-.386-1.4-.922-1.907-.535-.506-1.268-.927-2.112-1.264C16.773 1.652 14.487 1.25 12 1.25zM4 5.5c0-.21.104-.487.453-.817.35-.332.899-.666 1.638-.962C7.566 3. [...]
- ></path>
- </svg>
- );
-}
-
-export function CloudIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M16 7a7.66 7.66 0 0 1 1.51.15 8 8 0 0 1 6.35 6.34l.26 1.35 1.35.24a5.5 5.5 0 0 1-1 10.92H7.5a5.5 5.5 0 0 1-1-10.92l1.34-.24.26-1.35A8 8 0 0 1 16 7m0-2a10 10 0 0 0-9.83 8.12A7.5 7.5 0 0 0 7.49 28h17a7.5 7.5 0 0 0 1.32-14.88 10 10 0 0 0-7.94-7.94A10.27 10.27 0 0 0 16 5Z"/>
- <path
- d="M0 0h32v32H0z"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function FileIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="m25.7 9.3-7-7c-.2-.2-.4-.3-.7-.3H8c-1.1 0-2 .9-2 2v24c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V10c0-.3-.1-.5-.3-.7zM18 4.4l5.6 5.6H18V4.4zM24 28H8V4h8v6c0 1.1.9 2 2 2h6v16z"/>
- <path d="M10 22h12v2H10zM10 16h12v2H10z"/>
- <path
- d="M0 0h32v32H0z"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function MessagingIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="M28 28H4a2.002 2.002 0 0 1-2-2v-5h2v5h24v-5h2v5a2.002 2.002 0 0 1-2 2Z"/>
- <path d="M7 21h18v2H7zM7 16h18v2H7zM7 11h18v2H7zM7 6h18v2H7z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function SchedulingIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="M16 30a14 14 0 1 1 14-14 14 14 0 0 1-14 14Zm0-26a12 12 0 1 0 12 12A12 12 0 0 0 16 4Z"/>
- <path d="M20.59 22 15 16.41V7h2v8.58l5 5.01L20.59 22z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function HttpIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M30 11h-5v10h2v-3h3a2.003 2.003 0 0 0 2-2v-3a2.002 2.002 0 0 0-2-2Zm-3 5v-3h3l.001 3ZM10 13h2v8h2v-8h2v-2h-6v2zM23 11h-6v2h2v8h2v-8h2v-2zM6 11v4H3v-4H1v10h2v-4h3v4h2V11H6z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function GoogleCloudIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="0 -25 256 256"
- className="icon" width="32px" height="32px">
- <path
- fill="#EA4335"
- d="m170.252 56.819 22.253-22.253 1.483-9.37C153.437-11.677 88.976-7.496 52.42 33.92 42.267 45.423 34.734 59.764 30.717 74.573l7.97-1.123 44.505-7.34 3.436-3.513c19.797-21.742 53.27-24.667 76.128-6.168l7.496.39Z"
- />
- <path
- fill="#4285F4"
- d="M224.205 73.918a100.249 100.249 0 0 0-30.217-48.722l-31.232 31.232a55.515 55.515 0 0 1 20.379 44.037v5.544c15.35 0 27.797 12.445 27.797 27.796 0 15.352-12.446 27.485-27.797 27.485h-55.671l-5.466 5.934v33.34l5.466 5.231h55.67c39.93.311 72.553-31.494 72.864-71.424a72.303 72.303 0 0 0-31.793-60.453"
- />
- <path
- fill="#34A853"
- d="M71.87 205.796h55.593V161.29H71.87a27.275 27.275 0 0 1-11.399-2.498l-7.887 2.42-22.409 22.253-1.952 7.574c12.567 9.489 27.9 14.825 43.647 14.757"
- />
- <path
- fill="#FBBC05"
- d="M71.87 61.425C31.94 61.664-.237 94.228.001 134.159a72.301 72.301 0 0 0 28.222 56.88l32.248-32.246c-13.99-6.322-20.208-22.786-13.887-36.776 6.32-13.99 22.786-20.208 36.775-13.888a27.796 27.796 0 0 1 13.887 13.888l32.248-32.248A72.224 72.224 0 0 0 71.87 61.425"
- />
- </svg>
- );
-}
-
-export function AwsIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 16 16"
- className="icon" width="32px" height="32px">
- <path
- fill="#252F3E"
- d="M4.51 7.687c0 .197.02.357.058.475.042.117.096.245.17.384a.233.233 0 0 1 .037.123c0 .053-.032.107-.1.16l-.336.224a.255.255 0 0 1-.138.048c-.054 0-.107-.026-.16-.074a1.652 1.652 0 0 1-.192-.251 4.137 4.137 0 0 1-.165-.315c-.415.491-.936.737-1.564.737-.447 0-.804-.129-1.064-.385-.261-.256-.394-.598-.394-1.025 0-.454.16-.822.484-1.1.325-.278.756-.416 1.304-.416.18 0 .367.016.564.042.197.027.4.07.612.118v-.39c0-.406-.085-.689-.25-.854-.17-.166-.458-.246-.868-.246-.186 0-.37 [...]
- />
- <g fill="#F90" fillRule="evenodd" clipRule="evenodd">
- <path
- d="M14.465 11.813c-1.75 1.297-4.294 1.986-6.481 1.986-3.065 0-5.827-1.137-7.913-3.027-.165-.15-.016-.353.18-.235 2.257 1.313 5.04 2.109 7.92 2.109 1.941 0 4.075-.406 6.039-1.239.293-.133.543.192.255.406z"/>
- <path
- d="M15.194 10.98c-.223-.287-1.479-.138-2.048-.069-.17.022-.197-.128-.043-.24 1-.705 2.645-.502 2.836-.267.192.24-.053 1.89-.99 2.68-.143.123-.281.06-.218-.1.213-.53.687-1.72.463-2.003z"/>
- </g>
- </svg>
- );
-}
-
-export function MailIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M28 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2Zm-2.2 2L16 14.78 6.2 8ZM4 24V8.91l11.43 7.91a1 1 0 0 0 1.14 0L28 8.91V24Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function IotIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M30 19h-4v-4h-2v9H8V8h9V6h-4V2h-2v4H8a2.002 2.002 0 0 0-2 2v3H2v2h4v6H2v2h4v3a2.002 2.002 0 0 0 2 2h3v4h2v-4h6v4h2v-4h3a2.003 2.003 0 0 0 2-2v-3h4Z"/>
- <path d="M21 21H11V11h10Zm-8-2h6v-6h-6ZM31 13h-2A10.012 10.012 0 0 0 19 3V1a12.013 12.013 0 0 1 12 12Z"/>
- <path d="M26 13h-2a5.006 5.006 0 0 0-5-5V6a7.008 7.008 0 0 1 7 7Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function GithubIcon() {
- return (
- <svg
- aria-hidden="true"
- data-view-component="true"
- viewBox="0 0 16 16"
- className="icon" width="32px" height="32px">
- <path
- d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45 [...]
- </svg>
- );
-}
-
-export function CassandraIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- viewBox="0 0 113.63554 58.899029"
- className="icon" width="32px" height="32px">
- <defs>
- <path id="a" d="M24.216.082v24.141H.053V.082z"/>
- </defs>
- <g
- style={{
- fill: "none",
- fillRule: "evenodd",
- stroke: "none",
- strokeWidth: 1,
- }}
- >
- <path
- fill="#bbe6fb"
- d="M90.565 20.787C91.4 30.202 76.112 39.163 56.422 40.8c-19.69 1.638-36.329-4.669-37.162-14.083C18.426 17.3 33.713 8.34 53.404 6.702c19.69-1.636 36.329 4.669 37.161 14.085"
- />
- <path
- fill="#fff"
- d="M53.334 6.75c-4.16-.255-11.326 1.915-17.302 4.08a17.762 17.762 0 0 0-1.413 6.948c0 10.096 9.154 18.28 18.837 18.28 9.62 0 18.13-8.197 18.836-18.28.23-3.283-.9-6.377-2.47-9.044-6.196-1.091-12.771-1.758-16.488-1.984"
- />
- <image
- xlinkHref="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUwAAADqCAYAAADJXHwYAAAABGdBTUEAALGOfPtRkwAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABTKADAAQAAAABAAAA6gAAAAAGjBs3AAAWs0lEQVR4Ae2d+dPctAGG+SABQkI5AyFQ7hZaekA7nbbT0v7J/bkz7bRQGGDKGaCcIRAg5CBAIBchJH3fjfxh79q78q4P2X40o3hty7b02N8T2ZLlrasIEGiIwOXLl7e0qxtCvF7Ta0K8Ovc7W1Y2XZbO6y4pXlT8Pkzzv7Nl2bTuuotbW1uXtV8CBCoJ+AInQCCKgIR4rRJaiLvDNP/by3YpDvmamhdyJt9sWiZhL3P8NsTzYXoBAYvEyMKQL+6RnYp+i5O [...]
- width={43.164}
- height={31.532}
- x={31.672}
- y={6.587}
- opacity={0.596}
- />
- <path
- fill="#373535"
- d="M42.663 16.453c.51-1.13 1.282-1.683 2.031-2.63-.083-.224-.265-.958-.265-1.212 0-1.128.928-2.056 2.056-2.056.26 0 .517.05.758.146a14.985 14.985 0 0 1 13.597-2.39c-4.45-.617-9.466.96-12.878 3.713.104.246.393.949.393 1.232 0 1.135-.735 1.411-1.87 1.411-.258 0-.504-.05-.732-.136-.771 1.035-1.715 3.006-2.178 4.239 1.887 1.687 3.592 2.299 5.813 3.13-.006-.106.076-.205.076-.312 0-3.424 3.014-6.206 6.438-6.206a6.195 6.195 0 0 1 6.105 5.158c1.53-.974 3.01-1.72 4.139-3.164-. [...]
- />
- <path
- fill="#373535"
- d="M68.25 14.909c.303.265.555.58.748.932.502.9-.503 1.724-1.533 1.724a1.846 1.846 0 0 1-.306-.031c-1.161 1.814-3.194 4.14-5 5.311 2.769.454 5.38 1.563 7.46 3.277 1.513-2.711 2.673-6.627 2.673-9.953 0-2.532-1.117-4.387-2.804-5.748-.089 1.356-.813 3.252-1.236 4.488M45.77 32.084c.922-2.549 3.192-4.524 5.34-6.26-.315-.43-.786-1.496-.982-2a15.027 15.027 0 0 1-6.733-4.261l-.044.17a13.62 13.62 0 0 0-.232 4.52 2.709 2.709 0 0 1 2.203 2.654c0 .783-.687 1.92-1.22 2.414.58 1.25. [...]
- />
- <path
- fill="#373535"
- d="M45.607 34.222c-1.1-1.094-1.862-3.277-2.576-4.648a2.707 2.707 0 0 1-.41.035c-1.494 0-3.058-1.253-2.704-2.702.196-.803.75-1.327 1.652-1.765-.206-1.662-.261-4.051.124-5.78.111-.494.345-.726.5-1.196-1.647-2.41-2.711-5.574-2.711-8.713 0-.115.005-.228.008-.342-2.783 1.396-4.87 3.595-4.87 7.058 0 7.659 4.41 15.171 10.973 18.116l.014-.062m16.138-10.588a6.196 6.196 0 0 1-5.843 4.145 6.167 6.167 0 0 1-3.826-1.327c-2.173 1.692-4.143 4.664-5.145 7.242.45.484.763.882 1.267 1.3 [...]
- />
- <path
- fill="#1287b1"
- d="M42.493 17.348a14.975 14.975 0 0 1 1.898-3.122 2.057 2.057 0 0 1-.132-.72c0-1.127.929-2.056 2.056-2.056.26 0 .517.05.758.147A14.985 14.985 0 0 1 59.46 8.879c.407.093.811.202 1.21.328-4.45-.617-9.048.747-12.46 3.5.107.253.162.525.162.799a2.066 2.066 0 0 1-2.056 2.056 2.05 2.05 0 0 1-.733-.136 13.841 13.841 0 0 0-1.863 3.412c1.62 1.746 3.61 3.127 5.83 3.957-.005-.106-.016-.21-.016-.319a6.195 6.195 0 0 1 12.303-1.04 16.065 16.065 0 0 0 4.019-3.669 1.843 1.843 0 0 1-.4 [...]
- />
- <path
- fill="#1287b1"
- d="M68.54 15.214c.394.35.62.852.622 1.38a1.876 1.876 0 0 1-1.866 1.866 1.85 1.85 0 0 1-.307-.032 15.102 15.102 0 0 1-4.506 4.533 15.09 15.09 0 0 1 7.261 3.263 18.739 18.739 0 0 0 2.379-9.16c0-2.532-1.118-4.387-2.805-5.748a15.01 15.01 0 0 1-.778 3.898M46.054 32.696a15.04 15.04 0 0 1 4.674-6.572 6.186 6.186 0 0 1-.77-1.406 15.025 15.025 0 0 1-6.733-4.26c-.013.057-.03.113-.043.17a13.593 13.593 0 0 0-.232 4.52 2.71 2.71 0 0 1 2.203 2.653c0 .754-.316 1.473-.87 1.984a16.22 [...]
- />
- <path
- fill="#1287b1"
- d="M45.6 34.192a15.07 15.07 0 0 1-2.739-3.722 2.704 2.704 0 0 1-.41.034h-.004c-1.482 0-2.7-1.219-2.7-2.7 0-1.035.594-1.983 1.526-2.432-.273-2.209-.05-4.45.651-6.561a14.95 14.95 0 0 1-2.612-8.463c0-.115.006-.228.008-.341-2.783 1.395-4.87 3.595-4.87 7.057 0 7.659 4.573 14.245 11.136 17.19l.014-.062m15.976-9.661a6.198 6.198 0 0 1-5.843 4.144 6.17 6.17 0 0 1-3.826-1.327c-2.173 1.692-3.813 3.998-4.814 6.577.45.484.929.941 1.433 1.369 1.555.404 3.154.608 4.76.607 6.617 0 12 [...]
- />
- <g transform="translate(43.304 10.642)">
- <mask id="b" fill="#fff">
- <use xlinkHref="#a"/>
- </mask>
- <path
- fill="#fff"
- d="M14.783 6.242 14.704.147l-2.251 5.43L10.576.081l.101 6.472L7.433.753l1.755 6.16-5.262-3.827 4.122 5.18-6.533-2.403 5.156 3.815-6.612.203 6.76 1.745L.053 13.09l6.68.484L1.1 17.18l5.8-2.103-4.024 5.097 5.085-4.101-1.832 6.838 3.926-5.565-.55 6.573 2.228-5.958 1.897 6.262.461-6.281 2.815 5.36-1.663-6.131 5.155 3.993-3.328-5.091 5.656 2.203-4.325-4.25 5.8.456-5.712-2.192 5.727-1.366-5.748-.293 4.678-3.575-5.309 1.903 3.608-5-4.983 3.312 1.743-5.852z"
- mask="url(#b)"
- />
- </g>
- <image
- xlinkHref="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAx4AAADpCAYAAACqReECAAAABGdBTUEAALGOfPtRkwAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAADHqADAAQAAAABAAAA6QAAAADa02YqAABAAElEQVR4Ae292XcT19ruq6qS5B4bm76zMQYSDAZ34AYSyPedMc4a5+Jc5a/M7R5f9l5NFknArYwNiUnnhU2T0BuDbdlqStrPKyQjy2qqpKpSSXpqDLBUzWx+s1Q13/l2Hg83EiABEiABEiABEqhRAn19fU1ff/21VqPdZ7dJgARIgARIgARIgARIgATsJjA4ONg4MjLSZXc9LJ8ESIAESIAESIAESIAESMABAjdv3vSiGsWBqgxX0dvb67969eoNXKAavog [...]
- width={111.814}
- height={32.542}
- x={1.822}
- y={1.682}
- opacity={0.487}
- />
- <path
- fill="#373535"
- d="M46.372 6.794c1.704-.331 2.026-4.053 2.026-4.053s.238 2.743 1.43 3.1c1.193.357 2.742-4.291 2.742-4.291s-1.43 4.172 0 4.41c1.43.238 4.053-4.053 4.053-4.053s-1.072 3.695-.358 3.933c.715.239 4.291-5.364 4.291-5.364s-2.145 3.695-.119 4.053c2.027.358 4.984-2.521 4.984-2.521s-2.325 2.634-1.289 2.998c4.412 1.55 7.98-4.183 7.98-4.183s-.827 2.514-2.972 5.256C73.788 7.27 77.24.267 77.24.267L73.788 7.27C75.576 8.224 82.728 0 82.728 0s-3.694 6.436-5.84 7.747c1.192.954 5.483-2. [...]
- />
- <path
- fill="#373535"
- d="M0 34.76c9.388 4.71 17.97-.714 28.788 2.334 8.224 2.318 18.239 5.176 31.828 3.209 13.589-1.967 25.21-7.867 30.755-18.416 1.728-4.709 8.76 1.072 8.76 1.072s-5.125-2.145-5.006-1.132c.12 1.013 7.689 4.53 7.689 4.53s-6.855-2.146-6.437-.536c.417 1.608 8.583 8.045 8.583 8.045s-9.239-7.033-10.013-6.079c-.775.953 3.933 4.828 3.933 4.828s-7.808-4.828-10.55-3.405c-1.972 1.024 8.106 7.637 8.106 7.637S89.88 31.84 88.33 33.15c-1.55 1.312 7.391 12.04 7.391 12.04S85.588 34.223 84 [...]
- />
- </g>
- </svg>
- );
-}
-
-export function ActivemqIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 30.803 44.324"
- className="icon" width="32px" height="32px">
- <defs>
- <filter
- id="a"
- width={1.068}
- height={1.046}
- x={-0.017}
- y={-0.011}
- >
- <feFlood floodColor="#000" floodOpacity={0.498} result="flood"/>
- <feComposite
- in="flood"
- in2="SourceGraphic"
- operator="in"
- result="composite1"
- />
- <feGaussianBlur in="composite1" result="blur" stdDeviation={0.2}/>
- <feOffset dx={1} dy={1} result="offset"/>
- <feComposite in="SourceGraphic" in2="offset" result="composite2"/>
- </filter>
- </defs>
- <g
- style={{
- display: "inline",
- }}
- >
- <g
- style={{
- filter: "url(#a)",
- }}
- transform="translate(-39.667 -110.707)"
- >
- <path
- d="m64.697 153.552-8.352-.05-4.133-7.257 4.218-7.208 8.352.049 4.134 7.257z"
- style={{
- fill: "#fff",
- strokeWidth: 0.394699,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- }}
- />
- <path
- d="m52.632 146.553-8.352-.049-4.133-7.257 4.218-7.209 8.352.05 4.134 7.257z"
- style={{
- display: "inline",
- fill: "#fff",
- strokeWidth: 0.394699,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- }}
- />
- <path
- d="m64.771 139.589-8.352-.05-4.133-7.257 4.218-7.208 8.352.05 4.134 7.257z"
- style={{
- display: "inline",
- fill: "#fff",
- strokeWidth: 0.394699,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- }}
- />
- <path
- d="m64.765 125.702-8.351-.049-4.134-7.257 4.219-7.209 8.352.05 4.133 7.257z"
- style={{
- display: "inline",
- fill: "#fff",
- strokeWidth: 0.394699,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- }}
- />
- <path
- d="m52.696 132.676-8.352-.049-4.133-7.257 4.218-7.209 8.352.05 4.133 7.257z"
- style={{
- display: "inline",
- fill: "#fff",
- strokeWidth: 0.394699,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- }}
- />
- </g>
- </g>
- <g
- style={{
- display: "inline",
- }}
- transform="translate(-39.667 -110.707)"
- >
- <path
- d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
- style={{
- opacity: 1,
- fill: "#c12766",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 3,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- transform="matrix(.07206 .01553 -.01553 .07206 -59.031 63.796)"
- />
- <path
- d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
- style={{
- opacity: 1,
- fill: "#3e489f",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 15,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- transform="matrix(.07206 .01553 -.01553 .07206 -71.17 70.76)"
- />
- <path
- d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
- style={{
- opacity: 1,
- fill: "#714099",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 3,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- transform="matrix(.07206 .01553 -.01553 .07206 -59.106 77.758)"
- />
- <path
- d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
- style={{
- opacity: 1,
- fill: "#78932c",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 3,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- transform="matrix(.07206 .01553 -.01553 .07206 -71.106 56.883)"
- />
- <path
- d="m1849.139 640.353-96.824 20.558-66.216-73.574 30.608-94.13 96.824-20.559 66.216 73.573z"
- style={{
- opacity: 1,
- fill: "#cf242a",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 3,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- transform="matrix(.07206 .01553 -.01553 .07206 -59.037 49.91)"
- />
- <circle
- cx={60.564}
- cy={146.294}
- r={1.6}
- style={{
- opacity: 1,
- fill: "#fff",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 0.320071,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <path
- d="m61.748 117.71-14.267 8.174M48.514 124.197l.048 16.442M47.525 138.715l14.136 8.397M60.59 117.133l.048 16.442"
- style={{
- fill: "none",
- fillRule: "evenodd",
- stroke: "#fff",
- strokeWidth: 0.523753,
- strokeLinecap: "butt",
- strokeLinejoin: "miter",
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <path
- d="m60.657 131.093.048 16.442"
- style={{
- fill: "none",
- fillRule: "evenodd",
- stroke: "#fff",
- strokeWidth: 0.5238,
- strokeLinecap: "butt",
- strokeLinejoin: "miter",
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <path
- d="m61.766 131.708-14.267 8.174M47.564 124.84l14.136 8.398"
- style={{
- fill: "none",
- fillRule: "evenodd",
- stroke: "#fff",
- strokeWidth: 0.523753,
- strokeLinecap: "butt",
- strokeLinejoin: "miter",
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <circle
- cx={48.334}
- cy={139.242}
- r={1.6}
- style={{
- opacity: 1,
- fill: "#fff",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 0.320071,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <circle
- cx={60.901}
- cy={132.486}
- r={1.6}
- style={{
- opacity: 1,
- fill: "#fff",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 0.320071,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <circle
- cx={48.563}
- cy={125.419}
- r={1.6}
- style={{
- opacity: 1,
- fill: "#fff",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 0.320071,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- <circle
- cx={60.632}
- cy={118.445}
- r={1.6}
- style={{
- opacity: 1,
- fill: "#fff",
- fillOpacity: 1,
- stroke: "none",
- strokeWidth: 0.320071,
- strokeMiterlimit: 4,
- strokeDasharray: "none",
- strokeOpacity: 1,
- }}
- />
- </g>
- </svg>
- );
-}
-
-export function KafkaIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="-78.5 0 413 413"
- className="icon" width="32px" height="32px">
- <path
- fill="#1A1919"
- d="M87.932 36.714c-4.55-4.571-10.896-7.394-17.951-7.394-7.029 0-13.326 2.823-17.822 7.394h-.13c-4.535 4.55-7.358 10.9-7.358 17.93 0 7.055 2.823 13.352 7.359 17.875l.129.102c4.496 4.55 10.793 7.346 17.822 7.346 7.055 0 13.402-2.797 17.951-7.346L88 72.52c4.558-4.523 7.354-10.82 7.354-17.876 0-7.029-2.796-13.38-7.354-17.929h-.067Zm-17.951 346.64a25.504 25.504 0 0 0 17.951-7.368l.067-.134c4.558-4.487 7.354-10.838 7.354-17.817 0-7.056-2.796-13.38-7.354-17.952h-.067c-4.55-4.625 [...]
- />
- </svg>
- );
-}
-
-export function GrapeIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- viewBox="0 0 512 512"
- className="icon" width="32px" height="32px">
- <path
- d="M438.557 512H19.785c-8.216 0-14.876-6.66-14.876-14.876V256.916c0-8.216 6.66-14.876 14.876-14.876s14.876 6.66 14.876 14.876v225.332h389.021v-32.833c0-8.216 6.661-14.876 14.876-14.876s14.876 6.66 14.876 14.876v47.709c-.001 8.216-6.662 14.876-14.877 14.876z"
- style={{
- fill: "#2d527c",
- }}
- />
- <path
- d="M19.785 177.122v-4.79L175.581 14.876v162.246zM196.154 219.435h296.061v163.65H196.154z"
- style={{
- fill: "#cee8fa",
- }}
- />
- <path
- d="M492.215 204.559h-38.782V14.876C453.433 6.66 446.772 0 438.557 0H175.581c-.182 0-.361.021-.543.027a14.949 14.949 0 0 0-2.41.269c-.018.003-.036.01-.054.013-.613.126-1.211.302-1.8.504-.158.054-.315.11-.472.171-.58.22-1.148.466-1.697.756-.024.012-.048.021-.071.034-.567.305-1.105.66-1.63 1.037a10.84 10.84 0 0 0-.403.302c-.521.402-1.026.827-1.495 1.3L9.21 161.868c-.35.353-.678.721-.988 1.104-.207.254-.388.521-.576.784-.092.131-.195.256-.283.388a15.3 15.3 0 0 0-.592.998c-.04 [...]
- style={{
- fill: "#2d527c",
- }}
- />
- <path
- d="M265.4 270.343c-3.927 0-6.153-4.188-6.153-9.031 0-4.189 1.831-8.771 6.153-8.771h22.907c4.451 0 8.902 2.095 8.902 6.285v59.298c0 22.516-14.269 30.894-31.418 30.894-18.718 0-32.857-9.949-32.857-27.36 0-7.854 3.273-9.687 10.342-9.687 5.236 0 9.687 1.309 10.078 6.153.393 5.105 1.047 13.091 11.521 13.091 7.593 0 11.913-4.188 11.913-13.091v-47.78H265.4v-.001zM304.411 339.854c0-.393.131-.916.262-1.44l24.349-79.853c1.44-4.58 7.331-6.806 13.353-6.806s11.913 2.225 13.353 6.806l2 [...]
- style={{
- fill: "#2d527c",
- }}
- />
- </svg>
- );
-}
-
-export function MachineLearningIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M27 24a2.96 2.96 0 0 0-1.285.3l-4.3-4.3H18v2h2.586l3.715 3.715A2.966 2.966 0 0 0 24 27a3 3 0 1 0 3-3Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 13a2.995 2.995 0 0 0-2.816 2H18v2h6.184A2.995 2.995 0 1 0 27 13Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 2a3.003 3.003 0 0 0-3 3 2.966 2.966 0 0 0 .348 1.373L20.596 10H18v2h3.404l4.4-4.252A2.999 2.999 0 1 0 27 2Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1Z"/>
- <path
- d="M18 6h2V4h-2a3.976 3.976 0 0 0-3 1.382A3.976 3.976 0 0 0 12 4h-1a9.01 9.01 0 0 0-9 9v6a9.01 9.01 0 0 0 9 9h1a3.976 3.976 0 0 0 3-1.382A3.976 3.976 0 0 0 18 28h2v-2h-2a2.002 2.002 0 0 1-2-2V8a2.002 2.002 0 0 1 2-2Zm-6 20h-1a7.005 7.005 0 0 1-6.92-6H6v-2H4v-4h3a3.003 3.003 0 0 0 3-3V9H8v2a1 1 0 0 1-1 1H4.08A7.005 7.005 0 0 1 11 6h1a2.002 2.002 0 0 1 2 2v4h-2v2h2v4h-2a3.003 3.003 0 0 0-3 3v2h2v-2a1 1 0 0 1 1-1h2v4a2.002 2.002 0 0 1-2 2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function TerminalIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M26 4.01H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-20a2 2 0 0 0-2-2Zm0 2v4H6v-4Zm-20 20v-14h20v14Z"/>
- <path d="m10.76 16.18 2.82 2.83-2.82 2.83 1.41 1.41 4.24-4.24-4.24-4.24-1.41 1.41z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function SapIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 1024 1024"
- className="icon" width="32px" height="32px">
- <circle
- cx={512}
- cy={512}
- r={512}
- style={{
- fill: "#007cc5",
- }}
- />
- <path
- d="M256 359.88v304.24h310.82L871 359.88zm83.62 56.58h.14c22.11 0 49.06 6.29 68.56 16.22l-21 36.64C365.92 459 355.17 458 343 457.36c-18.14-1-27.26 5.51-27.4 12.5-.18 8.52 17.13 16.23 33.45 21.47 24.7 7.85 56.1 18.33 60.9 48.7l45.15-119.36h52.45l52.88 142.91-.2-142.86H621c57.84 0 85 19.58 85 64.53 0 40.36-28 64.42-75.25 64.42h-19.56l-.19 53.69-92-.09-6.38-23.27a101.65 101.65 0 0 1-31.56 4.83 100.52 100.52 0 0 1-32.32-5.12l-9.19 23.54-51.25.16 2.3-11.84c-.73.64-1.43 1.29-2.2 [...]
- style={{
- fill: "#fff",
- }}
- />
- </svg>
- );
-}
-
-export function ScriptIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="m18.83 26 2.58-2.58L20 22l-4 4 4 4 1.42-1.41L18.83 26zM27.17 26l-2.58 2.58L26 30l4-4-4-4-1.42 1.41L27.17 26z"/>
- <path
- d="M14 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h6Zm4-23.6 5.6 5.6H18Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function ValidationIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="m22 27.18-2.59-2.59L18 26l4 4 8-8-1.41-1.41L22 27.18z"/>
- <path
- d="M15 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h7Zm3-23.6 5.6 5.6H18Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function OpenstackIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="0 -2.5 256 256"
- className="icon" width="32px" height="32px">
- <path
- fill="#DA1A32"
- d="M57.82 170.723v9.156c0 7.104 5.756 12.86 12.86 12.86h114.65c7.104 0 12.86-5.756 12.86-12.86v-9.156H256v56.051c0 13.082-10.703 23.785-23.785 23.785H23.785C10.703 250.559 0 239.856 0 226.774v-56.051h57.82Zm-.01-74.353v57.809H0v-57.81h57.81Zm198.19 0v57.809h-57.81v-57.81H256ZM232.215 0C245.297 0 256 10.703 256 23.795v56.041h-57.81V70.68c0-7.104-5.756-12.86-12.86-12.86H70.67c-7.104 0-12.86 5.756-12.86 12.86v9.156H0V23.785C0 10.703 10.703 0 23.785 0Z"
- />
- </svg>
- );
-}
-
-export function OpenshiftIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="0 -9.5 256 256"
- className="icon" width="32px" height="32px">
- <path
- fill="#DA2430"
- d="m74.84 106.893-40.869 14.87c.525 6.552 1.652 13.024 3.24 19.366l38.818-14.137c-1.244-6.552-1.689-13.32-1.18-20.1M255.444 61.702c-2.85-5.879-6.147-11.561-9.966-16.916l-40.857 14.87c4.755 4.864 8.743 10.33 12.007 16.176L255.445 61.7v.002Z"
- />
- <path
- fill="#DA2430"
- d="M182.95 61.461c-5.14-4.46-10.946-8.31-17.408-11.324h-.003C127.6 32.449 82.33 48.905 64.642 86.859a73.976 73.976 0 0 0-2.653 6.487c-2.208 6.423-3.498 12.99-3.991 19.546l-.144.054-.011.144-24.596 8.95-15.826 5.849-.007-.088-.434.158c-1.536-19.435 1.74-39.512 10.553-58.411a117.952 117.952 0 0 1 3.687-7.246c29.054-54.116 95.164-76.736 150.918-50.33a115.314 115.314 0 0 1 30.557 21.074 116.597 116.597 0 0 1 15.78 17.94L187.618 65.86a79.69 79.69 0 0 0-.635-.641l-.113.041a78.6 [...]
- />
- <path
- fill="#E82429"
- d="m19.261 193.896-.064.024A118.404 118.404 0 0 1 .939 154.347l38.825-14.14.002.003.024.125.252-.093.006.015c1.994 10.56 6.145 20.635 12.198 29.494a75.287 75.287 0 0 0 7.722 9.326l-.154.057.294.308-40.488 14.97c-.12-.171-.24-.343-.359-.516Z"
- />
- <path
- fill="#DA2430"
- d="M173.465 183.447c-21.051 13.017-48.053 15.532-72.113 4.312a75.139 75.139 0 0 1-22.118-15.695l-40.772 14.844.313.437-.02.008c11.21 16.016 26.502 29.404 45.266 38.298 40.47 19.163 86.387 12.501 119.634-13.284 14.888-11.152 27.317-26.016 35.713-44.02 8.819-18.895 12.076-38.964 10.515-58.384l-1.136.414c-.015-.208-.03-.416-.047-.624l-40.49 14.957.002.004a76.457 76.457 0 0 1-6.806 26.46c-6.315 13.753-16.164 24.708-27.94 32.273Z"
- />
- <path
- fill="#E82429"
- d="m218.552 75.13.607-.222v-.001a117.732 117.732 0 0 1 11.454 42.055l-40.773 14.834.022-.304-.77.285c1.11-15.088-2.275-30.093-9.435-43.123l38.548-14.25.002-.004c.116.243.231.486.345.73Z"
- />
- <path
- fill="#C22035"
- d="M74.89 106.654 34.31 121.65c.52 6.61 1.64 13.136 3.219 19.532l38.546-14.258c-1.247-6.622-1.695-13.438-1.169-20.274M254.227 61.083c-2.83-5.929-6.106-11.658-9.898-17.059L203.76 59.02c4.72 4.906 8.68 10.418 11.92 16.315l38.542-14.256.006.004Z"
- />
- <path
- fill="#AC223B"
- d="m34.308 121.653 40.482-14.829-.165 8.133-39.056 14.749-1.266-8.063.005.01ZM203.766 58.897l41.113-14.108 4.273 6.449-39.946 14.121-5.434-6.465-.006.003Z"
- />
- <path
- fill="#B92135"
- d="m38.764 187.201 40.53-14.749 12.258 11.565-42.503 15.956-10.283-12.776-.002.004ZM249.38 109.862l-41.165 14.844-3.032 16.478 43.892-15.643.311-15.677-.005-.002Z"
- />
- </svg>
- );
-}
-
-export function RefIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M4 20v2h4.586L2 28.586 3.414 30 10 23.414V28h2v-8H4zM30 30h-8v-8h8Zm-6-2h4v-4h-4ZM20 20h-8v-8h8Zm-6-2h4v-4h-4Z"/>
- <path d="M24 17h-2v-2h2a4 4 0 0 0 0-8H12V5h12a6 6 0 0 1 0 12ZM10 10H2V2h8ZM4 8h4V4H4Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function RedisIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- preserveAspectRatio="xMidYMid"
- viewBox="0 -18 256 256"
- className="icon" width="32px" height="32px">
- <path
- fill="#912626"
- d="M245.97 168.943c-13.662 7.121-84.434 36.22-99.501 44.075-15.067 7.856-23.437 7.78-35.34 2.09-11.902-5.69-87.216-36.112-100.783-42.597C3.566 169.271 0 166.535 0 163.951v-25.876s98.05-21.345 113.879-27.024c15.828-5.679 21.32-5.884 34.79-.95 13.472 4.936 94.018 19.468 107.331 24.344l-.006 25.51c.002 2.558-3.07 5.364-10.024 8.988"
- />
- <path
- fill="#C6302B"
- d="M245.965 143.22c-13.661 7.118-84.431 36.218-99.498 44.072-15.066 7.857-23.436 7.78-35.338 2.09-11.903-5.686-87.214-36.113-100.78-42.594-13.566-6.485-13.85-10.948-.524-16.166 13.326-5.22 88.224-34.605 104.055-40.284 15.828-5.677 21.319-5.884 34.789-.948 13.471 4.934 83.819 32.935 97.13 37.81 13.316 4.881 13.827 8.9.166 16.02"
- />
- <path
- fill="#912626"
- d="M245.97 127.074c-13.662 7.122-84.434 36.22-99.501 44.078-15.067 7.853-23.437 7.777-35.34 2.087-11.903-5.687-87.216-36.112-100.783-42.597C3.566 127.402 0 124.67 0 122.085V96.206s98.05-21.344 113.879-27.023c15.828-5.679 21.32-5.885 34.79-.95C162.142 73.168 242.688 87.697 256 92.574l-.006 25.513c.002 2.557-3.07 5.363-10.024 8.987"
- />
- <path
- fill="#C6302B"
- d="M245.965 101.351c-13.661 7.12-84.431 36.218-99.498 44.075-15.066 7.854-23.436 7.777-35.338 2.087-11.903-5.686-87.214-36.112-100.78-42.594-13.566-6.483-13.85-10.947-.524-16.167C23.151 83.535 98.05 54.148 113.88 48.47c15.828-5.678 21.319-5.884 34.789-.949 13.471 4.934 83.819 32.933 97.13 37.81 13.316 4.88 13.827 8.9.166 16.02"
- />
- <path
- fill="#912626"
- d="M245.97 83.653c-13.662 7.12-84.434 36.22-99.501 44.078-15.067 7.854-23.437 7.777-35.34 2.087-11.903-5.687-87.216-36.113-100.783-42.595C3.566 83.98 0 81.247 0 78.665v-25.88s98.05-21.343 113.879-27.021c15.828-5.68 21.32-5.884 34.79-.95C162.142 29.749 242.688 44.278 256 49.155l-.006 25.512c.002 2.555-3.07 5.361-10.024 8.986"
- />
- <path
- fill="#C6302B"
- d="M245.965 57.93c-13.661 7.12-84.431 36.22-99.498 44.074-15.066 7.854-23.436 7.777-35.338 2.09C99.227 98.404 23.915 67.98 10.35 61.497-3.217 55.015-3.5 50.55 9.825 45.331 23.151 40.113 98.05 10.73 113.88 5.05c15.828-5.679 21.319-5.883 34.789-.948 13.471 4.935 83.819 32.934 97.13 37.811 13.316 4.876 13.827 8.897.166 16.017"
- />
- <path
- fill="#FFF"
- d="m159.283 32.757-22.01 2.285-4.927 11.856-7.958-13.23-25.415-2.284 18.964-6.839-5.69-10.498 17.755 6.944 16.738-5.48-4.524 10.855 17.067 6.391M131.032 90.275 89.955 73.238l58.86-9.035-17.783 26.072M74.082 39.347c17.375 0 31.46 5.46 31.46 12.194 0 6.736-14.085 12.195-31.46 12.195s-31.46-5.46-31.46-12.195c0-6.734 14.085-12.194 31.46-12.194"
- />
- <path
- fill="#621B1C"
- d="m185.295 35.998 34.836 13.766-34.806 13.753-.03-27.52"
- />
- <path
- fill="#9A2928"
- d="m146.755 51.243 38.54-15.245.03 27.519-3.779 1.478-34.791-13.752"
- />
- </svg>
- );
-}
-
-export function SearchIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="m29 27.586-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9 9.01 9.01 0 0 1-9-9Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function BlockchainIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="M6 24H4V8h2ZM28 8h-2v16h2Zm-4-2V4H8v2Zm0 22v-2H8v2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function ChatIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M17.74 30 16 29l4-7h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h9v2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4h20a4 4 0 0 1 4 4v12a4 4 0 0 1-4 4h-4.84Z"/>
- <path d="M8 10h16v2H8zM8 16h10v2H8z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function WorkflowIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- viewBox="0 0 512 512"
- className="icon" width="32px" height="32px">
- <path
- d="M445.66 49.341H340.206L294.008 3.143c-4.192-4.191-10.99-4.191-15.183 0l-49.341 49.342c-4.192 4.192-4.192 10.99 0 15.183l46.198 46.198v38.494h-80.516c-5.929 0-10.736 4.806-10.736 10.735v21.471h-42.942v-21.471c0-5.929-4.806-10.735-10.736-10.735H66.34c-5.929 0-10.735 4.806-10.735 10.735v64.413c0 5.929 4.806 10.735 10.735 10.735h20.755v93.798c0 5.929 4.806 10.736 10.735 10.736h95.437l-10.346 10.346c-4.192 4.192-4.193 10.99 0 15.182a10.7 10.7 0 0 0 7.591 3.144c2.747 0 5.495 [...]
- </svg>
- );
-}
-
-export function WebserviceIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M25.829 13.116A10.02 10.02 0 0 0 16 5v2a8.023 8.023 0 0 1 7.865 6.493l.259 1.346 1.349.245A5.502 5.502 0 0 1 24.508 26H16v2h8.508a7.502 7.502 0 0 0 1.32-14.884ZM8 24h6v2H8zM4 24h2v2H4zM6 20h8v2H6zM2 20h2v2H2zM8 16h6v2H8zM4 16h2v2H4zM10 12h4v2h-4zM6 12h2v2H6zM12 8h2v2h-2z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function MobileIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="M23 7h4v4h-4zM23 13h4v4h-4zM17 7h4v4h-4zM17 13h4v4h-4z"/>
- <circle cx={14.5} cy={24.5} r={1.5}/>
- <path
- d="M21 30H8a2.002 2.002 0 0 1-2-2V4a2.002 2.002 0 0 1 2-2h13v2H8v24h13v-8h2v8a2.002 2.002 0 0 1-2 2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function ClusterIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M16 7a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM11 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM7 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM21 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM25 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM4 21a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 [...]
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function RpcIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path d="m14 26 1.41-1.41L7.83 17H28v-2H7.83l7.58-7.59L14 6 4 16l10 10z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function InfinispanIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- id="artwork"
- viewBox="0 0 1024 1024"
- className="icon" width="32px" height="32px">
- <defs>
- <style>{".cls-2{fill:#fff}"}</style>
- </defs>
- <path
- d="M1 1h1022v1022H1z"
- style={{
- fill: "#599fc6",
- }}
- />
- <path
- d="M566.84 512c0-221.39-179.47-400.86-400.86-400.86v109.68c160.56 0 291.18 130.62 291.18 291.18 0 221.39 179.47 400.86 400.86 400.86V803.18c-160.56 0-291.18-130.62-291.18-291.18Z"
- className="cls-2"
- />
- <path
- d="M436.76 618.86C394.05 726.69 288.82 803.18 166 803.18v109.68c134.26 0 253-66.07 325.76-167.4a432.16 432.16 0 0 1-55-126.6ZM587.24 405.14C630 297.31 735.19 220.82 858 220.82V111.14c-134.26 0-253 66.07-325.77 167.4a431.92 431.92 0 0 1 55.01 126.6Z"
- className="cls-2"
- />
- </svg>
- );
-}
-
-export function TransformationIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2ZM2 6h6v2H2zM2 2h8v2H2z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function TestingIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M28 17v5H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-5ZM18 28h-4v-4h4Z"/>
- <path
- d="M30 10V8h-2.101a4.968 4.968 0 0 0-.732-1.753l1.49-1.49-1.414-1.414-1.49 1.49A4.968 4.968 0 0 0 24 4.101V2h-2v2.101a4.968 4.968 0 0 0-1.753.732l-1.49-1.49-1.414 1.414 1.49 1.49A4.968 4.968 0 0 0 18.101 8H16v2h2.101a4.968 4.968 0 0 0 .732 1.753l-1.49 1.49 1.414 1.414 1.49-1.49a4.968 4.968 0 0 0 1.753.732V16h2v-2.101a4.968 4.968 0 0 0 1.753-.732l1.49 1.49 1.414-1.414-1.49-1.49A4.968 4.968 0 0 0 27.899 10Zm-7 2a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function ApiIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M26 22a3.86 3.86 0 0 0-2 .57l-3.09-3.1a6 6 0 0 0 0-6.94L24 9.43a3.86 3.86 0 0 0 2 .57 4 4 0 1 0-4-4 3.86 3.86 0 0 0 .57 2l-3.1 3.09a6 6 0 0 0-6.94 0L9.43 8A3.86 3.86 0 0 0 10 6a4 4 0 1 0-4 4 3.86 3.86 0 0 0 2-.57l3.09 3.1a6 6 0 0 0 0 6.94L8 22.57A3.86 3.86 0 0 0 6 22a4 4 0 1 0 4 4 3.86 3.86 0 0 0-.57-2l3.1-3.09a6 6 0 0 0 6.94 0l3.1 3.09a3.86 3.86 0 0 0-.57 2 4 4 0 1 0 4-4Zm0-18a2 2 0 1 1-2 2 2 2 0 0 1 2-2ZM4 6a2 2 0 1 1 2 2 2 2 0 0 1-2-2Zm2 22a2 2 0 1 1 2-2 2 2 0 0 1-2 [...]
- <path
- d="M0 0h32v32H0z"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function KameletIcon() {
- return (
- <svg
- className="icon" id="icon"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- >
- <path d="M16 18H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2ZM6 6v10h10V6ZM26 12v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM26 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM16 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2Z" />
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- )
-}
-
-export function CouchbaseIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width={800}
- height={800}
- viewBox="0 0 256 256"
- className="icon"
- >
- <path
- fill="#ED2226"
- d="M128 0C57.426 0 0 57.233 0 128c0 70.574 57.233 128 128 128 70.574 0 128-57.233 128-128S198.574 0 128 0Zm86.429 150.429c0 7.734-4.447 14.502-13.148 16.048-15.082 2.707-46.792 4.254-73.281 4.254-26.49 0-58.2-1.547-73.281-4.254-8.7-1.546-13.148-8.314-13.148-16.048v-49.885c0-7.734 5.994-14.888 13.148-16.049 4.447-.773 14.888-1.546 23.01-1.546 3.093 0 5.606 2.32 5.606 5.994v34.997l44.858-.967 44.858.967V88.943c0-3.674 2.514-5.994 5.608-5.994 8.12 0 18.562.773 23.009 1.546 7 [...]
- />
- </svg>
- );
-}
-
-export function TwilioIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width={800}
- height={800}
- preserveAspectRatio="xMidYMid"
- viewBox="0 0 256 256"
- className="icon"
- >
- <path
- fill="#F12E45"
- d="M128 0c70.656 0 128 57.344 128 128s-57.344 128-128 128S0 198.656 0 128 57.344 0 128 0Zm0 33.792c-52.224 0-94.208 41.984-94.208 94.208S75.776 222.208 128 222.208s94.208-41.984 94.208-94.208S180.224 33.792 128 33.792Zm31.744 99.328c14.704 0 26.624 11.92 26.624 26.624 0 14.704-11.92 26.624-26.624 26.624-14.704 0-26.624-11.92-26.624-26.624 0-14.704 11.92-26.624 26.624-26.624Zm-63.488 0c14.704 0 26.624 11.92 26.624 26.624 0 14.704-11.92 26.624-26.624 26.624-14.704 0-26.624- [...]
- />
- </svg>
- );
-}
-
-export function TwitterIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width={800}
- height={800}
- viewBox="-0.25 -104.25 1109.5 1109.5"
- className="icon"
- >
- <path
- fill="#5da8dc"
- stroke="#5da8dc"
- strokeWidth={0.5}
- d="M741 .2V0h52l19 3.8c12.667 2.467 24.167 5.7 34.5 9.7 10.334 4 20.334 8.667 30 14 9.667 5.333 18.434 10.767 26.301 16.3 7.8 5.467 14.8 11.267 21 17.4C929.933 67.4 939.5 69 952.5 66s27-7.167 42-12.5 29.834-11.333 44.5-18c14.667-6.667 23.601-10.9 26.801-12.7 3.133-1.866 4.8-2.866 5-3l.199-.3 1-.5 1-.5 1-.5 1-.5.2-.3.3-.2.301-.2.199-.3 1-.3 1-.2-.199 1.5-.301 1.5-.5 1.5-.5 1.5-.5 1-.5 1-.5 1.5c-.333 1-.666 2.333-1 4-.333 1.667-3.5 8.333-9.5 20S1051 73 1042 85s-17.066 21.06 [...]
- />
- <path
- fill="#fff"
- stroke="#fff"
- strokeWidth={0.5}
- d="M0 399V0h741v.2c0 .2-4.333.966-13 2.3-8.666 1.333-19.333 4.167-32 8.5-12.666 4.333-26.5 10.667-41.5 19s-28.333 17.833-40 28.5c-11.666 10.667-21.166 21-28.5 31-7.333 10-13.266 18.9-17.8 26.7-4.466 7.866-9.033 18.3-13.7 31.3-4.666 13-8.166 25.833-10.5 38.5-2.333 12.667-3.5 26.5-3.5 41.5s.667 26.667 2 35l2 12.5.301 1.5.199 1.5-7-.2c-4.666-.2-13.333-.966-26-2.3-12.666-1.333-31.5-4.333-56.5-9s-42.666-8.5-53-11.5c-10.333-3-28.333-9.333-54-19-25.666-9.667-49.666-20.5-72-32.5- [...]
- />
- </svg>
- );
-}
-
-export function MonitoringIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6ZM18 28h-4v-4h4Z"/>
- <path
- d="M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76 3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04-3.082 10.018A1 1 0 0 1 18 18Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function NetworkingIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- viewBox="0 0 511.984 511.984"
- className="icon" width="32px" height="32px">
- <path
- d="M207.29 287.991H48.735C30.687 287.991 16 302.375 16 320.054v111.868c0 17.679 14.688 32.063 32.735 32.063H207.29c18.031 0 32.703-14.384 32.703-32.063V320.054c0-17.679-14.672-32.063-32.703-32.063zm0 143.996-159.291-.064.736-111.932 159.259.064.048 111.645c0 .015-.192.287-.752.287z"/>
- <path
- d="M383.988 239.992H127.996c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-31.999h223.993v31.999c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c0-8.832-7.167-16-15.999-16z"/>
- <path
- d="M463.25 287.991H304.727c-18.047 0-32.735 14.384-32.735 32.063v111.868c0 17.679 14.688 32.063 32.735 32.063H463.25c18.047 0 32.735-14.384 32.735-32.063V320.054c-.001-17.679-14.688-32.063-32.735-32.063zm0 143.996-159.259-.064.736-111.932 159.259.064.064 111.645c-.016-.001-.208.287-.8.287zM415.987 479.985h-63.998c-8.832 0-16 7.168-16 16s7.168 16 16 16h63.998c8.832 0 16-7.168 16-16s-7.168-16-16-16zM335.253 0H176.73c-18.047 0-32.735 14.384-32.735 32.063v111.869c0 17.679 14. [...]
- <path
- d="M255.992 191.994c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c.001-8.832-7.167-16-15.999-16z"/>
- </svg>
- );
-}
-
-export function HealthIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- id="Icons"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <style>
- {
- ".st0{fill:none;stroke:#000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}"
- }
- </style>
- <path
- d="M27 7h0c-2.6-2.7-6.9-2.7-9.5 0l-1.3 1.4c-.1.1-.4.1-.5 0L14.4 7C11.8 4.3 7.6 4.3 5 7h0c-2.6 2.7-2.6 7.1 0 9.8l1.6 1.6 9.2 9.5c.1.1.4.1.5 0l9.2-9.5 1.6-1.6c2.6-2.7 2.6-7.1-.1-9.8z"
- className="st0"
- />
- <path d="M9 15h3l2-2 2 4 2-5 2 3h3" className="st0"/>
- </svg>
- );
-}
-
-export function KubernetesIcon(className?: string) {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 -10.44 722.846 722.846"
- className={className ? className + " icon" : "icon"}
- width="32px" height="32px">
- <path
- fill="#326ce5"
- d="M358.986 10.06a46.725 46.342 0 0 0-17.906 4.531L96.736 131.341a46.725 46.342 0 0 0-25.28 31.438l-60.282 262.25a46.725 46.342 0 0 0 6.344 35.531 46.725 46.342 0 0 0 2.656 3.688l169.125 210.28a46.725 46.342 0 0 0 36.531 17.438l271.219-.062a46.725 46.342 0 0 0 36.531-17.406l169.063-210.313a46.725 46.342 0 0 0 9.03-39.219L651.3 162.716a46.725 46.342 0 0 0-25.281-31.437L381.643 14.59a46.725 46.342 0 0 0-22.657-4.53z"
- />
- <path
- fill="#fff"
- stroke="#fff"
- strokeWidth={0.25}
- d="M361.408 99.307c-8.077.001-14.626 7.276-14.625 16.25 0 .138.028.27.03.406-.011 1.22-.07 2.689-.03 3.75.192 5.176 1.32 9.138 2 13.907 1.23 10.206 2.26 18.667 1.625 26.531-.62 2.965-2.803 5.677-4.75 7.562l-.344 6.188a190.337 190.337 0 0 0-26.438 4.062c-37.974 8.623-70.67 28.184-95.562 54.594a245.167 245.167 0 0 1-5.281-3.75c-2.612.353-5.25 1.159-8.688-.844-6.545-4.405-12.506-10.486-19.719-17.812-3.305-3.504-5.698-6.841-9.625-10.219-.891-.767-2.252-1.804-3.25-2.594-3.07-2 [...]
- color="#000"
- fontFamily="Sans"
- fontWeight={400}
- overflow="visible"
- style={{
- textIndent: 0,
- textAlign: "start",
- lineHeight: "normal",
- textTransform: "none",
- marker: "none",
- }}
- />
- </svg>
- );
-}
-
-export function DocumentIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <path
- d="m25.7 9.3-7-7A.908.908 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h16a2.006 2.006 0 0 0 2-2V10a.908.908 0 0 0-.3-.7ZM18 4.4l5.6 5.6H18ZM24 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function GitIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- className="icon" width="32px" height="32px">
- <path
- fill="#000"
- fillRule="evenodd"
- d="M13.414 3.828a2 2 0 0 0-2.828 0l-.672.672 1.568 1.568a2.002 2.002 0 0 1 2.45 2.45l2.05 2.05a2 2 0 1 1-1.414 1.414L13 10.414v4.854A2 2 0 0 1 12 19a2 2 0 0 1-1-3.732V9.732a2 2 0 0 1-.932-2.25L8.5 5.914l-4.672 4.672a2 2 0 0 0 0 2.828l6.758 6.758a2 2 0 0 0 2.828 0l6.758-6.758a2 2 0 0 0 0-2.828l-6.758-6.758ZM9.172 2.414a4 4 0 0 1 5.656 0l6.758 6.758a4 4 0 0 1 0 5.656l-6.758 6.758a4 4 0 0 1-5.656 0l-6.758-6.758a4 4 0 0 1 0-5.656l6.758-6.758Z"
- clipRule="evenodd"
- />
- </svg>
- );
-}
-
-export function SocialIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 1024 1024"
- className="icon" width="32px" height="32px">
- <path
- fill="#FFB89A"
- d="M570.2 842c-50.6 0-278.7-180-278.7-401.9 0-58.8-2.9-133.1-1-183.9-50.8 3.2-91.4 45.7-91.4 97.3v272.1c37.4 194.7 137.5 334 255.2 334 69.5 0 132.9-48.6 180.9-128.5-20.8 7.1-42.6 10.9-65 10.9z"
- />
- <path
- fill="#4E5155"
- d="M926.1 191.8C900.5 74.1 817.9 62.1 704.9 62.1c-29.1 0-60.3.8-93 .8-36 0-70.5-1.1-102.5-1.1-109.7 0-189.8 12.5-201.3 123.7-20.4 198.3 30 617.1 306.1 617.1S939 414.3 926.1 191.8zm-76.9 268.5c-9.5 47.9-22.3 90.8-38.1 127.7-16.8 39.2-37 71.4-60 95.8-37.3 39.5-82.1 58.7-137 58.7-53.4 0-97.6-20.1-134.9-61.6-45.5-50.5-79.8-131.5-99-234.2-15.6-83.5-20.3-178.9-12.4-255.2 1.8-17.3 5.7-30.7 11.6-39.8 4.4-6.8 10.1-11.7 18.7-15.8 25.8-12.5 70.8-14.2 111.4-14.2 15 0 30.7.2 47.3.5 17 [...]
- />
- <path
- fill="#4E5155"
- d="M532 841.7c-32.5 22.3-70.6 33.7-113.2 33.7-29.7 0-57.3-6-82.1-17.7-23.2-11-44.7-27.4-63.9-48.7-46-50.9-80.3-131.3-99.2-232.4-15.1-80.6-19.6-172.9-12-246.8 3-29.5 12-50.2 27.5-63.2 14.2-12 35.1-19.2 65.8-22.9 16.5-2 28.2-16.9 26.3-33.3-2-16.5-16.9-28.2-33.3-26.3-42.9 5.1-73.8 16.7-97.4 36.5-27.9 23.5-43.8 57.2-48.5 103-8.2 79.3-3.4 178.1 12.7 264 9.7 51.9 23.4 99.4 40.6 141.2 19.8 48.1 44.4 88.6 73 120.4 51.6 57.2 115.7 86.2 190.6 86.2 55 0 104.5-14.9 147.2-44.2 13.7-9. [...]
- />
- <path
- fill="#3C9"
- d="M519.7 248.5c-16.6 0-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3c0-16.6-13.5-30-30-30zm-220.2 137c0-16.6-13.4-30-30-30s-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3zm455.1-137c-16.6 0-30 13.4-30 30v91.3c0 16.6 13.4 30 30 30s30-13.4 30-30v-91.3c0-16.6-13.4-30-30-30zm-37.9 306c0-16.6-13.4-30-30-30H551v30c0 58.5 38.1 123.7 92.8 123.7 22.9 0 45-11.9 62.2-33.6 10.3-13 8.1-31.9-4.9-42.1-13-10.3-31.9-8.1-42.1 4.9-5.3 6.7-11.1 10.9-15.1 10.9-4.3 [...]
- />
- </svg>
- );
-}
-
-export function DebeziumIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- viewBox="0 0 130.93 130.93"
- className="icon" width="32px" height="32px">
- <defs>
- <linearGradient
- id="linear-gradient"
- x1={19.74}
- x2={114.03}
- y1={19.73}
- y2={114.02}
- gradientUnits="userSpaceOnUse"
- >
- <stop offset={0} stopColor="#91d443"/>
- <stop offset={1} stopColor="#48bfe0"/>
- </linearGradient>
- <linearGradient
- xlinkHref="#linear-gradient"
- id="linear-gradient-2"
- x1={43.19}
- x2={137.48}
- y1={-3.72}
- y2={90.57}
- />
- <linearGradient
- xlinkHref="#linear-gradient"
- id="linear-gradient-3"
- x1={66.56}
- x2={160.85}
- y1={-27.09}
- y2={67.2}
- />
- <linearGradient
- xlinkHref="#linear-gradient"
- id="linear-gradient-4"
- x1={-3.72}
- x2={90.57}
- y1={43.18}
- y2={137.47}
- />
- <linearGradient
- xlinkHref="#linear-gradient"
- id="linear-gradient-5"
- x1={-27.09}
- x2={67.2}
- y1={66.55}
- y2={160.84}
- />
- <style>{".cls-1{fill:#fff}"}</style>
- </defs>
- <g id="Layer_1" data-name="Layer 1">
- <path
- d="M93.79 114.29a16.65 16.65 0 0 0 16.63 16.63h20.53v-20.53a16.65 16.65 0 0 0-16.63-16.63h-3.91A26.39 26.39 0 0 1 84 67.4v-3.89a16.65 16.65 0 0 0-16.59-16.62h-3.9a26.39 26.39 0 0 1-26.35-26.37v-3.9A16.65 16.65 0 0 0 20.53 0H0v20.52a16.65 16.65 0 0 0 16.63 16.63h3.91A26.39 26.39 0 0 1 46.9 63.51v3.89A16.65 16.65 0 0 0 63.53 84h3.9a26.39 26.39 0 0 1 26.36 26.36Z"
- style={{
- fill: "url(#linear-gradient)",
- }}
- />
- <path
- d="M130.94 63.51a16.65 16.65 0 0 0-16.63-16.63h-3.91A26.39 26.39 0 0 1 84 20.52v-3.9A16.65 16.65 0 0 0 67.41 0H46.9v20.75a16.64 16.64 0 0 0 16.62 16.4h3.91a26.39 26.39 0 0 1 26.36 26.36v3.89A16.65 16.65 0 0 0 110.36 84h20.58Z"
- style={{
- fill: "url(#linear-gradient-2)",
- }}
- />
- <path
- d="M130.94 16.49A16.63 16.63 0 0 0 115 0H93.47v20.7a16.64 16.64 0 0 0 16.62 16.44h20.85Z"
- style={{
- fill: "url(#linear-gradient-3)",
- }}
- />
- <path
- d="M0 67.44a16.65 16.65 0 0 0 16.64 16.62h3.91a26.39 26.39 0 0 1 26.36 26.36v3.89a16.65 16.65 0 0 0 16.63 16.63H84v-20.75A16.64 16.64 0 0 0 67.43 93.8h-3.9a26.39 26.39 0 0 1-26.37-26.36v-3.9a16.65 16.65 0 0 0-16.57-16.63H0Z"
- style={{
- fill: "url(#linear-gradient-4)",
- }}
- />
- <path
- d="M0 114.45a16.63 16.63 0 0 0 16 16.5h21.48v-20.71A16.64 16.64 0 0 0 20.86 93.8H0Z"
- style={{
- fill: "url(#linear-gradient-5)",
- }}
- />
- </g>
- </svg>
- );
-}
-
-export function IgniteIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 48 48"
- className="icon" width="32px" height="32px">
- <path
- fill="#ED1C24"
- d="M7.686 8.136S-8.95 18.28 6.73 28.355c3.016 1.962 13.956 7.418 13.644 12.466 0 0 6.631-9.81-3.064-15.983C7.351 18.52 4.862 11.772 7.686 8.135Z"
- />
- <path
- fill="#ED1C24"
- d="M1.893 27.517s-5.936 8.997 5.745 10.84c1.15.144 9.6 1.029 11.802 3.804 0 0-.192-4.785-7.086-7.609-6.87-2.823-9.695-3.517-10.46-7.035Zm22.981-9.451C17.74 10.6 15.754 5.982 18.818 0c0 0-21.281 8.183-.264 22.708 7.517 5.192 6.272 10.504 6.272 10.696 1.173-1.22 7.181-7.873.048-15.338Z"
- />
- </svg>
- );
-}
-
-export function HazelcastIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 133.3 133.3" className="icon" width="32px" height="32px">
- <defs>
- <style>{".a{fill:#00e1e1}"}</style>
- </defs>
- <path
- d="M133.3 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.93v.38c0 6.07-6.42 12.49-12.49 12.49h-.38v.93h.36c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM26.66 12.86h-.38C20.21 12.86 13.8 6.45 13.8.38V0h-.94v.38c0 6.07-6.41 12.48-12.48 12.48H0v.94h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.94Z"
- className="a"
- />
- <path
- d="M26.66 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.53v-.38h-.94V27c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
- className="a"
- />
- <path
- d="M53.32 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94V27c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM26.66 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
- className="a"
- />
- <path
- d="M53.32 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
- className="a"
- />
- <path
- d="M80 66.19h-.4c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.4h.94v-.4c0-6.07 6.41-12.48 12.48-12.48h.4v-.93ZM26.66 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.94v.38c0 6.07-6.41 12.49-12.48 12.49H0v.93h.38c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93Z"
- className="a"
- />
- <path
- d="M53.32 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.94v.38c0 6.07-6.41 12.49-12.48 12.49h-.38v.93H27c6.07 0 12.48 6.41 12.48 12.48v.38h.94v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM106.64 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93V27c0 6.07-6.42 12.49-12.49 12.49H80v.93h.38c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM106.64 66.19h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93v.38c0 6.07-6.42 12.49-12.49 12.49H80v.93h. [...]
- className="a"
- />
- <path
- d="M106.64 92.85h-.38c-6.07 0-12.48-6.42-12.48-12.49V80h-.93v.38c0 6.07-6.42 12.49-12.49 12.49H80v.93h.38c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM133.3 39.53h-.38c-6.07 0-12.48-6.42-12.48-12.49v-.38h-.93V27c0 6.07-6.42 12.49-12.49 12.49h-.38v.93h.36c6.07 0 12.49 6.41 12.49 12.48v.38h.93v-.38c0-6.07 6.41-12.48 12.48-12.48h.38v-.93ZM133.3 12.86h-.38c-6.07 0-12.48-6.41-12.48-12.48V0h-.93v.38c0 6.07-6.42 12.48-12.49 12.48h-.38v.94h.3 [...]
- className="a"
- />
- </svg>
- );
-}
-
-export function AzureIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 96 96"
- className="icon" width="32px" height="32px">
- <defs>
- <linearGradient
- id="a"
- x1={-1032.172}
- x2={-1059.213}
- y1={145.312}
- y2={65.426}
- gradientTransform="matrix(1 0 0 -1 1075 158)"
- gradientUnits="userSpaceOnUse"
- >
- <stop offset={0} stopColor="#114a8b"/>
- <stop offset={1} stopColor="#0669bc"/>
- </linearGradient>
- <linearGradient
- id="b"
- x1={-1023.725}
- x2={-1029.98}
- y1={108.083}
- y2={105.968}
- gradientTransform="matrix(1 0 0 -1 1075 158)"
- gradientUnits="userSpaceOnUse"
- >
- <stop offset={0} stopOpacity={0.3}/>
- <stop offset={0.071} stopOpacity={0.2}/>
- <stop offset={0.321} stopOpacity={0.1}/>
- <stop offset={0.623} stopOpacity={0.05}/>
- <stop offset={1} stopOpacity={0}/>
- </linearGradient>
- <linearGradient
- id="c"
- x1={-1027.165}
- x2={-997.482}
- y1={147.642}
- y2={68.561}
- gradientTransform="matrix(1 0 0 -1 1075 158)"
- gradientUnits="userSpaceOnUse"
- >
- <stop offset={0} stopColor="#3ccbf4"/>
- <stop offset={1} stopColor="#2892df"/>
- </linearGradient>
- </defs>
- <path
- fill="url(#a)"
- d="M33.338 6.544h26.038l-27.03 80.087a4.152 4.152 0 0 1-3.933 2.824H8.149a4.145 4.145 0 0 1-3.928-5.47L29.404 9.368a4.152 4.152 0 0 1 3.934-2.825z"
- />
- <path
- fill="#0078d4"
- d="M71.175 60.261h-41.29a1.911 1.911 0 0 0-1.305 3.309l26.532 24.764a4.171 4.171 0 0 0 2.846 1.121h23.38z"
- />
- <path
- fill="url(#b)"
- d="M33.338 6.544a4.118 4.118 0 0 0-3.943 2.879L4.252 83.917a4.14 4.14 0 0 0 3.908 5.538h20.787a4.443 4.443 0 0 0 3.41-2.9l5.014-14.777 17.91 16.705a4.237 4.237 0 0 0 2.666.972H81.24L71.024 60.261l-29.781.007L59.47 6.544z"
- />
- <path
- fill="url(#c)"
- d="M66.595 9.364a4.145 4.145 0 0 0-3.928-2.82H33.648a4.146 4.146 0 0 1 3.928 2.82l25.184 74.62a4.146 4.146 0 0 1-3.928 5.472h29.02a4.146 4.146 0 0 0 3.927-5.472z"
- />
- </svg>
- );
-}
-
-
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/EipIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/EipIcons.tsx
deleted file mode 100644
index 4bdac684..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/EipIcons.tsx
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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';
-
-export function LoadBalanceIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="32px" height="32px">
- <path
- d="M4 26h4v4H4zM14 26h4v4h-4zM24 26h4v4h-4zM25 16h-8v-2h-2v2H7a2.002 2.002 0 0 0-2 2v6h2v-6h8v6h2v-6h8v6h2v-6a2.002 2.002 0 0 0-2-2ZM9 2v10h14V2Zm2 2h2v6h-2Zm10 6h-6V4h6Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function AggregateIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M496.2 417.71l-130.22 101.1c-.19.14-.39.29-.59.42a28.39 28.39 0 01-30.77 0c-.21-.13-.4-.28-.59-.42L203.8 417.71h292.4z"></path>
- <path
- d="M516.1 426.23v202.1c0 4.12-3.34 7.46-7.45 7.46H191.36c-4.11 0-7.46-3.34-7.46-7.46V426.22l138.52 107.53c.68.53 1.31.98 1.94 1.38 7.79 5.04 16.72 7.55 25.66 7.55s17.86-2.52 25.66-7.55c.62-.4 1.25-.85 1.94-1.38l138.5-107.52zM247.14 358.45l-12.91 30.22-.03.06v.03c-.11.21-.21.43-.32.64s-.23.42-.36.61c-.08.14-.17.27-.27.4-.08.11-.16.21-.24.31-.1.13-.21.25-.31.36-.08.09-.16.18-.24.25-.05.06-.1.11-.16.15l-.27.25c-.17.15-.33.29-.51.42-.15.13-.3.23-.47.33-.19.13-.39.25-.59.36s-. [...]
- <path
- d="M277.46 154.15V264.2c0 5.52-4.48 10-10 10H82.69c-5.52 0-10-4.48-10-10V154.14l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
- <g>
- <path d="M610.57 145.6l-76.07 57.24c-5.52 4.16-13.24 4.16-18.76 0l-76.08-57.24h170.91z"></path>
- <path
- d="M627.5 154.15V264.2c0 5.52-4.48 10-10 10H432.73c-5.52 0-10-4.48-10-10V154.14l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
- </g>
- </svg>
- );
-}
-
-export function ToIcon(classname: string = '') {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width={800}
- height={800}
- viewBox="0 0 32 32"
- className={classname ? "icon " + classname : "icon"}
- >
- <path d="m12.103 11.923 2.58 2.59H2.513v2h12.17l-2.58 2.59 1.41 1.41 5-5-5-5z"/>
- <path
- d="M9.513 23.013v-.5h2v.5a4.504 4.504 0 0 0 9 .36v-.86l.82-.1a7 7 0 0 0 0-13.88l-.82-.02v-.86a4.504 4.504 0 0 0-9 .36v.5h-2v-.5a6.5 6.5 0 0 1 12.86-1.3 9 9 0 0 1 0 17.6 6.5 6.5 0 0 1-12.86-1.3z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function PollIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width={800}
- height={800}
- viewBox="0 0 32 32"
- className="icon"
- >
- <title>{"cloud--download"}</title>
- <path
- d="M10.013 23.513v-.5h2v.5a4.504 4.504 0 0 0 9 .36v-.86l.82-.1a7 7 0 0 0 0-13.88l-.82-.02v-.86a4.504 4.504 0 0 0-9 .36v.5h-2v-.5a6.5 6.5 0 0 1 12.86-1.3 9 9 0 0 1 0 17.6 6.5 6.5 0 0 1-12.86-1.3z"/>
- <path d="M18.013 17.013v-2H5.843l2.58-2.59-1.41-1.41-5 5 5 5 1.41-1.41-2.58-2.59z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function ChoiceIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M407.33 113.97V609.2c0 2.75-1.9 5-4.22 5H291.55c-2.33 0-4.22-2.25-4.22-5V113.97c0-2.76 1.89-5 4.22-5h111.56c2.32 0 4.22 2.24 4.22 5zM27.1 437.55l60.87-57.64c.95-.9 2.32-1.41 3.76-1.41H258.2c2.76 0 5 1.87 5 4.17v111.65c0 2.3-2.24 4.17-5 4.17H91.54c-1.38 0-2.7-.48-3.65-1.32L27.2 443.15c-1.77-1.58-1.81-3.99-.1-5.61zM667.57 285.62l-60.87 57.64c-.95.9-2.32 1.41-3.76 1.41H436.47c-2.76 0-5-1.87-5-4.17V228.85c0-2.3 2.24-4.17 5-4.17h166.66c1.38 0 2.7.48 3.65 1.32l60.69 54.02c1. [...]
- </svg>
- );
-}
-
-
-export function SplitIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M496.2 83.65l-130.22 101.1c-.19.14-.39.29-.59.42a28.39 28.39 0 01-30.77 0c-.21-.13-.4-.28-.59-.42L203.8 83.65h292.4z"></path>
- <path
- d="M516.1 92.17v202.1c0 4.12-3.34 7.46-7.45 7.46H191.36c-4.11 0-7.46-3.34-7.46-7.46V92.16l138.52 107.53c.68.53 1.31.98 1.94 1.38 7.79 5.04 16.72 7.55 25.66 7.55s17.86-2.52 25.66-7.55c.62-.4 1.25-.85 1.94-1.38l138.5-107.52zM524.34 397.22l-12.91 30.22-.03.06v.03c-.11.21-.21.43-.32.64s-.23.42-.36.61c-.08.14-.17.27-.27.4-.08.11-.16.21-.24.31-.1.13-.21.25-.31.36-.08.09-.16.18-.24.25-.05.06-.1.11-.16.15l-.27.25c-.17.15-.33.29-.51.42-.15.13-.3.23-.47.33-.19.13-.39.25-.59.36s-.42 [...]
- <path
- d="M277.36 476.26v110.05c0 5.52-4.48 10-10 10H82.59c-5.52 0-10-4.48-10-10V476.25l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
- <g>
- <path d="M610.48 467.71l-76.07 57.24c-5.52 4.16-13.24 4.16-18.76 0l-76.08-57.24h170.91z"></path>
- <path
- d="M627.41 476.26v110.05c0 5.52-4.48 10-10 10H432.64c-5.52 0-10-4.48-10-10V476.25l82.79 62.29c5.77 4.34 12.69 6.51 19.6 6.51s13.83-2.17 19.6-6.51l82.78-62.28z"></path>
- </g>
- </svg>
- );
-}
-
-export function SagaIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M626.41 255.77c-.56-4.77-2.95-9.03-6.71-11.99l-46.46-36.64-1.06-1.09-.8-.28c-.81-.52-1.67-.98-2.56-1.36-.43-.19-.85-.36-1.25-.5-.47-.16-.96-.31-1.51-.45-.47-.11-.96-.22-1.45-.3-.49-.08-.97-.14-1.43-.18-.96-.08-1.95-.08-2.91-.01-.41.03-.83.08-1.23.14-.41.06-.82.14-1.25.23l-.58.14c-.1.03-.2.05-.31.08-.11.03-.21.06-.3.09-.29.08-.57.18-.86.28-.49.17-.99.37-1.53.61l-.16.08c-.32.15-.65.31-.97.49-.49.26-.93.53-1.34.81-.39.26-.76.52-1.12.8l-46.96 37.05a17.823 17.823 0 00-6.72 [...]
- </svg>
- );
-}
-
-export function TransformIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M441.77 277.51l-82.73 64.23c-.07.05-.13.09-.19.13-5.37 3.48-12.33 3.48-17.69.01-.07-.05-.13-.09-.18-.13l-82.76-64.24h183.54z"></path>
- <path
- d="M462.2 287.02V420.7c0 .98-.79 1.77-1.77 1.77H239.57c-.98 0-1.77-.79-1.77-1.77V287.02l90.91 70.56c.54.44 1.06.8 1.57 1.12 5.99 3.88 12.86 5.81 19.72 5.81s13.73-1.94 19.73-5.81c.49-.32 1.01-.68 1.58-1.13l90.89-70.55zM622.28 330.68l-35.89 31.78a1.48 1.48 0 01-1.98 0l-35.89-31.78c-.3-.26-.48-.63-.51-1.03-.02-.4.11-.79.38-1.09l11.28-12.73c.55-.61 1.49-.67 2.11-.12l12.44 11.02c-5.24-51.26-28.18-99.47-64.84-136.12-35.82-35.82-81.13-58.05-131.04-64.27-.1 0-.19-.03-.28-.06v.09s [...]
- </svg>
- );
-}
-
-export function FilterIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" id="a" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <path
- d="M565.62 156.56L413.36 350.33a10.032 10.032 0 00-2.14 6.18v190.52c0 19.05-25.01 34.49-55.86 34.49s-55.86-15.44-55.86-34.49V356.51c0-2.24-.75-4.42-2.14-6.18L145.1 156.56c-5.15-6.56-.48-16.18 7.87-16.18h404.79c8.34 0 13.02 9.62 7.86 16.18z"></path>
- </svg>
- );
-}
-
-export function SetExchangePatternIcon() {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- className="icon" width="32px" height="32px">
- <title>{"data-share"}</title>
- <path
- d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM4.226 1.135h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2zm4 6v-4H4.225l.001 4zM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- );
-}
-
-export function SortIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon" width="32px" height="32px">
- <defs>
- <style>{".b{stroke-linejoin: round;}.b,.c {stroke-linecap: round;}.b,.c,.d {fill: none;stroke: #000;stroke-width: 35px;}.c,.d {stroke-miterlimit: 10;}"}</style>
- </defs>
- <path d="M160.63 168.63L160.63 531.37" className="d"></path>
- <path d="M576.31 170.27L269.3 170.27" className="c"></path>
- <path d="M517.53 290.64L269.3 290.64" className="c"></path>
- <path d="M458.75 411L269.3 411" className="c"></path>
- <path d="M399.97 531.37L269.3 531.37" className="c"></path>
- <path d="M197.7 197.95L160.63 168.71 123.55 197.95" className="b"></path>
- <path d="M123.55 502.12L160.62 531.37 197.7 502.12" className="b"></path>
- </svg>
- );
-}
-
-export function OnCompletion() {
- return (
- <svg
- className="icon" width="32px" height="32px"
- xmlns="http://www.w3.org/2000/svg"
- id="icon"
- fill="#000"
- viewBox="0 0 32 32"
- >
- <defs>
- <style>{".cls-1 { fill: none; }"}</style>
- </defs>
- <path d="M22 26.59L19.41 24 18 25.41 22 29.41 30 21.41 28.59 20 22 26.59z"></path>
- <circle cx="16" cy="16" r="2"></circle>
- <path d="M16 22a6 6 0 116-6 6.007 6.007 0 01-6 6zm0-10a4 4 0 104 4 4.005 4.005 0 00-4-4z"></path>
- <path d="M28 16a12 12 0 10-12 12v-2a10 10 0 1110-10z"></path>
- <path
- id="_Transparent_Rectangle_"
- d="M0 0H32V32H0z"
- className="cls-1"
- data-name="<Transparent Rectangle>"
- ></path>
- </svg>
- );
-}
-
-export function Intercept() {
- return (
- <svg
- className="icon" width="32px" height="32px"
- xmlns="http://www.w3.org/2000/svg"
- id="icon"
- fill="#000"
- viewBox="0 0 32 32"
- >
- <defs>
- <style>{".cls-1 { fill: none; }"}</style>
- </defs>
- <path d="M15 4H17V28H15z"></path>
- <path
- d="M10 7v18H4V7h6m0-2H4a2 2 0 00-2 2v18a2 2 0 002 2h6a2 2 0 002-2V7a2 2 0 00-2-2zM28 7v18h-6V7h6m0-2h-6a2 2 0 00-2 2v18a2 2 0 002 2h6a2 2 0 002-2V7a2 2 0 00-2-2z"></path>
- <path
- id="_Transparent_Rectangle_"
- d="M0 0H32V32H0z"
- className="cls-1"
- data-name="<Transparent Rectangle>"
- ></path>
- </svg>
- );
-}
-
-export function InterceptFrom() {
- return (
- <svg
- className="icon" width="32px" height="32px"
- xmlns="http://www.w3.org/2000/svg"
- id="icon"
- fill="#000"
- viewBox="0 0 32 32"
- >
- <defs>
- <style>{".cls-1 { fill: none; }"}</style>
- </defs>
- <path d="M26 30H14a2 2 0 01-2-2v-3h2v3h12V4H14v3h-2V4a2 2 0 012-2h12a2 2 0 012 2v24a2 2 0 01-2 2z"></path>
- <path d="M14.59 20.59L18.17 17 4 17 4 15 18.17 15 14.59 11.41 16 10 22 16 16 22 14.59 20.59z"></path>
- <path
- id="_Transparent_Rectangle_"
- d="M0 0H32V32H0z"
- className="cls-1"
- data-name="<Transparent Rectangle>"
- ></path>
- </svg>
- );
-}
-
-export function InterceptSendToEndpoint() {
- return (
- <svg
- className="icon" width="32px" height="32px"
- xmlns="http://www.w3.org/2000/svg"
- id="icon"
- fill="#000"
- viewBox="0 0 32 32"
- >
- <defs>
- <style>{".cls-1 { fill: none; }"}</style>
- </defs>
- <path
- d="M6 30h12a2.002 2.002 0 002-2v-3h-2v3H6V4h12v3h2V4a2.002 2.002 0 00-2-2H6a2.002 2.002 0 00-2 2v24a2.002 2.002 0 002 2z"></path>
- <path
- d="M20.586 20.586L24.172 17 10 17 10 15 24.172 15 20.586 11.414 22 10 28 16 22 22 20.586 20.586z"></path>
- <path
- id="_Transparent_Rectangle_"
- d="M0 0H32V32H0z"
- className="cls-1"
- data-name="<Transparent Rectangle>"
- ></path>
- </svg>
- );
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/KaravanIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/KaravanIcons.tsx
deleted file mode 100644
index e6ac0778..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/KaravanIcons.tsx
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * 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, {ReactElement} from 'react';
-
-export function KaravanIcon(className?: string) {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- id="svg50"
- width={32}
- height={32}
- preserveAspectRatio="xMidYMid"
- version="1.1"
- viewBox="0 0 256 256"
- className={className ? className : "logo"}
- >
- <defs id="defs31">
- <linearGradient id="linearGradient1351">
- <stop
- id="stop1347"
- offset="0"
- stopColor="#dcffff"
- stopOpacity="1"
- ></stop>
- <stop
- id="stop1349"
- offset="1"
- stopColor="#96d2e6"
- stopOpacity="1"
- ></stop>
- </linearGradient>
- <circle id="path-1" cx="128" cy="128" r="128"></circle>
- <linearGradient
- id="linearGradient-3"
- x1="-26.051"
- x2="254.316"
- y1="271.331"
- y2="0.048"
- gradientUnits="userSpaceOnUse"
- >
- <stop
- id="stop10"
- offset="0%"
- stopColor="#4790bb"
- stopOpacity="1"
- ></stop>
- <stop
- id="stop12"
- offset="10.996%"
- stopColor="#64b7db"
- stopOpacity="1"
- ></stop>
- <stop
- id="stop14"
- offset="94.502%"
- stopColor="#326ea0"
- stopOpacity="1"
- ></stop>
- </linearGradient>
- <linearGradient
- id="linearGradient-4"
- x1="-32.163"
- x2="259.338"
- y1="277.029"
- y2="-5.028"
- gradientUnits="userSpaceOnUse"
- >
- <stop id="stop17" offset="0%" stopColor="#F69923"></stop>
- <stop id="stop19" offset="8.048%" stopColor="#F79A23"></stop>
- <stop id="stop21" offset="41.874%" stopColor="#E97826"></stop>
- </linearGradient>
- <linearGradient
- id="linearGradient-5"
- x1="217.945"
- x2="99.459"
- y1="67.505"
- y2="247.005"
- gradientTransform="scale(.96442 1.0369)"
- gradientUnits="userSpaceOnUse"
- xlinkHref="#linearGradient-4"
- >
- <stop
- id="stop24"
- offset="0%"
- stopColor="#92d6d5"
- stopOpacity="1"
- ></stop>
- <stop
- id="stop26"
- offset="41.191%"
- stopColor="#79b7cc"
- stopOpacity="1"
- ></stop>
- <stop
- id="stop28"
- offset="73.271%"
- stopColor="#5891c5"
- stopOpacity="1"
- ></stop>
- </linearGradient>
- <mask id="mask-2" fill="#fff">
- <use id="use33" xlinkHref="#path-1"></use>
- </mask>
- <mask id="mask-2-7" fill="#fff">
- <use id="use137" xlinkHref="#path-1"></use>
- </mask>
- <linearGradient
- id="linearGradient1345"
- x1="233.122"
- x2="2.24"
- y1="56.015"
- y2="242.78"
- gradientUnits="userSpaceOnUse"
- xlinkHref="#linearGradient1351"
- ></linearGradient>
- </defs>
- <circle
- id="circle38"
- cx="127.994"
- cy="127.994"
- r="123.111"
- fill="url(#linearGradient-3)"
- fillRule="nonzero"
- mask="url(#mask-2)"
- ></circle>
- <g id="g2266">
- <path
- id="path42"
- fill="url(#linearGradient-5)"
- fillOpacity="1"
- fillRule="nonzero"
- d="M98.044 75.517c-1.751-.002-3.524.01-5.292.061-2.056.06-4.817.713-8 1.785 53.775 40.834 73.108 114.497 39.875 178.514 1.129.03 2.249.123 3.385.123 60.736 0 111.492-42.323 124.609-99.071-38.542-45.178-90.813-81.314-154.578-81.412z"
- mask="url(#mask-2)"
- opacity="0.75"
- ></path>
- </g>
- <path
- id="path44"
- fill="#1e4b7b"
- fillOpacity="1"
- fillRule="nonzero"
- d="M84.752 77.368C66.895 83.378 32.83 104.546.079 132.81c2.487 67.334 57.028 121.313 124.548 123.07 33.233-64.016 13.901-137.68-39.875-178.513z"
- mask="url(#mask-2)"
- opacity="0.75"
- ></path>
- <path
- id="path150"
- fill="url(#linearGradient1345)"
- fillOpacity="1"
- fillRule="nonzero"
- d="M128.747 54.005c-10.985 5.495 0 27.466 0 27.466C95.774 108.954 102.78 155.9 64.312 155.9c-20.97 0-42.242-24.077-64.233-38.828-.283 3.479-.785 6.972-.785 10.524 0 48.095 26.263 89.924 65.42 111.897 10.952-1.38 22.838-4.114 31.05-9.592 43.146-28.765 53.857-83.491 71.487-109.925 10.979-16.492 62.434-15.061 65.906-22.01 5.502-10.991-10.99-27.467-16.491-27.467h-43.958c-3.071 0-7.897-5.456-10.974-5.456h-16.492s-7.307-11.085-13.794-11.526c-.93-.066-1.83.053-2.7.488z"
- mask="url(#mask-2-7)"
- transform="translate(-.769 -.133)"
- ></path>
- <path
- id="path40"
- fill="#2d4150"
- fillOpacity="1"
- fillRule="nonzero"
- d="M128 256C57.308 256 0 198.692 0 128 0 57.308 57.308 0 128 0c70.692 0 128 57.308 128 128 0 70.692-57.308 128-128 128zm0-9.768c65.298 0 118.232-52.934 118.232-118.232S193.298 9.768 128 9.768 9.768 62.702 9.768 128 62.702 246.232 128 246.232z"
- mask="url(#mask-2)"
- transform="translate(-.59) scale(1.00078)"
- ></path>
- </svg>
- );
-}
-
-export function CamelIcon(props?: (React.SVGProps<SVGSVGElement>) | undefined) {
- return (<svg
- xmlns="http://www.w3.org/2000/svg"
- xmlnsXlink="http://www.w3.org/1999/xlink"
- preserveAspectRatio="xMidYMid"
- viewBox="0 0 256 256"
- {...props}
- className="icon" width="32px" height="32px">
- <defs>
- <linearGradient
- id="b"
- x1="-12.564%"
- x2="101.304%"
- y1="108.214%"
- y2="-1.964%"
- >
- <stop offset="0%" stopColor="#F69923"/>
- <stop offset="10.996%" stopColor="#F79A23"/>
- <stop offset="94.502%" stopColor="#E97826"/>
- </linearGradient>
- <linearGradient
- id="d"
- x1="-12.564%"
- x2="101.304%"
- y1="108.214%"
- y2="-1.964%"
- >
- <stop offset="0%" stopColor="#F69923"/>
- <stop offset="8.048%" stopColor="#F79A23"/>
- <stop offset="41.874%" stopColor="#E97826"/>
- </linearGradient>
- <linearGradient
- id="e"
- x1="74.724%"
- x2="6.653%"
- y1="-3.059%"
- y2="100.066%"
- >
- <stop offset="0%" stopColor="#F6E423"/>
- <stop offset="41.191%" stopColor="#F79A23"/>
- <stop offset="73.271%" stopColor="#E97826"/>
- </linearGradient>
- <circle id="a" cx={128} cy={128} r={128}/>
- </defs>
- <mask id="c" fill="#fff">
- <use xlinkHref="#a"/>
- </mask>
- <circle
- cx={127.994}
- cy={127.994}
- r={123.111}
- fill="url(#b)"
- mask="url(#c)"
- />
- <path
- fill="url(#d)"
- d="M128 256C57.308 256 0 198.692 0 128 0 57.308 57.308 0 128 0c70.692 0 128 57.308 128 128 0 70.692-57.308 128-128 128Zm0-9.768c65.298 0 118.232-52.934 118.232-118.232S193.298 9.768 128 9.768 9.768 62.702 9.768 128 62.702 246.232 128 246.232Z"
- mask="url(#c)"
- />
- <path
- fill="url(#e)"
- d="M98.044 75.517c-1.751-.002-3.524.01-5.292.061-2.056.06-4.817.713-8 1.785 53.775 40.834 73.108 114.497 39.875 178.514 1.129.03 2.249.123 3.385.123 60.736 0 111.492-42.323 124.609-99.071-38.542-45.178-90.813-81.314-154.578-81.412Z"
- mask="url(#c)"
- opacity={0.75}
- />
- <path
- fill="#28170B"
- d="M84.752 77.368C66.895 83.378 32.83 104.546.079 132.81c2.487 67.334 57.028 121.313 124.548 123.07 33.233-64.016 13.901-137.68-39.875-178.513Z"
- mask="url(#c)"
- opacity={0.75}
- />
- <path
- fill="#FFF"
- d="M128.747 54.005c-10.985 5.495 0 27.466 0 27.466C95.774 108.954 102.78 155.9 64.312 155.9c-20.97 0-42.242-24.077-64.233-38.828-.283 3.479-.785 6.972-.785 10.524 0 48.095 26.263 89.924 65.42 111.897 10.952-1.38 22.838-4.114 31.05-9.592 43.146-28.765 53.857-83.491 71.487-109.925 10.979-16.492 62.434-15.061 65.906-22.01 5.502-10.991-10.99-27.467-16.491-27.467h-43.958c-3.071 0-7.897-5.456-10.974-5.456h-16.492s-7.307-11.085-13.794-11.526c-.93-.066-1.83.053-2.7.488Z"
- mask="url(#c)"
- />
- </svg>
- );
-}
-
-export function getDesignerIcon(icon: string, className?: string): ReactElement {
- if (icon === 'kamelet') return (
- <svg
- className={`top-icon ${className}`} id="icon"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 32 32"
- width="32px" height="32px"
- >
- <title>{"application"}</title>
- <path
- d="M16 18H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2ZM6 6v10h10V6ZM26 12v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM26 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM16 22v4h-4v-4h4m0-2h-4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- )
- if (icon === 'code') return (
- <svg
- className={`top-icon ${className}`}
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- fill="none"
- viewBox="0 0 24 24"
- >
- <path
- fill="#000000"
- d="M8.502 5.387a.75.75 0 00-1.004-1.115L5.761 5.836c-.737.663-1.347 1.212-1.767 1.71-.44.525-.754 1.088-.754 1.784 0 .695.313 1.258.754 1.782.42.499 1.03 1.049 1.767 1.711l1.737 1.564a.75.75 0 101.004-1.115l-1.697-1.527c-.788-.709-1.319-1.19-1.663-1.598-.33-.393-.402-.622-.402-.817 0-.196.072-.425.402-.818.344-.409.875-.889 1.663-1.598l1.697-1.527zM14.18 4.275a.75.75 0 01.532.918l-3.987 15a.75.75 0 11-1.45-.386l3.987-15a.75.75 0 01.918-.532zM15.443 10.498a.75.75 0 011.059 [...]
- ></path>
- </svg>
- )
- if (icon === 'routes') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <path
- d="M29,10H24v2h5v6H22v2h3v2.142a4,4,0,1,0,2,0V20h2a2.0027,2.0027,0,0,0,2-2V12A2.0023,2.0023,0,0,0,29,10ZM28,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,28,26Z"/>
- <path
- d="M19,6H14V8h5v6H12v2h3v6.142a4,4,0,1,0,2,0V16h2a2.0023,2.0023,0,0,0,2-2V8A2.0023,2.0023,0,0,0,19,6ZM18,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,18,26Z"/>
- <path
- d="M9,2H3A2.002,2.002,0,0,0,1,4v6a2.002,2.002,0,0,0,2,2H5V22.142a4,4,0,1,0,2,0V12H9a2.002,2.002,0,0,0,2-2V4A2.002,2.002,0,0,0,9,2ZM8,26a2,2,0,1,1-2-2A2.0023,2.0023,0,0,1,8,26ZM3,10V4H9l.0015,6Z"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
- height="32"/>
- </svg>)
- if (icon === 'route') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>{"category"}</title>
- <path
- d="M27 22.141V18a2 2 0 0 0-2-2h-8v-4h2a2.002 2.002 0 0 0 2-2V4a2.002 2.002 0 0 0-2-2h-6a2.002 2.002 0 0 0-2 2v6a2.002 2.002 0 0 0 2 2h2v4H7a2 2 0 0 0-2 2v4.142a4 4 0 1 0 2 0V18h8v4.142a4 4 0 1 0 2 0V18h8v4.141a4 4 0 1 0 2 0ZM13 4h6l.001 6H13ZM8 26a2 2 0 1 1-2-2 2.002 2.002 0 0 1 2 2Zm10 0a2 2 0 1 1-2-2 2.003 2.003 0 0 1 2 2Zm8 2a2 2 0 1 1 2-2 2.002 2.002 0 0 1-2 2Z"/>
- <path
- d="M0 0h32v32H0z"
- data-name="<Transparent Rectangle>"
- style={{
- fill: "none",
- }}
- />
- </svg>
- )
- if (icon === 'rest') return (
- <svg className={`top-icon ${className}`} viewBox="0 0 32 32" width="32px" height="32px">
- <g className="layer">
- <title>Layer 1</title>
- <path
- d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0 0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0 -13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0 0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0 0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
- id="svg_1"/>
- <path
- d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0 0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0 -1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0 -1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0 -0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0 0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0 1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0 1.7529,-0.7319l1.49,1.49l1.414,-1.414 [...]
- id="svg_2" transform="rotate(25 15.9724 21.2664)" xmlns="http://www.w3.org/2000/svg"/>
- </g>
- </svg>
- )
- if (icon === 'beans') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>data--1</title>
- <rect x="15" y="6" width="13" height="2"/>
- <rect x="15" y="24" width="13" height="2"/>
- <rect x="4" y="15" width="13" height="2"/>
- <path d="M7,11a4,4,0,1,1,4-4A4,4,0,0,1,7,11ZM7,5A2,2,0,1,0,9,7,2,2,0,0,0,7,5Z" transform="translate(0 0)"/>
- <path d="M7,29a4,4,0,1,1,4-4A4,4,0,0,1,7,29Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,7,23Z" transform="translate(0 0)"/>
- <path d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
- transform="translate(0 0)"/>
- <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
- <rect fill='none' width="32" height="32"/>
- </g>
- </svg>
- )
- if (icon === 'dependencies') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>application</title>
- <path d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
- transform="translate(0 0)"/>
- <path d="M26,12v4H22V12h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V12a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <path d="M26,22v4H22V22h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <path d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
- <rect fill='none' width="32" height="32"/>
- </g>
- </svg>
- )
- if (icon === 'error') return (
- <svg className={`top-icon ${className}`} width="36px" height="36px" viewBox="0 0 36 36" version="1.1"
- preserveAspectRatio="xMidYMid meet">
- <circle className="clr-i-outline clr-i-outline-path-1" cx="18" cy="26.06" r="1.33"/>
- <path className="clr-i-outline clr-i-outline-path-2"
- d="M18,22.61a1,1,0,0,1-1-1v-12a1,1,0,1,1,2,0v12A1,1,0,0,1,18,22.61Z"/>
- <path className="clr-i-outline clr-i-outline-path-3"
- d="M18,34A16,16,0,1,1,34,18,16,16,0,0,1,18,34ZM18,4A14,14,0,1,0,32,18,14,14,0,0,0,18,4Z"/>
- <rect x="0" y="0" width="36" height="36" fillOpacity="0"/>
- </svg>)
- if (icon === 'exception') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>misuse--alt</title>
- <polygon
- points="21.41 23 16 17.591 10.59 23 9 21.41 14.409 16 9 10.591 10.591 9 16 14.409 21.409 9 23 10.591 17.591 16 23 21.41 21.41 23"/>
- <path d="M16,4A12,12,0,1,1,4,16,12.0136,12.0136,0,0,1,16,4m0-2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Z"
- transform="translate(0)"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
- height="32"/>
- </svg>)
- if (icon === 'routeConfiguration') return (
- <svg className={`top-icon ${className}`} width="32" height="32" viewBox="0 0 32 32">
- <path
- d="M28.83 21.17L25 17.37l.67-.67a1 1 0 000-1.41l-6-6a1 1 0 00-1.41 0l-.79.79-6.76-6.79a1 1 0 00-1.41 0l-4 4-.12.15-4 6a1 1 0 00.12 1.26l3 3a1 1 0 001.42 0L10 13.41l2.09 2.09-4.8 4.79a1 1 0 000 1.41l2 2a1 1 0 00.71.3 1 1 0 00.52-.15l4.33-2.6 2.44 2.45a1 1 0 001.41 0l.67-.7 3.79 3.83a4 4 0 005.66-5.66zM10 10.58l-5 5-1.71-1.71 3.49-5.24L10 5.41l6.09 6.09-2.59 2.58zm8 11l-2.84-2.84-5 3-.74-.74L19 11.41 23.59 16zm9.42 3.83a2 2 0 01-2.83 0l-3.8-3.79 2.83-2.83 3.8 3.79a2 2 0 010 [...]
- <path
- d="M0 0H32V32H0z"
- fill='none'
- data-name="<Transparent Rectangle>"
- ></path>
- </svg>)
- if (icon === 'yaml') return (
- <svg className={`top-icon ${className}`} x="0px" y="0px" width="32px" height="32px"
- viewBox="0 0 32 32">
- <style type="text/css">{".st0{fill:none;}"}</style>
- <title>document</title>
- <path
- d="M25.7,9.3l-7-7C18.5,2.1,18.3,2,18,2H8C6.9,2,6,2.9,6,4v24c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V10C26,9.7,25.9,9.5,25.7,9.3 z M18,4.4l5.6,5.6H18V4.4z M24,28H8V4h8v6c0,1.1,0.9,2,2,2h6V28z"/>
- <rect x="10" y="22" width="12" height="2"/>
- <rect x="10" y="16" width="12" height="2"/>
- <rect className="st0" width="32" height="32"/>
- </svg>)
- if (icon === 'code') return (
- <svg className={`top-icon ${className}`} width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>code</title>
- <polygon points="31 16 24 23 22.59 21.59 28.17 16 22.59 10.41 24 9 31 16"/>
- <polygon points="1 16 8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 16"/>
- <rect x="5.91" y="15" width="20.17" height="2" transform="translate(-3.6 27.31) rotate(-75)"/>
- <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none' width="32"
- height="32" transform="translate(0 32) rotate(-90)"/>
- </svg>)
- return <></>;
-}
-
-
-export class BeanIcon extends React.Component<any> {
-
- render() {
- return (
- <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>data--1</title>
- <rect x="15" y="6" width="13" height="2"/>
- <rect x="15" y="24" width="13" height="2"/>
- <rect x="4" y="15" width="13" height="2"/>
- <path d="M7,11a4,4,0,1,1,4-4A4,4,0,0,1,7,11ZM7,5A2,2,0,1,0,9,7,2,2,0,0,0,7,5Z"
- transform="translate(0 0)"/>
- <path d="M7,29a4,4,0,1,1,4-4A4,4,0,0,1,7,29Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,7,23Z"
- transform="translate(0 0)"/>
- <path d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
- transform="translate(0 0)"/>
- <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
- <rect fill='none' width="32" height="32"/>
- </g>
- </svg>
- )
- }
-}
-
-export class DependencyIcon extends React.Component<any> {
-
- render() {
- return (
- <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32" id="icon">
- <title>application</title>
- <path d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
- transform="translate(0 0)"/>
- <path d="M26,12v4H22V12h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V12a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <path d="M26,22v4H22V22h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <path d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
- transform="translate(0 0)"/>
- <g id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>">
- <rect fill='none' width="32" height="32"/>
- </g>
- </svg>
- )
- }
-}
-
-export class RestIcon extends React.Component<any> {
-
- render() {
- return (
- <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32">
- <g className="layer">
- <title>Layer 1</title>
- <path
- d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0 0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0 -13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0 0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0 0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
- id="svg_1"/>
- <path
- d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0 0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0 -1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0 -1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0 -0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0 0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0 1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0 1.7529,-0.7319l1.49,1.49l1.414,-1 [...]
- id="svg_2" transform="rotate(25 15.9724 21.2664)" xmlns="http://www.w3.org/2000/svg"/>
- </g>
- </svg>
- )
- }
-}
-
-export class ConceptIcon extends React.Component<any> {
-
- render() {
- return (
- <svg className="icon" width="32px" height="32px" viewBox="0 0 32 32">
- <title>concept</title>
- <path
- d="M20.8851,19.4711a5.9609,5.9609,0,0,0,0-6.9422L23,10.4141l1.293,1.2929a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414l-4-4a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414L21.5859,9l-2.1148,2.1149a5.9609,5.9609,0,0,0-6.9422,0L10,8.5859V2H2v8H8.5859l2.529,2.5289a5.9609,5.9609,0,0,0,0,6.9422L9,21.5859,7.707,20.293a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414l4,4a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414L10.4141,23l2.1148-2.1149a5.960 [...]
- <rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" fill='none'
- width="32" height="32"/>
- </svg>
- )
- }
-}
-
-export function JKubeIcon(className?: string) {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 59.799997 68.099998"
- className={className ? className + " icon" : "icon"}
- >
- <style id="style1" type="text/css">
- {".jkube-icon-outer{fill-rule:evenodd;clip-rule:evenodd;fill:#0a4e9b}"}
- </style>
- <g id="g8" transform="translate(-9.2 -8.3)">
- <path
- id="path6"
- d="M9.3 59.8c.9.8 2.5 1.5 3.5 2.1l21.6 12.5c1 .6 2.5 1.6 3.6 2v-6.3L14.8 56.6V29.8c-1.6-.4-4.2-2.7-5.6-2.9Z"
- className="jkube-icon-outer"
- />
- <path
- id="path7"
- d="m69 59.8-.1-33c-1.5.5-3.9 2.6-5.5 3v26.9c-.8.8-4.9 2.9-6.1 3.6l-12.3 7c-5.1 3-4.8 2-4.8 4.9l.1 4.2z"
- className="jkube-icon-outer"
- />
- <path
- id="path8"
- d="M15.9 28c1.9-.7 4.3-2.4 6-3.4l5.7-3.3c2.1-1.2 3.7-2.2 5.8-3.4 1.7-.9 4.1-2.6 5.7-3.2l14.3 8.2c2.4 1.4 4.7 2.7 7.2 4.1 2.1 1.2 1.6 1 3.7-.1 1-.6 2.7-1.4 3.4-2.1-.7-.7-28.3-16.5-28.5-16.5-.2 0-27.8 15.7-28.7 16.6Z"
- className="jkube-icon-outer"
- />
- </g>
- <path
- id="path9"
- d="M30 9.5 8.6 21.8v24.7L30 58.8l21.4-12.3V21.8Zm7.4 29c0 1.8-.5 3.6-1.4 5.1-.9 1.6-2.2 2.8-3.8 3.7-1.6.9-3.3 1.4-5.2 1.4-1.9 0-3.6-.5-5.2-1.4-1.6-.9-2.9-2.2-3.8-3.7-.9-1.6-1.4-3.3-1.4-5.1h6.8c0 .9.3 1.7 1 2.4s1.5 1 2.5 1 1.8-.3 2.5-1 1-1.5 1-2.4V28.2H24v-6.8h13.3v17.1z"
- style={{
- fill: "#0a4e9b",
- }}
- />
- </svg>
- )
-}
-
-export function AsyncApiIcon({className = ''}) {
- return (
- <svg className={"h-10 mt-0.5 w-auto " + className} width="165" height="36" viewBox="0 0 165 36" fill="none" xmlns="http://www.w3.org/2000/svg">
- <defs>
- <linearGradient id="gradient1" x1="33.0317" y1="3.3661" x2="4.57364" y2="32.1761" gradientUnits="userSpaceOnUse">
- <stop stop-color="#2DCCFD"></stop>
- <stop offset="100%" stop-color="#AD20E2"></stop>
- </linearGradient>
- <linearGradient id="gradient2" x1="33.0317" y1="32.6313" x2="4.571" y2="3.82126" gradientUnits="userSpaceOnUse">
- <stop stop-color="#A829E2"></stop>
- <stop offset="5%" stop-color="#A829E2" stop-opacity="84%"></stop>
- <stop offset="11%" stop-color="#A829E2" stop-opacity="67%"></stop>
- <stop offset="18%" stop-color="#A829E2" stop-opacity="51%"></stop>
- <stop offset="25%" stop-color="#A829E2" stop-opacity="38%"></stop>
- <stop offset="33%" stop-color="#A829E2" stop-opacity="28%"></stop>
- <stop offset="43%" stop-color="#A829E2" stop-opacity="20%"></stop>
- <stop offset="54%" stop-color="#A829E2" stop-opacity="14%"></stop>
- <stop offset="68%" stop-color="#A829E2" stop-opacity="11%"></stop>
- <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
- </linearGradient>
- <linearGradient id="gradient3" x1="3.41005" y1="32.6313" x2="31.8682" y2="3.82129" gradientUnits="userSpaceOnUse">
- <stop stop-color="#E50E99"></stop>
- <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
- </linearGradient>
- <linearGradient id="gradient4" x1="33.0317" y1="3.36871" x2="4.57097" y2="32.1761" gradientUnits="userSpaceOnUse">
- <stop stop-color="#21D4FD"></stop>
- <stop offset="3%" stop-color="#27CDFC" stop-opacity="96%"></stop>
- <stop offset="23%" stop-color="#4E9CF4" stop-opacity="70%"></stop>
- <stop offset="43%" stop-color="#6E73EE" stop-opacity="49%"></stop>
- <stop offset="61%" stop-color="#8753E9" stop-opacity="32%"></stop>
- <stop offset="77%" stop-color="#993CE5" stop-opacity="20%"></stop>
- <stop offset="90%" stop-color="#A42EE3" stop-opacity="13%"></stop>
- <stop offset="100%" stop-color="#A829E2" stop-opacity="10%"></stop>
- </linearGradient>
- </defs>
- <path
- d="M63.9815 27.6971H61.4524L59.3704 22.3187H50.4894L48.4074 27.6971H45.9074L53.5529 8.30026H56.3783L63.9815 27.6971ZM51.3386 20.1182H58.5079L54.9074 10.5635L51.3386 20.1182Z"
- fill="#0C0928"></path>
- <path
- d="M71.7037 27.9925C70.3161 28.0052 68.9453 27.6926 67.7037 27.0804C66.5264 26.5139 65.5472 25.6129 64.8915 24.4931L66.9154 23.0531C67.3281 23.9309 67.9957 24.6678 68.8333 25.17C69.7573 25.7002 70.8129 25.9645 71.881 25.9331C72.9392 25.9331 73.7566 25.7345 74.3519 25.332C74.5772 25.1976 74.771 25.0172 74.9202 24.8029C75.0695 24.5887 75.1707 24.3455 75.2173 24.0895C75.2639 23.8335 75.2547 23.5707 75.1903 23.3185C75.1259 23.0663 75.0078 22.8306 74.8439 22.6271C74.5741 22.27 [...]
- fill="#0C0928"></path>
- <path
- d="M90.3703 13.0018H92.9285L85.9391 30.1668C85.642 30.9811 85.2258 31.748 84.7037 32.4431C84.3138 32.9574 83.8037 33.3707 83.2169 33.6479C82.6214 33.9034 81.9771 34.0291 81.328 34.0164C80.6995 34.0219 80.0743 33.9275 79.4762 33.7367C78.939 33.565 78.4321 33.312 77.9735 32.9867L78.6269 30.9299C78.9951 31.2671 79.424 31.5331 79.8915 31.7139C80.3125 31.8803 80.7609 31.9689 81.2143 31.9753C81.7379 31.9722 82.2474 31.8077 82.6719 31.5049C83.127 31.1913 83.5432 30.5545 83.9206 [...]
- fill="#0C0928"></path>
- <path
- d="M94.9735 27.6971V13.0018H97.0502L97.2566 16.2947L96.8703 15.9707C97.1438 15.2501 97.5819 14.6017 98.1507 14.0759C98.6824 13.5968 99.3148 13.2398 100.003 13.0306C100.711 12.8158 101.449 12.7075 102.19 12.7091C103.193 12.6965 104.187 12.9017 105.101 13.3102C105.966 13.7045 106.695 14.3405 107.198 15.1396C107.727 15.9637 107.992 17.0091 107.992 18.2757V27.6841H105.611V19.1146C105.611 17.4891 105.258 16.3566 104.553 15.7172C103.842 15.079 102.91 14.7371 101.95 14.7633C101. [...]
- fill="#0C0928"></path>
- <path
- d="M117.251 12.7091C118.181 12.6912 119.105 12.851 119.974 13.1795C120.741 13.4831 121.436 13.9436 122.011 14.5307C122.599 15.1392 123.072 15.8474 123.407 16.6214L121.148 17.6668C120.895 16.8219 120.393 16.0705 119.706 15.5081C118.978 14.983 118.091 14.7185 117.19 14.758C116.291 14.7331 115.404 14.9625 114.632 15.4192C113.903 15.8776 113.332 16.5437 112.995 17.3297C112.243 19.2646 112.243 21.4057 112.995 23.3405C113.329 24.1319 113.9 24.8032 114.632 25.264C115.404 25.7207 [...]
- fill="#0C0928"></path>
- <path
- d="M143.659 27.6971H140.296L138.423 22.614H130.183L128.307 27.6971H125.034L132.442 8.30026H136.251L143.659 27.6971ZM131.074 20.0555H137.526L134.312 11.0052L131.074 20.0555Z"
- fill="#0C0928"></path>
- <path
- d="M152.992 8.30024C154.248 8.26933 155.494 8.52043 156.638 9.03462C157.616 9.49485 158.441 10.2199 159.019 11.1254C159.584 12.1193 159.881 13.2402 159.881 14.3804C159.881 15.5205 159.584 16.6415 159.019 17.6354C158.443 18.5428 157.617 19.2684 156.638 19.7262C155.495 20.2425 154.248 20.4945 152.992 20.4631H148.619V27.6919H145.444V8.30024H152.992ZM152.487 17.7635C153.898 17.7635 154.934 17.4743 155.595 16.8958C156.257 16.3174 156.589 15.4802 156.593 14.3843C156.593 13.2692 [...]
- fill="#0C0928"></path>
- <path d="M165 8.30026V27.6971H161.825V8.30026H165Z" fill="#0C0928"></path>
- <path
- d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
- fill="url(#gradient1)"></path>
- <path
- d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
- fill="url(#gradient2)"></path>
- <path
- d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
- fill="url(#gradient3)"></path>
- <path
- d="M27.8228 0H8.61905C3.85888 0 0 3.8121 0 8.51456V27.4854C0 32.1879 3.85888 36 8.61905 36H27.8228C32.5829 36 36.4418 32.1879 36.4418 27.4854V8.51456C36.4418 3.8121 32.5829 0 27.8228 0Z"
- fill="url(#gradient4)"></path>
- <path d="M11.7645 14.1988L10.6799 15.6754L19.1508 21.749L19.209 21.7908L20.2936 20.3142L11.8227 14.2406L11.7645 14.1988Z" fill="white"></path>
- <path d="M17.2989 14.2406L17.2407 14.1988L16.1561 15.6754L24.627 21.749L24.6852 21.7908L25.7698 20.3142L17.2989 14.2406Z" fill="white"></path>
- <path
- d="M18.2275 6.64075C13.6349 6.64075 9.89948 9.46064 9.89948 12.9261V12.9966H11.7513V12.9261C11.7513 10.4668 14.6614 8.46492 18.2328 8.46492C21.8042 8.46492 24.7143 10.4668 24.7143 12.9261V12.9966H26.5661V12.9261C26.5556 9.46064 22.8201 6.64075 18.2275 6.64075Z"
- fill="white"></path>
- <path
- d="M24.6958 23.0714C24.6958 25.5306 21.7857 27.5325 18.2116 27.5325C14.6376 27.5325 11.7301 25.5306 11.7301 23.0714V23.0008H9.8783V23.0714C9.8783 26.5368 13.6137 29.3567 18.2063 29.3567C22.7989 29.3567 26.5344 26.5368 26.5344 23.0714V23.0008H24.6825L24.6958 23.0714Z"
- fill="white"></path>
- </svg>
- );
-}
-
-export function OpenApiIcon(className?: string, height?: number | string | undefined, width?: number | string | undefined, fill?: string) {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- xmlSpace="preserve"
- viewBox="0 0 112 112"
- height={height}
- width={width}
- className={className}
- >
- <path
- fill={fill ?? "#93d500"}
- d="M74.909 189.069H45.352c.005.144.009.289.017.433.012.278.032.555.049.833.008.119.013.238.022.356.023.322.051.642.08.962l.02.215a46.218 46.218 0 0 0 .126 1.168 43.62 43.62 0 0 0 .154 1.158c.339 2.356.848 4.69 1.527 6.984.003.01.007.019.009.029a43.315 43.315 0 0 0 .373 1.203c.105.323.215.645.325.968.029.081.056.163.086.244.099.279.2.558.304.837l.143.378.27.691c.069.173.141.346.213.519.074.18.15.359.226.54.094.22.192.439.289.658l.175.391c.12.263.244.526.368.787.041.084.08. [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#4d5a31"}
- d="m82.173 202.638-.071.071-20.819 20.82c.107.1.213.201.323.298.194.176.392.351.589.523.102.091.202.181.304.269.236.204.474.403.711.602l.192.16a47.32 47.32 0 0 0 .917.737 62.01 62.01 0 0 0 .928.711 50.044 50.044 0 0 0 3.895 2.633l.139.085c.255.153.51.304.767.453l.471.268c.148.086.296.168.446.251a63.783 63.783 0 0 0 .927.499c.757.396 1.527.764 2.303 1.118l.739-1.794 10.471-25.429.039-.094a20.195 20.195 0 0 1-3.271-2.181z"
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#6ba43a"}
- d="M80.005 200.564a20.653 20.653 0 0 1-1.767-2.28 21.467 21.467 0 0 1-.54-.843l-25.275 15.226c.388.645.793 1.273 1.206 1.894l.041.065.015.023c.014.02.026.042.04.063l.004.006.101.148.006.009.003.004c.439.649.89 1.288 1.355 1.91l.031.04.03.039a45.939 45.939 0 0 0 1.351 1.715l.158.191c.2.239.4.477.604.713.087.101.178.202.266.302.174.198.346.395.524.59.097.107.198.215.297.322l.135.146c.13.14.259.28.39.419.052.055.107.109.16.164.23.24.462.48.699.716l20.85-20.85a17.977 17.977 0 [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#4d5a31"}
- d="M107.642 202.627c-.229.185-.461.366-.697.54l.052.087 15.202 25.235c.704-.46 1.4-.934 2.08-1.432a50.463 50.463 0 0 0 4.267-3.527l-20.821-20.821z"
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#93d500"}
- d="m74.961 105.035-.006.003.015-.008a.024.024 0 0 1-.009.005zM75.004 105.012c.066-.039.133-.072.198-.112-.065.04-.132.075-.198.112z"
- />
- <path
- fill={fill ?? "#93d500"}
- d="m119.99 228.696-.516-.856-14.19-23.555c-.287.173-.581.329-.874.487a20.15 20.15 0 0 1-9.528 2.404c-1.936 0-3.871-.28-5.742-.838-.319-.095-.63-.22-.945-.332-.315-.111-.634-.207-.944-.335l-10.464 25.412-.41.996-.351.853-.002.004.082.031.086.033h.001l.002.001.02.008c.247.101.496.188.744.285.311.121.622.244.934.358.159.058.317.126.476.182h.001a49.947 49.947 0 0 0 10.119 2.422c.135.016.269.035.404.054l.424.046c.266.03.531.061.798.087l.198.017c.327.031.654.059.979.082.111.008 [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#4d5a31"}
- d="M59.838 151.994c-.237.237-.461.482-.692.722-.231.24-.466.479-.692.723a49.743 49.743 0 0 0-4.212 5.22c-.061.085-.122.174-.182.261a49.018 49.018 0 0 0-1.008 1.522 49.48 49.48 0 0 0-7.7 24.627c-.013.333-.02.667-.027 1-.007.333-.017.667-.017 1h29.488c0-.334.031-.666.048-1 .017-.334.022-.668.055-1a20.013 20.013 0 0 1 4.447-10.739c.21-.256.447-.496.672-.743.224-.247.432-.504.671-.742zM120.681 144.675l-.122-.073c-.259-.159-.521-.312-.783-.465-.152-.088-.304-.173-.457-.26-.154 [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#6ba43a"}
- d="M93.914 137.485c-.333.007-.667.008-1 .021a49.856 49.856 0 0 0-6.233.643l-.136.023c-.29.05-.577.103-.865.157-.163.031-.327.061-.49.094-.17.034-.339.069-.508.106-.28.058-.56.119-.84.184l-.153.034a49.891 49.891 0 0 0-11.898 4.438h-.001c-.245.13-.484.277-.728.411-.292.16-.582.325-.872.491-.215.124-.434.238-.648.366l-.007.004h-.001l-.045.026c-.056.034-.114.062-.17.096l.003.005.516.857 14.705 24.412c.287-.173.581-.33.874-.487.295-.159.594-.308.895-.451a20.051 20.051 0 0 1 7. [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#4d5a31"}
- d="M144.458 184.631a53.77 53.77 0 0 0-.048-.795c-.008-.132-.015-.263-.026-.397a41.966 41.966 0 0 0-.077-.934c-.006-.081-.014-.161-.021-.242a60.396 60.396 0 0 0-.111-1.043l-.01-.084-.005-.04c-.046-.375-.096-.75-.149-1.124-.001-.011-.002-.025-.005-.035a49.558 49.558 0 0 0-1.524-6.972l-.014-.044c-.107-.356-.216-.71-.328-1.063-.015-.046-.031-.093-.045-.14a66.772 66.772 0 0 0-.412-1.212 50.701 50.701 0 0 0-.714-1.892c-.072-.18-.144-.357-.218-.534-.072-.176-.146-.35-.22-.526a80 [...]
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#6ba43a"}
- d="M115.03 187.069c0 .334-.031.666-.048 1-.016.334-.022.668-.055 1a20.022 20.022 0 0 1-4.446 10.74c-.21.256-.447.496-.672.743-.224.247-.432.504-.671.742l20.851 20.85c.237-.237.46-.482.691-.723.231-.241.466-.479.691-.723a49.783 49.783 0 0 0 4.224-5.236l.148-.214c.155-.223.306-.448.458-.673.133-.201.266-.402.395-.605.064-.097.128-.198.19-.295a49.46 49.46 0 0 0 7.685-24.607c.013-.333.02-.667.027-1 .007-.333.017-.666.017-1H115.03Z"
- style={{
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- <path
- fill={fill ?? "#424143"}
- d="M153.276 128.706c-5.395-5.395-14.142-5.395-19.536 0-4.304 4.303-5.164 10.736-2.601 15.902L101.048 174.7c-5.166-2.562-11.599-1.703-15.903 2.6-5.395 5.395-5.394 14.142 0 19.537 5.396 5.395 14.143 5.393 19.538-.001 4.303-4.303 5.162-10.736 2.599-15.903l30.091-30.091c5.167 2.562 11.599 1.703 15.902-2.601 5.395-5.392 5.395-14.14.001-19.535z"
- style={{
- fill: fill ?? "#424143",
- fillOpacity: 1,
- }}
- transform="translate(-45.308 -124.66)"
- />
- </svg>
- )
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/OtherIcons.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/OtherIcons.tsx
deleted file mode 100644
index 1e10e7ae..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/icons/OtherIcons.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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';
-
-export function AutoStartupFalseIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="24px" height="24px">
- <circle cx="16" cy="16" r="13" fill="var(--pf-t--global--background--color--primary--default)" stroke="var(--pf-t--global--text--color--regular)" strokeWidth="1px"/>
- <rect x="12" y="10" width="2" height="12" fill="black"/>
- <rect x="18" y="10" width="2" height="12" fill="black"/>
- </svg>
- );
-}
-
-export function ErrorHandlerIcon() {
- return (
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" className="icon" width="24px" height="24px">
- <circle cx="16" cy="16" r="13" fill="var(--pf-t--global--background--color--primary--default)" stroke="var(--pf-t--global--text--color--regular)" strokeWidth="1px"/>
- <path d="m19.264 14.98-3.998 7-1.736-1 2.287-4h-3.889l3.993-7 1.737 1-2.284 4z"/>
- </svg>
- );
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletAnnotationsPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletAnnotationsPanel.tsx
deleted file mode 100644
index 96dffbca..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletAnnotationsPanel.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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 {
- Card,
- CardBody,
- CardTitle,
- Form, Grid,
-} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-import {useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import { KameletInput } from './KameletInput';
-
-const PREFIX = 'camel.apache.org/';
-
-export function KameletAnnotationsPanel() {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
-
- function setValue(key: string, value: string) {
- if (key && value && value.length > 0) {
- (integration.metadata.annotations as any)[PREFIX + key] = value;
- setIntegration(integration, true);
- }
- }
-
- function getValue(key: string): string {
- const annotations = integration.metadata.annotations;
- if (annotations) {
- return (annotations as any)[PREFIX + key];
- } else {
- return '';
- }
- }
-
- function getElement(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='text' isRequired={true}/>);
- }
-
- function getElementToggleGroup(key: string, label: string, values: string[], span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='toggle' options={values} isRequired={true}/>);
-
- }
-
- function getElementIcon(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
-
- return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='icon' isRequired={true}/>);
- }
-
- return (
- <Card isCompact ouiaId="AnnotationsCard">
- <CardTitle>Annotations</CardTitle>
- <CardBody>
- <Form>
- <Grid hasGutter md={6}>
- {getElementToggleGroup('kamelet.support.level', 'Support Level', ['Preview', 'Stable'], 2)}
- {getElementIcon('kamelet.icon', 'Icon', 10)}
- {getElement('catalog.version', 'Version', 3)}
- {getElement('provider', 'Provider', 3)}
- {getElement('kamelet.group', 'Group', 3)}
- {getElement('kamelet.namespace', 'Namespace', 3)}
- </Grid>
- </Form>
- </CardBody>
- </Card>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionPropertyCard.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionPropertyCard.tsx
deleted file mode 100644
index 148b98c3..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionPropertyCard.tsx
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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, {useState} from 'react';
-import {Button, Card, CardBody, CardTitle, Flex, FlexItem, FormGroup, FormSelect, FormSelectOption, Grid, GridItem, Label, LabelGroup, Switch} from '@patternfly/react-core';
-import './kamelet.css';
-import {useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {DefinitionProperty} from "@karavan-core/model/IntegrationDefinition";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {PlusCircleIcon} from '@patternfly/react-icons';
-import {KameletInput} from './KameletInput';
-import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
-
-interface Props {
- index: number
- propKey: string
- property: DefinitionProperty
-}
-
-export function KameletDefinitionPropertyCard(props: Props) {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
- const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
-
- const key = props.propKey;
- const required = integration.spec.definition?.required || [];
-
- function setPropertyValue(field: string, value: any) {
- if (integration.spec.definition?.properties) {
- (integration.spec.definition?.properties as any)[key][field] = value;
- setIntegration(integration, true);
- }
- }
-
- function getPropertyValue(field: string) {
- const properties: any = integration.spec.definition?.properties;
- if (properties) {
- return properties[key][field];
- }
- return undefined;
- }
-
-
- function getPropertyField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (<KameletInput elementKey={key + field} label={label} span={span} value={getPropertyValue(field)} setValue={(value: string) => setPropertyValue(field, value)}
- type='text' isRequired={isRequired}/>);
- }
-
- function getPropertyTypeField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (
- <GridItem span={span}>
- <FormGroup label={label} fieldId={key + field} isRequired={isRequired}>
- <FormSelect
- value={getPropertyValue(field)}
- onChange={(_, value) => setPropertyValue(field, value)}
- aria-label="FormSelect Input"
- ouiaId="BasicFormSelect"
- >
- {['string', 'number', 'integer', 'boolean'].map((option, index) => (
- <FormSelectOption key={option} isDisabled={false} id={key + field} name={key + field}
- value={option} label={option}/>
- ))}
- </FormSelect>
- </FormGroup>
- </GridItem>
- )
- }
-
- function sortEnum(source: string, dest: string) {
- const i = CamelUtil.cloneIntegration(integration);
- if (i.spec.definition && integration.spec.definition?.properties[key]) {
- const enums: string [] = i.spec.definition.properties[key].enum;
- if (enums && Array.isArray(enums)) {
- const from = enums.findIndex(e => source);
- const to = enums.findIndex(e => dest);
- if (from > -1 && to > -1) {
- [enums[from], enums[to]] = [enums[to], enums[from]];
- i.spec.definition.properties[key].enum = enums;
- setIntegration(i, true);
- }
- }
- }
- }
-
- function addEnum() {
- const i = CamelUtil.cloneIntegration(integration);
- if (i.spec.definition && integration.spec.definition?.properties[key]) {
- let enums: string [] = i.spec.definition.properties[key].enum;
- if (enums && Array.isArray(enums)) {
- enums.push("enum")
- } else {
- enums = ['enum'];
- }
- i.spec.definition.properties[key].enum = enums;
- setIntegration(i, true);
- }
- }
-
- function deleteEnum(val: string) {
- const enumVal = getPropertyValue('enum');
- const i = CamelUtil.cloneIntegration(integration);
- if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
- const enums: string[] = [...enumVal];
- setPropertyValue('enum', enums.filter(e => e !== val));
- }
- }
-
- function renameEnum(index: number, newVal: string) {
- const enumVal = getPropertyValue('enum');
- const i = CamelUtil.cloneIntegration(integration);
- if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
- const enums: string[] = [...enumVal];
- enums[index] = newVal;
- setPropertyValue('enum', enums);
- }
- }
-
- function getPropertyEnumField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- const enumVal = getPropertyValue(field);
- return (
- <GridItem span={span}>
- <FormGroup fieldId={key + field} isRequired={isRequired}>
- <LabelGroup
- categoryName={label}
- numLabels={enumVal?.length || 0}
- isEditable
- addLabelControl={
- <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addEnum()}>
- Add
- </Button>
- }
- >
- {enumVal && enumVal.map((val: string, index: number) => (
- <Label
- key={val}
- id={val}
- color="grey"
- isEditable
- onClose={() => deleteEnum(val)}
- onEditCancel={(_event, prevText) => {
- }}
- onEditComplete={(event, newText) => {
- if (event.type === 'mousedown') {
- renameEnum(index, val)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
- renameEnum(index, newText)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
- renameEnum(index, newText)
- } else {
- renameEnum(index, val)
- }
- }}
- >
- {val}
- </Label>
- ))}
- </LabelGroup>
- </FormGroup>
- </GridItem>
- )
- }
-
- function renameProperty(newKey: string) {
- const oldKey = key;
- newKey = newKey.replace(/[\W_]+/g, '');
- if (oldKey !== newKey) {
- if (integration.spec.definition?.properties) {
- const o = (integration.spec.definition?.properties as any)
- const newObject: any = {};
- Object.keys(o).forEach(k => {
- if (k !== oldKey) {
- newObject[k] = o[k];
- } else {
- newObject[newKey] = o[k];
- }
- })
- integration.spec.definition.properties = newObject;
-
- if (required.includes(oldKey)) {
- const newRequired = [...required];
- const index = newRequired.findIndex(r => r === oldKey);
- newRequired.splice(index, 1);
- newRequired.push(newKey)
- integration.spec.definition.required = newRequired;
- }
- setIntegration(integration, true);
- }
- }
- }
-
- function deleteProperty() {
- if (integration.spec.definition?.properties) {
- integration.spec.definition.required = integration.spec.definition.required.filter(r => r !== key);
- delete integration.spec.definition.properties[key];
- setIntegration(integration, true);
- }
- }
-
- function setRequired(checked: boolean) {
- const newRequired = [...required];
- if (checked && !newRequired.includes(key)) {
- newRequired.push(key);
- } else if (!checked && newRequired.includes(key)) {
- const index = newRequired.findIndex(r => r === key);
- newRequired.splice(index, 1);
- }
- if (integration.spec.definition !== undefined) {
- integration.spec.definition.required = newRequired;
- }
- setIntegration(integration, true);
- }
-
- function getTitle() {
- return (
- <Flex>
- <FlexItem>
- <Label
- color="blue"
- onClose={() => {
- setShowDeleteConfirmation(true);
- }}
- closeBtnAriaLabel="Delete Property"
- onEditCancel={(_, previousText) => {
- }}
- onEditComplete={(event, newText) => {
- if (event.type === 'mousedown') {
- renameProperty(newText)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
- renameProperty(newText)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
- renameProperty(newText)
- } else {
- renameProperty(key)
- }
- }}
- isEditable
- editableProps={{
- 'aria-label': `Editable property with text ${key}`,
- id: 'editable-property'
- }}
- >
- {key}
- </Label>
- </FlexItem>
- <FlexItem align={{default: "alignRight"}}>
- <Switch
- label={"Required"}
- isChecked={required.includes(key)}
- onChange={(_, checked) => setRequired(checked)}
- isReversed
- />
- </FlexItem>
- </Flex>
- )
- }
-
-
- return (
- <Card isClickable isCompact ouiaId="PropertyCard" className="property-card">
- <CardTitle>
- {getTitle()}
- </CardTitle>
- <CardBody>
- <Grid hasGutter>
- {getPropertyField("title", "Title", true, 3)}
- {getPropertyField("description", "Description", true, 6)}
- {getPropertyTypeField("type", "Type", true, 3)}
- {getPropertyField("format", "Format", false, 3)}
- {getPropertyField("example", "Example", false, 6)}
- {getPropertyField("default", "Default", false, 3)}
- {getPropertyValue('type') === 'string' && getPropertyEnumField("enum", "Enum", true, 12)}
- {/*{getPropertyField("x-descriptors", "Descriptors", false, 12)}*/}
- </Grid>
- </CardBody>
- <ModalConfirmation
- isOpen={showDeleteConfirmation}
- message={`Delete ${key} property?`}
- btnConfirm='Delete'
- btnConfirmVariant='danger'
- onConfirm={() => deleteProperty()}
- onCancel={() => setShowDeleteConfirmation(false)}
- />
- </Card>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionsPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionsPanel.tsx
deleted file mode 100644
index 0cf3391a..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDefinitionsPanel.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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, CardBody, CardTitle, Flex, FlexItem, Form, Grid,} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-import {useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {PlusCircleIcon} from '@patternfly/react-icons';
-import {KameletDefinitionPropertyCard} from "./KameletDefinitionPropertyCard";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {DefinitionProperty} from "@karavan-core/model/IntegrationDefinition";
-import {KameletDependenciesCard} from "./KameletDependenciesCard";
-import {KameletInput} from './KameletInput';
-
-export function KameletDefinitionsPanel() {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
-
- function setValue(key: string, value: string) {
- if (key && value && value.length > 0) {
- (integration.spec.definition as any)[key] = value;
- setIntegration(integration, true);
- }
- }
-
- function getValue(key: string): string {
- const annotations = integration.spec.definition;
- if (annotations) {
- return (annotations as any)[key];
- } else {
- return '';
- }
- }
-
- function getElementTextInput(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='text' isRequired={true}/>);
-
- }
-
- function getElementTextArea(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
- return (<KameletInput elementKey={key} label={label} span={span} value={getValue(key)} setValue={(value: string) => setValue(key, value)} type='textArea' isRequired={true}/>);
-
- }
-
- const properties = integration.spec.definition?.properties ? Object.keys(integration.spec.definition?.properties) : [];
-
- function addNewProperty() {
- const i = CamelUtil.cloneIntegration(integration);
- if (i.spec.definition && integration.spec.definition?.properties) {
- const propertyName = generatePropertyName();
- i.spec.definition.properties = Object.assign({[propertyName]: new DefinitionProperty()}, integration.spec.definition.properties);
- setIntegration(i, true);
- }
- }
-
- function generatePropertyName(count: number = 0): string {
- const prefix = 'property';
- const propName = 'property' + count;
- if (integration.spec.definition?.properties) {
- const keys = Object.keys(integration.spec.definition?.properties);
- if (keys.includes(propName)) {
- return generatePropertyName(count + 1);
- } else {
- return propName;
- }
- }
- return prefix;
- }
-
- return (
- <>
- <Card isCompact ouiaId="DefinitionsCard">
- <CardTitle>Definitions</CardTitle>
- <CardBody>
- <Form>
- <Grid hasGutter>
- {getElementTextInput('title', 'Title', 3)}
- {getElementTextArea('description', 'Description', 9)}
- {/*{getElementTextInput('type', 'Type', 2)}*/}
- </Grid>
- </Form>
- </CardBody>
- </Card>
- <Card isCompact ouiaId="PropertiesCard">
- <CardTitle>
- <Flex>
- <FlexItem>Properties</FlexItem>
- <FlexItem align={{default: "alignRight"}}>
- <Button variant={"link"} icon={<PlusCircleIcon/>} onClick={event => addNewProperty()}>
- Add property
- </Button>
- </FlexItem>
- </Flex>
- </CardTitle>
- <CardBody>
- <Form>
- {properties.map((key: string, index: number) => {
- const property = (integration.spec.definition?.properties as any)[key];
- return <KameletDefinitionPropertyCard key={key}
- index={index}
- propKey={key}
- property={property}/>
- })}
- </Form>
- </CardBody>
- </Card>
- <KameletDependenciesCard/>
- </>
-
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDependenciesCard.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDependenciesCard.tsx
deleted file mode 100644
index 6fc2c50a..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDependenciesCard.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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, CardBody, CardTitle, FormGroup, FormHelperText, HelperText, HelperTextItem, Label, LabelGroup,} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-import {useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {PlusCircleIcon} from '@patternfly/react-icons';
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-
-export function KameletDependenciesCard() {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
-
- const dependencies: string[] = [...(integration.spec.dependencies || [])];
-
-
- function setDependencies(deps: string[]) {
- const i = CamelUtil.cloneIntegration(integration);
- i.spec.dependencies = deps;
- setIntegration(i, true);
- }
-
- function addDepencency() {
- dependencies.push("dependency")
- setDependencies(dependencies);
- }
-
- function deleteDependency(val: string) {
- setDependencies(dependencies.filter(e => e !== val));
- }
-
- function renameDependency(index: number, newVal: string) {
- dependencies[index] = newVal;
- setDependencies(dependencies);
- }
-
- return (
- <Card isCompact ouiaId="PropertyCard">
- <CardTitle>
- Dependencies
- </CardTitle>
- <CardBody>
- <FormHelperText>
- <HelperText>
- <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
- </HelperText>
- </FormHelperText>
- </CardBody>
- <CardBody>
- <FormGroup fieldId={'dependencies'}>
- <LabelGroup
- // categoryName={"Dependencies"}
- numLabels={dependencies.length}
- isEditable
- addLabelControl={
- <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addDepencency()}>
- Add
- </Button>
- }
- >
- {dependencies.map((val: string, index: number) => (
- <Label
- key={val}
- id={val}
- color="grey"
- isEditable
- onClose={() => deleteDependency(val)}
- onEditCancel={(_event, prevText) => {}}
- onEditComplete={(event, newText) => {
- if (event.type === 'mousedown') {
- renameDependency(index, val)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
- renameDependency(index, newText)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
- renameDependency(index, newText)
- } else {
- renameDependency(index, val)
- }
- }}
- >
- {val}
- </Label>
- ))}
- </LabelGroup>
- </FormGroup>
- </CardBody>
- </Card>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDesigner.tsx
deleted file mode 100644
index 4c88c133..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletDesigner.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 {
- PageSection,
-} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-import {KameletAnnotationsPanel} from "./KameletAnnotationsPanel";
-import {KameletDefinitionsPanel} from "./KameletDefinitionsPanel";
-
-export function KameletDesigner() {
-
- return (
- <div className="kamelet-designer">
- <div className="main">
- <KameletAnnotationsPanel/>
- <KameletDefinitionsPanel/>
- </div>
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletInput.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletInput.tsx
deleted file mode 100644
index 7b57caab..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletInput.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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, {useEffect, useState} from "react";
-import {
- GridItem,
- FormGroup,
- InputGroup,
- InputGroupItem,
- TextInput,
- InputGroupText,
- ToggleGroup,
- ToggleGroupItem,
- capitalize,
- TextArea
-} from "@patternfly/react-core";
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-
-interface Props {
- label: string;
- type: string;
- span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
- elementKey: string;
- value: any;
- isRequired: boolean;
- options?: string[];
- setValue: (value: string) => void;
-}
-
-export function KameletInput(props: Props) {
-
- const [inputValue, setInputValue] = useState(props.value);
- const [checkChanges, setCheckChanges] = useState<boolean>(false);
-
- useEffect(()=> {
- if (checkChanges) {
- const interval = setInterval(() => {
- if (props.value !== inputValue) {
- saveValue(inputValue);
- }
- }, 1000);
- return () => {
- clearInterval(interval)
- }
- }
- }, [checkChanges, inputValue])
-
- function saveValue(value?: string) {
- setCheckChanges(false)
- props.setValue(value ? value : inputValue);
- }
-
- function getTextField() {
- return (
- <InputGroup>
- <InputGroupItem isFill>
- <TextInput className="text-field" type="text" id={props.elementKey} name={props.elementKey}
- onChange={(_, value) => {
- setInputValue(value);
- setCheckChanges(true);
- }}
- onBlur={() => saveValue()}
- value={inputValue}/>
- </InputGroupItem>
- </InputGroup>
- )
- }
-
- function getTextArea() {
- return (<InputGroup>
- <InputGroupItem isFill> <TextArea type="text" id={props.elementKey} name={props.elementKey} autoResize
- onChange={(_, value) => {
- setInputValue(value);
- setCheckChanges(true);
- }}
- onBlur={() => saveValue()}
- value={inputValue}/></InputGroupItem></InputGroup>)
- }
-
- function getIcon() {
- return (<InputGroup>
- <InputGroupText id="username">
- <svg className="icon">
- <image href={props.value} className="icon"/>
- </svg>
- </InputGroupText>
- <InputGroupItem isFill>
- <TextInput className="text-field" type="text" id={props.elementKey} name={props.elementKey}
- onChange={(_, value) => setInputValue(value)}
- onBlur={() => saveValue()}
- value={inputValue}/>
- </InputGroupItem>
- </InputGroup>);
- }
-
- function getToggleGroup() {
- return (<ToggleGroup aria-label={props.elementKey} id={props.elementKey} name={props.elementKey}>
- {props.options?.map((option: string) =>
- <ToggleGroupItem
- key={option}
- text={capitalize(option)}
- buttonId="toggle-group-single-1"
- isSelected={inputValue === option}
- onChange={(_, selected) => {
- setInputValue(option);
- saveValue(option);
- setCheckChanges(false);
- }}
- />
- )}
- </ToggleGroup>)
- }
-
- return (
- <GridItem span={props.span}>
- <FormGroup label={props.label} fieldId={props.elementKey} isRequired={props.isRequired}>
- {props.type === 'text' && getTextField()}
- {props.type === 'icon' && getIcon()}
- {props.type === 'toggle' && getToggleGroup()}
- {props.type === 'textArea' && getTextArea()}
- </FormGroup>
- </GridItem>
- )
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletTypesOutCard.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletTypesOutCard.tsx
deleted file mode 100644
index 80f1bbb1..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/KameletTypesOutCard.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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, CardBody, CardTitle, FormGroup, FormHelperText, HelperText, HelperTextItem, Label, LabelGroup,} from '@patternfly/react-core';
-import '@features/integration/designer/karavan.css';
-import './kamelet.css';
-import {useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {PlusCircleIcon} from '@patternfly/react-icons';
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-
-export function KameletTypesOutCard() {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
-
- const dependencies: string[] = [...(integration.spec.dependencies || [])];
-
-
- function setDependencies(deps: string[]) {
- const i = CamelUtil.cloneIntegration(integration);
- i.spec.dependencies = deps;
- setIntegration(i, true);
- }
-
- function addDepencency() {
- dependencies.push("dependency")
- setDependencies(dependencies);
- }
-
- function deleteDependency(val: string) {
- setDependencies(dependencies.filter(e => e !== val));
- }
-
- function renameDependency(index: number, newVal: string) {
- dependencies[index] = newVal;
- setDependencies(dependencies);
- }
-
- return (
- <Card isClickable isCompact ouiaId="PropertyCard" className="property-card">
- <CardTitle>
- Dependencies
- </CardTitle>
- <CardBody>
- <FormHelperText>
- <HelperText>
- <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
- </HelperText>
- </FormHelperText>
- </CardBody>
- <CardBody>
- <FormGroup fieldId={'dependencies'}>
- <LabelGroup
- // categoryName={"Dependencies"}
- numLabels={dependencies.length}
- isEditable
- addLabelControl={
- <Button variant="link" icon={<PlusCircleIcon/>} onClick={event => addDepencency()}>
- Add
- </Button>
- }
- >
- {dependencies.map((val: string, index: number) => (
- <Label
- key={val}
- id={val}
- color="grey"
- isEditable
- onClose={() => deleteDependency(val)}
- onEditCancel={(_event, prevText) => {}}
- onEditComplete={(event, newText) => {
- if (event.type === 'mousedown') {
- renameDependency(index, val)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
- renameDependency(index, newText)
- } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
- renameDependency(index, newText)
- } else {
- renameDependency(index, val)
- }
- }}
- >
- {val}
- </Label>
- ))}
- </LabelGroup>
- </FormGroup>
- </CardBody>
- </Card>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/kamelet.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/kamelet.css
deleted file mode 100644
index f909f7ee..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/kamelet/kamelet.css
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.
- */
-
-.karavan .kamelet-designer {
- display: block;
- height: 100vh;
- width: 100%;
- overflow-y: auto;
- padding: 16px 16px 106px 16px;
-}
-
-.karavan .kamelet-designer .main {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-.karavan .kamelet-designer .icon {
- height: 20px;
- width: 20px;
- border: none;
- -webkit-user-select: none;
- user-select: none;
-}
-
-/*.karavan .kamelet-designer .properties {*/
-/* padding: 10px 10px 10px 10px;*/
-/* background: transparent;*/
-/* width: 100%;*/
-/* height: 100%;*/
-/* overflow: auto;*/
-/* display: flex;*/
-/* flex-direction: column;*/
-/* justify-content: space-between;*/
-/*}*/
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/karavan.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/karavan.css
deleted file mode 100644
index 9729ffe9..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/karavan.css
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * 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.
- */
-/*:root {*/
- /*--pf-v6-global--FontSize--md: 14px;*/
- /*--pf-v6-c-page__main-section--PaddingTop: 1em;*/
- /*--pf-v6-c-page__main-section--PaddingBottom: 1em;*/
- /*--pf-v6-c-page__main-section--PaddingLeft: 1em;*/
- /*--pf-v6-c-page__main-section--PaddingRight: 1em;*/
-/*}*/
-
-.karavan .tools-section {
- padding: 0 0 0 16px;
-}
-
-.karavan .tools-section-wrapper {
- padding: 0 0 0 16px;
- border-bottom: 1px solid #eee;
- background-color: white;
-}
-.karavan .tools-section-tabs {
- padding: 0;
- border-bottom: 1px solid #eee;
- background-color: white;
-}
-
-.karavan .tools-section .dsl-title {
- display: flex;
- flex-direction: row;
-}
-
-.karavan .tools-section .dsl-title .title {
- margin-right: 16px;
-}
-
-.karavan .tools-section .tools .header {
- display: flex;
- flex-direction: row;
-}
-
-.karavan .tools-section .tools .header .labels {
- height: fit-content;
- margin-left: 3px;
-}
-
-.karavan .brand {
- height: 36px;
-}
-
-.karavan .pf-v6-c-switch__input:focus ~ .pf-v6-c-switch__toggle,
-.pf-v6-c-modal-box .pf-v6-c-switch__input:focus ~ .pf-v6-c-switch__toggle {
- outline: transparent;
- outline-offset: 0;
-}
-
-.karavan .header-button {
- /*margin-left: var(--pf-v6-c-page__header-tools--MarginRight);*/
-}
-
-.karavan .page-header {
- display: flex;
- justify-content: space-between;
-}
-
-.karavan .page-header .top-toolbar .pf-v6-c-page__header-tools {
- margin-right: 0;
-}
-
-.karavan .page-header .top-toolbar {
- width: 100%;
-}
-
-.karavan .page-header .pf-v6-c-page__header-brand {
- padding-right: 16px;
-}
-
-.filler {
- width: 100%;
-}
-
-.modal-footer {
- width: 100%;
-}
-
-.modal-footer .deploy-buttons .pf-v6-c-form__actions {
- justify-content: flex-end;
- margin-top: 16px;
-}
-
-.modal-footer .deploy-buttons .pf-v6-c-button {
- margin-left: 16px;
-}
-
-.action-buttons .pf-v6-c-form__actions {
- justify-content: flex-end;
- margin-top: 16px;
-}
-
-.action-buttons .pf-v6-c-button {
- margin-left: 16px;
-}
-
-.pf-v6-c-modal-box__footer .hidden {
- display: none;
-}
-
-.upload-buttons .pf-v6-c-form__actions {
- margin-top: 20px;
- justify-content: flex-end;
-}
-
-/*integration page*/
-.integration-page .integration-card {
- cursor: pointer;
- height: 160px;
-}
-
-.integration-page .integration-card .pf-v6-c-card__header {
- padding-right: 6px;
-}
-
-.integration-page .integration-card .icon {
- height: 24px;
-}
-
-.integration-page .integration-card .delete-button {
- font-size: 17px;
- line-height: 1;
- border: 0;
- padding: 0;
- margin: 0;
- background: transparent;
- color: #b1b1b7;
- visibility: hidden;
-}
-
-.integration-page .integration-card:hover .delete-button {
- visibility: visible;
-}
-
-/*kamelets*/
-.kamelets-page .kamelet-card {
- cursor: pointer;
- height: 160px;
-}
-
-.kamelets-page .kamelet-card .pf-v6-c-card__header .custom {
- margin-left: auto;
-}
-
-.kamelets-page .kamelet-card .pf-v6-c-card__header .pf-v6-c-card__header-main {
- display: flex;
- flex-direction: row;
-}
-
-.kamelets-page .kamelet-card .pf-v6-c-card__title {
- font-size: 15px;
- font-weight: 400;
-}
-
-.kamelets-page .kamelet-card .pf-v6-c-card__body {
- overflow: hidden;
- position: relative;
- line-height: 1.6em;
-}
-
-.kamelets-page .kamelet-card .icon {
- height: 24px;
- max-width: 24px;
- margin-top: auto;
- margin-bottom: auto;
- margin-right: 5px;
- border: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
-}
-
-.kamelets-page .kamelet-card .header-labels {
- padding: 5px;
- display: flex;
- flex-direction: row;
- justify-content: flex-end;
-}
-
-.kamelets-page .kamelet-card .header-labels .pf-v6-c-card__header-main {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-
-.kamelets-page .kamelet-card .footer-labels {
- padding: 5px;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
-}
-
-.kamelets-page .kamelet-card .version,
-.kamelets-page .kamelet-card .support-type,
-.kamelets-page .kamelet-card .support-level {
- white-space: nowrap;
-}
-
-.kamelets-page .kamelet-card .labels {
- opacity: 0.5;
- font-weight: 200;
-}
-
-.kamelets-page .kamelet-card:hover .labels {
- opacity: 1;
-}
-
-/*kamelet modal*/
-.kamelet-modal-card .pf-v6-c-card__header {
- padding-right: 6px;
- display: flex;
- justify-content: space-between;
-}
-
-.kamelet-modal-card .pf-v6-c-card__title {
- font-weight: 600;
-}
-
-.kamelet-modal-card .description {
- overflow: hidden;
- position: relative;
- max-width: 600px;
-}
-
-.kamelet-modal-card .icon {
- height: 36px;
- width: 36px;
- margin-top: auto;
- margin-bottom: auto;
- border: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
-}
-
-.karavan .page {
- height: 100vh;
- width: 100%;
- overflow: hidden;
- display: flex;
- flex-direction: column;
-}
-
-.karavan main {
- overflow: hidden;
-}
-
-
-
-.element-builder .add-button {
- top: 0;
- right: 5px;
- font-size: 15px;
- line-height: 1;
- border: 0;
- padding: 0;
- margin: 3px auto 0 auto;
- background: transparent;
- visibility: hidden;
- height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: flex-end;
- width: 16px;
-}
-
-.element-builder .add-button svg {
- margin: 0 auto 3px auto;
-}
-
-.element-builder:hover .add-button,
-.dsl-gallery {
- margin-top: 16px;
-}
-
-.move-modal {
- width: 270px !important;
-}
-
-.move-modal .pf-v6-c-modal-box__body {
- margin-right: 0 !important;
-}
-
-.move-modal .pf-v6-m-plain {
- display: none;
-}
-
-.yaml-code {
- overflow: auto;
- height: 100%;
- width: 100%;
- padding-bottom: 100px;
-}
-
-.pf-v6-c-popover__footer {
- overflow-wrap: anywhere;
-}
-
-/*YAML*/
-.karavan .yaml-page {
- height: 100px;
-}
-
-
-/* Help */
-.dont-show {
- margin-right: auto;
-}
-
-/* Project Tools */
-.karavan .project-builder {
- height: 100%;
-}
-
-.karavan .project-builder .tools-section {
- padding-left: 10px;
- padding-right: 10px;
-}
-
-.karavan .project-builder .pf-v6-c-toolbar__content {
- padding: 0;
-}
-
-.karavan .project-builder .card-header svg {
- margin-right: 6px;
-}
-
-.karavan .project-builder .card-disabled {
- opacity: 0.4;
-}
-
-.karavan .project-builder .pf-v6-c-form {
- --pf-v6-c-form--GridGap: 1em;
-}
-
-.karavan .project-builder .pf-v6-c-card__body {
- --pf-v6-c-card--child--PaddingRight: 0.5em;
- --pf-v6-c-card--child--PaddingBottom: 1em;
- --pf-v6-c-card--child--PaddingLeft: 1em;
-}
-
-.karavan .project-builder .pf-v6-c-card__header {
- --pf-v6-c-card--first-child--PaddingTop: 0.5em;
-}
-
-.karavan .project-builder .center {
- height: 100%;
- width: 100%;
- display: flex;
- flex-direction: row;
- gap: 10px;
- padding: 10px;
-}
-
-.karavan .project-builder .center-column {
- width: 100%;
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-
-.karavan .project-builder .footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- padding: 10px;
-}
-
-.karavan .project-builder .footer .progress {
- flex-grow: 4;
-}
-
-.karavan .project-builder .footer .buttons {
- height: 60px;
- display: flex;
- flex-direction: column;
- justify-content: space-around;
-}
-
-.karavan .project-builder .project-properties td {
- padding: 0;
- margin: 0;
-}
-
-.karavan .project-builder .project-properties td,
-.karavan .project-builder .project-properties tr {
- border: none;
-}
-
-.karavan .project-builder .project-properties .delete-button {
- padding: 0 0 0 6px;
- margin: 0;
-}
-
-.karavan .project-builder .add-button {
- width: fit-content;
- margin-top: 6px;
-}
-
-.root .tooltip-required-field .pf-v6-c-tooltip__content {
- text-align: start;
-}
-
-.karavan .kamelet-section {
- display: flex;
- flex-direction: column;
- height: 100%;
-}
-
-.karavan .kamelets-page {
- overflow: auto;
- flex-shrink: unset;
- flex-grow: 1;
- margin-bottom: 100px;
-}
-
-.karavan .scrolled-page {
- overflow: auto;
- flex-shrink: unset;
- flex-grow: 1;
-}
-
-.karavan .knowledbase-eip-section .pf-v6-c-toggle-group {
- margin: 16px;
-}
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- appearance: none;
- margin: 0;
-}
-
-.resize-handler {
- background-color: var(--pf-t--global--border--color--default);
- width: 1px;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.css
deleted file mode 100644
index cf7ef7ab..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.css
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * 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.
- */
-
-/*Properties*/
-
-.karavan .main-properties {
- width: 100%;
- height: 100%;
- padding-bottom: 64px;
- border-left-color: var(--pf-t--global--border--color--default);
- border-left-style: solid;
- border-left-width: var(--pf-t--global--border--width--box--default);
-}
-
-.karavan .main-properties .main-tabs-wrapper .main-tabs .top-menu-item {
- display: flex;
- flex-direction: row;
- justify-content: center;
- width: 100%;
-}
-
-.karavan .main-properties .main-tabs-wrapper .main-tabs .top-menu-item .count {
- background: var(--pf-t--global--color--brand--default);
- color: white;
- height: fit-content;
- margin-top: auto;
- margin-bottom: auto;
- min-width: 0;
-}
-
-.karavan .main-properties .main-tabs-wrapper .main-tabs .pf-v6-c-tabs__link .pf-v6-c-tabs__item-icon {
- /*height: 24px;*/
- /*margin-right: 0;*/
-}
-
-.karavan .main-properties .main-tabs-wrapper .main-tabs .pf-v6-c-tabs__item-text {
- /*font-weight: bold;*/
- /*margin-top: auto;*/
- /*margin-bottom: auto;*/
- /*margin-right: 6px;*/
-}
-
-.karavan .main-properties .main-tabs-wrapper .hide-log {
- white-space: nowrap;
- margin-right: 16px;
-}
-
-.karavan .properties {
- padding: 8px 8px 8px 8px;
- /*background-color: white;*/
- width: 100%;
- height: 100%;
- overflow: auto;
- /*display: flex;*/
- /*flex-direction: column;*/
- /*justify-content: space-between;*/
-}
-
-.karavan .properties .headers {
- grid-row-gap: 8px;
- row-gap: 8px;
- display: contents;
-}
-
-.karavan .properties .headers .top {
- width: 100%;
- display: flex;
- flex-direction: row;
- /*justify-content: space-between;*/
- align-items: center;
- gap: 8px;
-}
-
-.karavan .properties .headers .top h1 {
- /*width: 100%;*/
- margin-top: auto;
- margin-bottom: auto;
- text-wrap: nowrap;
-}
-
-.karavan .properties .headers .top .pf-v6-c-switch {
- column-gap: 6px;
-}
-
-.karavan .properties .headers .top .description-help-icon {
- /*color: var(--pf-v6-c-form__group-label-help--Color);*/
- cursor: pointer;
-}
-.karavan .properties .headers .top:hover .description-help-icon {
- color: unset;
-}
-
-.karavan .properties .headers .step-type-switch {
- column-gap: 6px;
-}
-
-
-.karavan .properties .footer {
- height: 100%;
- display: contents;
-}
-
-.karavan .properties .pf-v6-c-form {
- row-gap: 10px;
- .pf-v6-c-form__group {
- gap: 0.1em;
- }
-}
-
-.karavan .properties .pf-v6-c-form__group-label {
- display: flex;
- justify-content: space-between;
- .pf-v6-c-form__group-label-help .pf-v6-c-button {
- padding: 0;
- visibility: hidden;
- }
-}
-
-.karavan .properties .component-headers .pf-v6-c-button {
- padding: 0;
-}
-
-.karavan .properties .pf-v6-c-form__group:hover {
- .pf-v6-c-form__group-label-help .pf-v6-c-button {
- visibility: visible;
- }
-}
-
-.karavan .properties .dsl-property-form-group .pf-v6-c-form__label {
- display: flex;
-}
-
-/*ok till there*/
-
-.karavan .properties .pf-v6-c-expandable-section {
- .pf-v6-c-expandable-section__toggle .pf-v6-c-button {
- padding: 1px 0 1px 0;
- }
-}
-.karavan .properties .pf-m-expanded {}
-
-.karavan .properties .pf-v6-c-form-control:focus-within {
- --pf-v6-c-form-control--after--BorderBottomColor: var(--pf-v6-c-form-control--after--BorderBottomColor);
- --pf-v6-c-form-control--after--BorderBottomWidth: var(--pf-v6-c-form-control--after--BorderBottomWidth);
-}
-
-.karavan .properties .pf-v6-c-select {
- --pf-v6-c-select__toggle--FontSize: 14px;
- --pf-v6-c-select__menu-item--FontSize: 14px;
-}
-
-.karavan .properties .input-group .pf-v6-c-text-input-group__text {
- width: 100%;
-}
-
-.karavan .properties .input-group .pf-v6-c-chip-group,
-.karavan .properties .input-group .pf-v6-c-text-input-group__main,
-.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__list,
-.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__list .pf-v6-c-chip-group__list-item,
-.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip-group__main {
- display: block;
-}
-
-.karavan .properties .input-group .pf-v6-c-chip-group {
- margin-left: 0;
-}
-
-.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip .pf-v6-c-chip__text {
- max-width: inherit;
-}
-
-.karavan .properties .input-group .pf-v6-c-chip-group .pf-v6-c-chip {
- width: 100%;
-}
-
-.karavan .properties .input-group .pf-v6-c-text-input-group__utilities {
- align-items: flex-end;
- margin-top: auto;
-}
-
-.karavan .properties .chip .pf-v6-c-button {
- padding: 4px;
-}
-
-.karavan .properties .expression-title {
- font-size: 17px;
- font-weight: bold;
-}
-
-.karavan .properties .text-area {
- font-size: 13px;
-}
-
-.karavan .properties .pf-v6-c-select__menu-search {
- padding: 0 6px 6px 6px;
-}
-
-.karavan .properties .pf-v6-c-select__toggle-typeahead {
- height: auto;
-}
-
-.karavan .properties .pf-v6-c-select__menu-item {
- /*width: 280px;*/
-}
-
-.karavan .properties .pf-v6-c-select__menu-item-description {
- overflow-wrap: anywhere;
-}
-
-.karavan .properties .number {
- display: flex;
- justify-content: space-between;
-}
-
-.karavan .properties .number .number-property {
- width: 100%;
-}
-
-.karavan .properties .number .clear-button {
- color: #b1b1b7;
- --pf-v6-c-button--BorderRadius: var(--pf-v6-c-button--m-control--BorderRadius);
- --pf-v6-c-button--disabled--BackgroundColor: var(--pf-v6-c-button--m-control--BackgroundColor);
- --pf-v6-c-button--BorderWidth: var(--pf-v6-c-button--m-control--BorderWidth);
- --pf-v6-c-button--BorderColor: var(--pf-v6-c-button--m-control--BorderColor);
- background-color: var(--pf-v6-c-button--m-control--BackgroundColor);
- padding-left: 5px;
- padding-right: 5px;
-}
-
-.karavan .properties .help-button {
- font-size: 12px;
-}
-
-.karavan .properties .component-selector {
- border-width: var(--pf-t--global--border--width--box--default);
- border-top-color: var(--pf-t--global--border--color--default);
- border-right-color: var(--pf-t--global--border--color--default);
- border-bottom-color: var(--pf-t--global--border--color--default);
- border-left-color: var(--pf-t--global--border--color--default);
- border-style: solid;
-}
-
-.karavan .properties .object-value {
- display: flex;
- flex-direction: row;
- /*justify-content: stretch;*/
- /*align-items: center;*/
- padding: 6px 8px 0 0;
- border-width: var(--pf-t--global--border--width--box--default);
- border-color: var(--pf-t--global--border--color--default);
- border-style: solid;
- border-radius: var(--pf-t--global--border--radius--medium);
- position: relative;
-}
-
-.karavan .properties .object-key-value .object {
- padding-top: 0;
-}
-
-.karavan .properties .object-value .delete-button {
- margin: 0;
- padding: 6px;
- /*height: 16px;*/
- color: var(--pf-t--global--icon--color--status--danger--default);
- position: absolute;
- bottom: 0;
- right: 0;
-}
-.karavan .properties .object-value .delete-button svg {
- fill:var(--pf-t--global--icon--color--status--danger--default);
-}
-
-.karavan .properties .object-key-value,
-.karavan .properties .object-key-value .object-field {
- display: flex;
- flex-direction: row;
- gap: 3px;
-}
-
-.karavan .properties .object-key-value .delete-button {
- margin: auto 0 22px 0;
- padding: 0 0 0 3px;
- height: 16px;
- color: #909090;
-}
-
-.karavan .properties .expression,
-.karavan .properties .object,
-.karavan .properties .dataformat,
-.karavan .properties .parameters {
- padding-top: 0;
- padding-left: 8px;
- row-gap: 6px;
- display: grid;
- width: 100%;
-}
-
-.karavan .properties .expression .pf-v6-c-form__group-label,
-.karavan .properties .object .pf-v6-c-form__group-label,
-.karavan .properties .dataformat .pf-v6-c-form__group-label,
-.karavan .properties .parameters .pf-v6-c-form__group-label {
- font-weight: 100;
-}
-
-.karavan .properties .expression .pf-v6-c-form__group,
-.karavan .properties .object .pf-v6-c-form__group,
-.karavan .properties .dataformat .pf-v6-c-form__group,
-.karavan .properties .parameters .pf-v6-c-form__group {
- margin-bottom: 8px;
-}
-
-.karavan .properties .expression .pf-v6-c-select__menu-wrapper,
-.karavan .properties .object .pf-v6-c-select__menu-wrapper,
-.karavan .properties .dataformat .pf-v6-c-select__menu-wrapper,
-.karavan .properties .parameters .pf-v6-c-select__menu-wrapper {
- width: 350px;
-}
-
-.karavan .properties .change-button {
- font-size: 15px;
- height: 15px;
- line-height: 1;
- border: 0;
- padding: 0;
- margin: auto auto auto 6px;
- background: transparent;
-}
-
-.karavan .properties .change-button svg {
- margin-right: 6px;
-}
-
-.karavan .properties .add-button {
- color: var(--pf-t--global--color--brand--default);
-}
-
-.karavan .properties .delete-button {
- color: var(--pf-t--global--icon--color--status--danger--default);
-}
-
-.karavan .properties .pf-v6-c-expandable-section__toggle {
- margin: 0;
- padding: 0;
-}
-
-.karavan .properties .pf-v6-c-expandable-section__content {
- margin: 0;
-}
-
-.karavan .properties .pf-v6-c-expandable-section__content p {
- min-height: 6px;
-}
-
-.karavan .properties .header-menu-toggle {
- padding-left: 6px;
- padding-right: 0;
-}
-
-.karavan .properties .component-headers {
- margin-left: 24px;
-}
-
-.karavan .properties .component-headers .pf-v6-c-clipboard-copy.pf-m-inline {
- background-color: transparent;
-}
-
-.karavan .properties .value-changed {
- /*box-shadow: gold 0px 0px 0px 2px;*/
- /*border-radius: 3px;*/
-}
-
-.karavan .properties .value-changed-label {
- background-color: var(--pf-t--global--color--nonstatus--yellow--default);
- color: var(--pf-t--color--gray--95);
- padding: 0 2px 0 2px;
- transition: background-color 0.5s ease;
-}
-
-.karavan .properties .value-sensitive-invalid {
- background-color: var(--pf-t--global--icon--color--status--danger--default);
-}
-.karavan .properties .property-selector-group .property-selector .pf-v6-c-toggle-group__button:before {
- border-start-end-radius: 0;
- border-end-end-radius: 0;
-}
-
-.karavan .properties .property-selector .pf-v6-c-toggle-group__button {
- padding-left: 6px;
- padding-right: 6px;
-}
-
-
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.tsx
deleted file mode 100644
index 8c350f4b..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/DslProperties.tsx
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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, {useEffect, useState, ReactElement} from 'react';
-import {
- Button,
- Content,
- ContentVariants,
- ExpandableSection,
- Form,
- TextInputGroup,
- TextInputGroupMain,
- TextInputGroupUtilities,
- Title,
- ToggleGroup,
- ToggleGroupItem,
- Tooltip,
-} from '@patternfly/react-core';
-import './DslProperties.css';
-import {DataFormatField} from "./property/DataFormatField";
-import {DslPropertyField} from "./property/DslPropertyField";
-import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
-import {CamelUi} from "../utils/CamelUi";
-import {CamelMetadataApi, DataFormats, PropertyMeta} from "@karavan-core/model/CamelMetadata";
-import {IntegrationHeader} from "../utils/IntegrationHeader";
-import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {usePropertiesHook} from "./usePropertiesHook";
-import {CamelDisplayUtil} from "@karavan-core/api/CamelDisplayUtil";
-import {PropertiesHeader} from "./PropertiesHeader";
-import {PropertyUtil} from "./property/PropertyUtil";
-import {usePropertiesStore} from "./PropertyStore";
-import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
-import {RouteTemplateDefinition} from "@karavan-core/model/CamelDefinition";
-
-interface Props {
- expressionEditor: React.ComponentType<any>;
-}
-
-export function DslProperties(props: Props) {
-
- const [integration] = useIntegrationStore((s) => [s.integration], shallow)
-
- const {
- cloneElement,
- onDataFormatChange,
- onPropertyChange,
- onParametersChange,
- onExpressionChange
- } =
- usePropertiesHook();
-
- const [selectedStep, setParameterPlaceholders, tab]
- = useDesignerStore((s) => [s.selectedStep, s.setParameterPlaceholders, s.tab], shallow)
-
- const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, sensitiveOnly, setSensitiveOnly, setPropertyFilter, setRequiredOnly]
- = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, s.requiredOnly, s.setChangedOnly, s.sensitiveOnly, s.setSensitiveOnly, s.setPropertyFilter, s.setRequiredOnly], shallow)
-
- const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
-
- useEffect(() => {
- setRequiredOnly(false);
- setChangedOnly(false);
- setSensitiveOnly(false);
- setPropertyFilter('');
- getRouteTemplateParameters()
- }, [selectedStep?.uuid])
-
- function getRouteTemplateParameters() {
- if (selectedStep) {
- const root = CamelDefinitionApiExt.findTopRouteElement(integration, selectedStep.uuid);
- if ('RouteTemplateDefinition' === root?.dslName) {
- const paramPlaceholders: [string, string][] = (root as RouteTemplateDefinition).parameters?.map(p => [p.name, p.description || '']) || [];
- setParameterPlaceholders(paramPlaceholders);
- }
- }
- }
-
- function getClonableElementHeader(): ReactElement {
- const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep);
- const description = selectedStep?.dslName ? CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description : title;
- const descriptionLines: string [] = description ? description?.split("\n") : [""];
- return (
- <div className="headers">
- <div className="top">
- <Title headingLevel="h1" size="md">{title}</Title>
- <Tooltip content="Clone element" position="bottom">
- <Button variant="link" onClick={() => cloneElement()} icon={<CloneIcon/>}/>
- </Tooltip>
- </div>
- {descriptionLines.map((desc, index, array) => <Content key={index}
- component={ContentVariants.p}>{desc}</Content>)}
- </div>
- )
- }
-
- function getPropertiesHeader(): ReactElement {
- if (tab === 'routes') return <PropertiesHeader/>
- else return getClonableElementHeader();
- }
-
- function getProperties(): PropertyMeta[] {
- const dslName = selectedStep?.dslName;
- return CamelDefinitionApiExt.getElementProperties(dslName)
- .filter((p: PropertyMeta) => dslName === 'InterceptSendToEndpointDefinition' || p.name !== 'uri') // do not show uri except InterceptSendToEndpointDefinition
- .filter((p: PropertyMeta) => p.name !== 'id') // do not show id
- // .filer((p: PropertyMeta) => (showAdvanced && p.label.includes('advanced')) || (!showAdvanced && !p.label.includes('advanced')))
- .filter((p: PropertyMeta) => !p.isObject || (p.isObject && !CamelUi.dslHasSteps(p.type)) || (p.name === 'onWhen'))
- .filter((p: PropertyMeta) => !(dslName === 'RestDefinition' && ['get', 'post', 'put', 'patch', 'delete', 'head'].includes(p.name)))
- .filter((p: PropertyMeta) => !(dslName === 'RouteTemplateDefinition' && ['route', 'beans'].includes(p.name)));
- // .filter((p: PropertyMeta) => dslName && !(['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(dslName) && ['param', 'responseMessage'].includes(p.name))) // TODO: configure this properties
- }
-
- function sortProperties(p1: PropertyMeta, p2: PropertyMeta): number {
- const isConvert = selectedStep?.dslName.startsWith('Convert');
-
- if (isConvert) {
- if (p1.name === 'description' && p2.name !== 'description') return 1;
- if (p1.name !== 'description' && p2.name === 'description') return -1;
-
- if (p1.name === 'name' && p2.name !== 'name') return -1;
- if (p1.name !== 'name' && p2.name === 'name') return 1;
- }
-
- if (selectedStep?.dslName.startsWith('Set')) {
- if (p1.name === 'name' && p2.name !== 'name') return -1;
- if (p1.name !== 'name' && p2.name === 'name') return 1;
- }
-
- return 0;
- }
-
- function getPropertyFields(properties: PropertyMeta[]) {
- return (<>
- {properties.sort(sortProperties).map((property: PropertyMeta) =>
- <DslPropertyField key={property.name}
- property={property}
- element={selectedStep}
- value={getPropertyValue(property)}
- onExpressionChange={onExpressionChange}
- onParameterChange={onParametersChange}
- onDataFormatChange={onDataFormatChange}
- onPropertyChange={onPropertyChange}
- expressionEditor={props.expressionEditor}
- />
- )}
- </>)
- }
-
- function getPropertyValue(property: PropertyMeta) {
- return selectedStep ? (selectedStep as any)[property.name] : undefined;
- }
-
- function getFilteredProperties(): PropertyMeta[] {
- let propertyMetas = !dataFormatElement ? getProperties() : getProperties().filter(p => !dataFormats.includes(p.name));
- const filter = propertyFilter.toLocaleLowerCase()
- propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.name.toLocaleLowerCase().includes(filter) || p.label.toLocaleLowerCase().includes(filter) || p.displayName.toLocaleLowerCase().includes(filter));
- if (requiredOnly) {
- propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.required);
- }
- if (changedOnly) {
- propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
- }
- if (sensitiveOnly) {
- propertyMetas = propertyMetas.filter(p => p.name === 'parameters' || p.secret);
- }
- return propertyMetas
- }
-
- const dataFormats = DataFormats.map(value => value[0]);
- const dataFormatElement = selectedStep !== undefined && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName);
- const properties = getFilteredProperties();
- const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
- const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
-
- function getPropertySelector() {
- return (
- <TextInputGroup className='property-selector-group'>
- <TextInputGroupUtilities>
- <ToggleGroup className='property-selector' aria-label="properties selctor">
- <ToggleGroupItem
- text="Required"
- buttonId="requiredOnly"
- isSelected={requiredOnly}
- onChange={(_, selected) => setRequiredOnly(selected)}
- />
- <ToggleGroupItem
- text="Changed"
- buttonId="changedOnly"
- isSelected={changedOnly}
- onChange={(_, selected) => setChangedOnly(selected)}
- />
- <ToggleGroupItem
- text="Sensitive"
- buttonId="sensitiveOnly"
- isSelected={sensitiveOnly}
- onChange={(_, selected) => setSensitiveOnly(selected)}
- />
- </ToggleGroup>
- </TextInputGroupUtilities>
- <TextInputGroupMain
- value={propertyFilter}
- placeholder="filter by name"
- type="text"
- autoComplete={"off"}
- autoFocus={true}
- onChange={(_event, value) => setPropertyFilter(value)}
- aria-label="filter by name"
- />
- <TextInputGroupUtilities>
- <Button icon={<TimesIcon aria-hidden={true}/>} variant="plain" onClick={_ => setPropertyFilter('')}/>
- </TextInputGroupUtilities>
- </TextInputGroup>
- )
- }
-
- function getPropertySelectorChanged(): boolean {
- return requiredOnly || changedOnly || sensitiveOnly || propertyFilter?.trim().length > 0;
- }
-
- function getShowExpanded(): boolean {
- return showAdvanced || getPropertySelectorChanged();
- }
-
- return (
- <div key={selectedStep ? selectedStep.uuid : 'integration'}
- className='properties'>
- <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
- {selectedStep === undefined && <IntegrationHeader/>}
- {selectedStep && getPropertiesHeader()}
- {selectedStep !== undefined && getPropertySelector()}
- {getPropertyFields(propertiesMain)}
- {selectedStep && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName) &&
- <DataFormatField
- integration={integration}
- dslName={selectedStep.dslName}
- value={selectedStep}
- onDataFormatChange={onDataFormatChange}
- expressionEditor={props.expressionEditor}
- />
- }
- {selectedStep && propertiesAdvanced.length > 0 &&
- <ExpandableSection
- toggleText={'Processors advanced properties'}
- onToggle={(_event, isExpanded) => setShowAdvanced(!showAdvanced)}
- isExpanded={getShowExpanded()}>
- <div className="parameters">
- {getPropertyFields(propertiesAdvanced)}
- </div>
- </ExpandableSection>}
- </Form>
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/MainPropertiesPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/MainPropertiesPanel.tsx
deleted file mode 100644
index f038d3cb..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/MainPropertiesPanel.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import {Tab, Tabs, TabTitleIcon, TabTitleText,} from '@patternfly/react-core';
-import './DslProperties.css';
-import {DslProperties} from "./DslProperties";
-import {getDesignerIcon} from "../icons/KaravanIcons";
-import {useDesignerStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import { ExpressionEditor } from './expression/ExpressionEditor';
-
-export function MainPropertiesPanel() {
-
- const [tab] = useDesignerStore((s) => [s.tab], shallow)
-
- const [lastStatus, setLastStatus] = useState<boolean>(false);
- const [activeTabKey, setActiveTabKey] = React.useState<string | number>();
- const handleTabClick = (event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent, tabIndex: string | number) => {
- setActiveTabKey(tabIndex);
- };
-
- useEffect(() => {
- if (!lastStatus) {
- setActiveTabKey('properties');
- setLastStatus(true);
- }
- }, [])
-
- function getTab(title: string, icon: string, error: boolean = false) {
- const color = error ? "red" : "initial";
- return (
- <div className="top-menu-item" style={{color: color}}>
- <TabTitleIcon>{getDesignerIcon(icon)}</TabTitleIcon>
- <TabTitleText>{title}</TabTitleText>
- </div>
- )
- }
-
- function getPropertiesPanelTabs() {
- return (
- <div className={"main-tabs-wrapper"}>
- <Tabs className="main-tabs"
- activeKey={activeTabKey}
- onSelect={handleTabClick}
- isFilled
- aria-label="PropertyTypes"
- role="proeprty-type"
- >
- <Tab eventKey={'properties'} title={getTab('Properties', 'properties')} aria-label="Properties"/>
- </Tabs>
- </div>
- )
- }
-
- function getPropertiesPanel() {
- if (tab === "routes") {
- return <DslProperties expressionEditor={ExpressionEditor}/>
- } else if (tab === "rest") {
- return <DslProperties expressionEditor={ExpressionEditor}/>
- } else if (tab === "beans") {
- return <DslProperties expressionEditor={ExpressionEditor}/>
- } else {
- return <></>
- }
- }
-
- return (
- <div className='main-properties'>
- {getPropertiesPanelTabs()}
- {activeTabKey === 'properties' && getPropertiesPanel() }
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertiesHeader.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertiesHeader.tsx
deleted file mode 100644
index d5b5ed35..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertiesHeader.tsx
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * 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, {ReactElement, useEffect, useRef, useState} from 'react';
-import {
- Badge,
- Button,
- ClipboardCopy,
- Content,
- ContentVariants,
- Dropdown,
- DropdownItem,
- DropdownList,
- ExpandableSection,
- Flex,
- FlexItem,
- FormGroupLabelHelp,
- Label,
- MenuToggle,
- MenuToggleElement,
- Popover,
- Switch,
- Title,
- Tooltip,
-} from '@patternfly/react-core';
-import './DslProperties.css';
-import {CamelUi} from "../utils/CamelUi";
-import {useDesignerStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {usePropertiesHook} from "./usePropertiesHook";
-import {CamelDisplayUtil} from "@karavan-core/api/CamelDisplayUtil";
-import {EllipsisVIcon} from '@patternfly/react-icons';
-import {ComponentApi} from "@karavan-core/api/ComponentApi";
-import {CamelMetadataApi} from "@karavan-core/model/CamelMetadata";
-import {useRouteDesignerHook} from "../route/useRouteDesignerHook";
-
-export function PropertiesHeader() {
-
- const {saveAsRoute, convertStep, onPropertyChange} = usePropertiesHook();
- const {openSelectorToReplaceFrom} = useRouteDesignerHook();
-
- const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow)
-
- const [isDescriptionExpanded, setIsDescriptionExpanded] = useState<boolean>(false);
- const [isHeadersExpanded, setIsHeadersExpanded] = useState<boolean>(false);
- const [isExchangePropertiesExpanded, setIsExchangePropertiesExpanded] = useState<boolean>(false);
- const [isMenuOpen, setMenuOpen] = useState<boolean>(false);
- const [stepIsPoll, setStepIsPoll] = React.useState(false);
- const [stepDynamic, setStepDynamic] = React.useState(false);
- const [stepWireTap, setStepWireTap] = React.useState(false);
- const labelHelpRef = useRef(null);
-
- useEffect(() => {
- setStepDynamic(selectedStep?.dslName === 'ToDynamicDefinition')
- setStepIsPoll(selectedStep?.dslName === 'PollDefinition')
- setStepWireTap(selectedStep?.dslName === 'WireTapDefinition')
- }, [])
-
- useEffect(() => {
- setMenuOpen(false)
- }, [selectedStep])
-
- function getHeaderMenu(): ReactElement {
- const hasSteps = selectedStep?.hasSteps();
- const targetDsl = CamelUi.getConvertTargetDsl(selectedStep?.dslName);
- const targetDslTitle = targetDsl?.replace("Definition", "");
- const showMenu = hasSteps || targetDsl !== undefined;
- return showMenu ?
- <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', width: '100%'}}>
- <Dropdown
- popperProps={{position: "end"}}
- isOpen={isMenuOpen}
- onSelect={() => {
- }}
- onOpenChange={(isOpen: boolean) => setMenuOpen(isOpen)}
- toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
- <MenuToggle
- className="header-menu-toggle"
- ref={toggleRef}
- aria-label="menu"
- variant="plain"
- onClick={() => setMenuOpen(!isMenuOpen)}
- isExpanded={isMenuOpen}
- >
- <EllipsisVIcon/>
- </MenuToggle>
- )}
- >
- <DropdownList>
- {isFrom &&
- <DropdownItem key="changeFrom" onClick={(ev) => {
- ev.preventDefault()
- openSelectorToReplaceFrom((selectedStep as any).id)
- setMenuOpen(false);
- }}>
- Change From...
- </DropdownItem>}
- {hasSteps &&
- <DropdownItem key="saveStepsRoute" onClick={(ev) => {
- ev.preventDefault()
- if (selectedStep) {
- saveAsRoute(selectedStep, true);
- setMenuOpen(false);
- }
- }}>
- Save Steps to Route
- </DropdownItem>}
- {hasSteps && !isFrom &&
- <DropdownItem key="saveElementRoute" 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>
- </div>
- : <></>;
- }
-
- function getExchangePropertiesSection(): ReactElement {
- return (
- <ExpandableSection toggleText='Exchange Properties'
- onToggle={(_event, isExpanded) => setIsExchangePropertiesExpanded(!isExchangePropertiesExpanded)}
- isExpanded={isExchangePropertiesExpanded}>
- <Flex className='component-headers' direction={{default: "column"}}>
- {exchangeProperties.map((header, index, array) =>
- <div key={index} style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', padding: 0}}>
- <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
- isCode>
- {header.name}
- </ClipboardCopy>
- <Popover
- position={"left"}
- headerContent={header.name}
- bodyContent={header.description}
- footerContent={
- <Flex>
- <Content component={ContentVariants.p}>{header.javaType}</Content>
- <FlexItem align={{default: 'alignRight'}}>
- <Badge isRead>{header.label}</Badge>
- </FlexItem>
- </Flex>
- }
- >
- <FormGroupLabelHelp aria-label="More info"/>
- </Popover>
- </div>
- )}
- </Flex>
- </ExpandableSection>
- )
- }
-
- function getComponentHeadersSection(): ReactElement {
- return (
- <ExpandableSection toggleText='Headers'
- onToggle={(_event, isExpanded) => setIsHeadersExpanded(!isHeadersExpanded)}
- isExpanded={isHeadersExpanded}>
- <Flex className='component-headers' direction={{default: "column"}}>
- {headers.filter((header) => groups.includes(header.group))
- .map((header, index, array) =>
- <Flex key={index}>
- <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied" variant="inline-compact"
- isCode>
- {header.name}
- </ClipboardCopy>
- <FlexItem align={{default: 'alignRight'}}>
- <Popover
- triggerRef={labelHelpRef}
- position={"left"}
- headerContent={header.name}
- bodyContent={header.description}
- footerContent={
- <Flex>
- <Content component={ContentVariants.p}>{header.javaType}</Content>
- <FlexItem align={{default: 'alignRight'}}>
- <Badge isRead>{header.group}</Badge>
- </FlexItem>
- </Flex>
- }
- >
- <FormGroupLabelHelp ref={labelHelpRef} aria-label="More info"/>
- </Popover>
- </FlexItem>
- </Flex>
- )}
- </Flex>
- </ExpandableSection>
- )
- }
-
- function getDescriptionSection(): ReactElement {
- return (
- <ExpandableSection toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'}
- onToggle={(_event, isExpanded) => setIsDescriptionExpanded(!isDescriptionExpanded)}
- isExpanded={isDescriptionExpanded}>
- {descriptionLines.filter((value, index) => index > 0)
- .map((desc, index, array) => <Content key={index} component={ContentVariants.p}>{desc}</Content>)}
- </ExpandableSection>
- )
- }
-
- const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep)
- const description = selectedStep && CamelDisplayUtil.getDescription(selectedStep);
- const descriptionLines: string [] = description ? description?.split("\n") : [""];
- const headers = ComponentApi.getComponentHeadersList(selectedStep)
- const exchangeProperties = selectedStep ? CamelMetadataApi.getExchangeProperties(selectedStep.dslName) : [];
- const isFrom = selectedStep?.dslName === 'FromDefinition';
- const isPoll = selectedStep?.dslName === 'PollDefinition';
- const component = ComponentApi.findStepComponent(selectedStep);
- const groups = (isFrom || isPoll) ? ['consumer', 'common'] : ['producer', 'common'];
- const isKamelet = CamelUi.isKamelet(selectedStep);
- const showSwitchers = !isFrom && selectedStep !== undefined && ['ToDefinition', 'PollDefinition', 'ToDynamicDefinition', 'WireTapDefinition']
- .includes(selectedStep?.dslName);
-
- function changeStepType(poll: boolean, dynamic: boolean, wireTap: boolean) {
- if (selectedStep) {
- if (poll) {
- convertStep(selectedStep, 'PollDefinition');
- setStepIsPoll(true);
- setStepDynamic(false);
- setStepWireTap(false);
- } else if (dynamic) {
- convertStep(selectedStep, 'ToDynamicDefinition');
- setStepIsPoll(false);
- setStepDynamic(true);
- setStepWireTap(false);
- } else if (wireTap) {
- convertStep(selectedStep, 'WireTapDefinition');
- setStepIsPoll(false);
- setStepDynamic(false);
- setStepWireTap(true);
- } else {
- convertStep(selectedStep, 'ToDefinition');
- setStepIsPoll(false);
- setStepDynamic(false);
- setStepWireTap(false);
- }
- }
- }
-
- function getStepTypeSwitch() {
- const pollSupported = !component?.component.producerOnly;
- return (<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', width: '100%', gap: '16px'}}>
- <Tooltip content='Send messages to a dynamic endpoint evaluated on-demand' position='top-end'>
- <Switch
- id="step-type-dynamic"
- className='step-type-switch'
- label="Dynamic"
- isChecked={stepDynamic}
- onChange={(event, checked) => {
- changeStepType(stepIsPoll, checked, stepWireTap)
- }}
- ouiaId="step-type-switch"
- isDisabled={stepIsPoll || stepWireTap}
- isReversed
- />
- </Tooltip>
- {pollSupported && !isKamelet &&
- <Tooltip content='Simple Polling Consumer to obtain the additional data' position='top-end'>
- <Switch
- id="step-type-poll"
- className='step-type-switch'
- label="Poll"
- isChecked={stepIsPoll}
- onChange={(event, checked) => {
- changeStepType(checked, stepDynamic, stepWireTap)
- }}
- ouiaId="step-type-switch"
- isDisabled={stepDynamic || stepWireTap}
- isReversed
- />
- </Tooltip>
- }
- <Tooltip content='Copy the original Exchange and route to a separate location' position='top-end'>
- <Switch
- id="step-type-wiretap"
- className='step-type-switch'
- label="WireTap"
- isChecked={stepWireTap}
- onChange={(event, checked) => {
- changeStepType(stepIsPoll, stepDynamic, checked)
- }}
- ouiaId="step-type-switch"
- isDisabled={stepIsPoll || stepDynamic}
- isReversed
- />
- </Tooltip>
- </div>
- )
- }
-
- function getIdInput() {
- return (
- (selectedStep as any)?.id !== undefined
- ? <Label isEditable color='blue' isCompact onEditComplete={(event, newText) => onPropertyChange("id", newText)}>
- {(selectedStep as any)?.id || ''}
- </Label>
- : <Button variant="link" onClick={event => onPropertyChange("id", "rc-" + Math.floor(1000 + Math.random() * 9000).toString())}>
- Add Id
- </Button>
- )
- }
-
- function getDslDescription() {
- return (
- <div style={{flex: 2, display: 'flex', justifyContent: 'flex-end'}}>
- <Popover position={"left"} bodyContent={description}>
- <FormGroupLabelHelp style={{padding: 0}} aria-label="More info"/>
- </Popover>
- </div>
- )
- }
-
- return (
- <div className="headers">
- <div className="top">
- <Title headingLevel="h1" size="md">{title}</Title>
- {getIdInput()}
- {getHeaderMenu()}
- {getDslDescription()}
- </div>
- {/*<Content component={ContentVariants.p}>{descriptionLines.at(0)}</Content>*/}
- {/*{descriptionLines.length > 1 && getDescriptionSection()}*/}
- {showSwitchers && getStepTypeSwitch()}
- {headers.length > 0 && getComponentHeadersSection()}
- {exchangeProperties.length > 0 && getExchangePropertiesSection()}
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertyStore.ts b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertyStore.ts
deleted file mode 100644
index 3515ec0a..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/PropertyStore.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 {createWithEqualityFn} from "zustand/traditional";
-import {shallow} from "zustand/shallow";
-
-interface PropertiesState {
- propertyFilter: string;
- setPropertyFilter: (propertyFilter: string) => void
- requiredOnly: boolean;
- setRequiredOnly: (requiredOnly: boolean) => void
- changedOnly: boolean;
- setChangedOnly: (changedOnly: boolean) => void
- sensitiveOnly: boolean;
- setSensitiveOnly: (sensitiveOnly: boolean) => void
-}
-
-export const usePropertiesStore = createWithEqualityFn<PropertiesState>((set, get) => ({
- requiredOnly: false,
- changedOnly: false,
- sensitiveOnly: false,
- propertyFilter: '',
- setPropertyFilter: (propertyFilter: string) => {
- set({propertyFilter: propertyFilter});
- },
- setRequiredOnly: (requiredOnly: boolean) => {
- set({requiredOnly: requiredOnly});
- },
- setChangedOnly: (changedOnly: boolean) => {
- set({changedOnly: changedOnly});
- },
- setSensitiveOnly: (sensitiveOnly: boolean) => {
- set({sensitiveOnly: sensitiveOnly});
- },
-}), shallow)
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionBottomPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionBottomPanel.tsx
deleted file mode 100644
index c59ecf22..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionBottomPanel.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 {ClipboardCopy, Content, } from '@patternfly/react-core';
-import './ExpressionEditor.css'
-import {Table, Tbody, Td, Tr} from "@patternfly/react-table";
-import {Context, ExpressionFunctions, ExpressionVariables} from "./ExpressionContextModel";
-
-interface Props {
- dslLanguage?: [string, string, string],
-}
-
-export function ExpressionBottomPanel(props: Props) {
-
- const {dslLanguage} = props;
- const language = dslLanguage?.[0];
- const vars: Context[] = ExpressionVariables.filter(e => e.name === language)?.[0]?.information || [];
- const funcs: Context[] = ExpressionFunctions.filter(e => e.name === language)?.at(0)?.information || []
- const showVars = vars.length > 0;
- const showFuncs = funcs.length > 0;
-
- function getRows(data: Context[]) {
- return (
- data?.map((context, index, array) =>
- <Tr key={index} style={{padding: '0'}}>
- <Td style={{padding: '0px 0px 6px 0px'}} modifier='fitContent'>
- <ClipboardCopy key={index} hoverTip="Copy" clickTip="Copied"
- variant="inline-compact">
- {context.key}
- </ClipboardCopy>
- </Td>
- <Td style={{padding: '0px 0px 0px 16px'}}>
- {context.value}
- </Td>
- </Tr>
- )
- )
- }
-
- function getRowHeader(data: string) {
- return (
- <Tr key='vars' style={{padding: '0'}}>
- <Td style={{padding: '16px 6px 6px 0px'}}>
- <Content>
- <Content component='h3'>{data}</Content>
- </Content>
- </Td>
- </Tr>
- )
- }
-
- return (
- <div className='context'>
- <div className='context-column'>
- <Table variant='compact' borders={false}>
- <Tbody>
- {showVars && getRowHeader('Variables')}
- {showVars && getRows(vars)}
- {showFuncs && getRowHeader('Functions')}
- {showFuncs && getRows(funcs)}
- </Tbody>
- </Table>
- </div>
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionContextModel.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionContextModel.tsx
deleted file mode 100644
index 3f0a3411..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionContextModel.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.
- */
-
-export class ExpressionContext {
- name: string = '';
- information: Context[] = [];
-
- constructor(name: string, information: Context[]) {
- this.name = name;
- this.information = information;
- }
-}
-
-export class Context {
- key: string = '';
- value: string = '';
-
- constructor(key: string, value: string) {
- this.key = key;
- this.value = value;
- }
-}
-
-export const ExpressionVariables: ExpressionContext[] = [
- new ExpressionContext('groovy', [
- new Context('exchange', 'The Exchange itself.'),
- new Context('exchangeProperties', 'The Exchange properties.'),
- new Context('variables', 'The variables'),
- new Context('headers', 'The headers of the In message.'),
- new Context('camelContext', 'The Camel Context.'),
- new Context('request', 'The In message.'),
- new Context('body', 'The message body'),
- new Context('response', 'The Out message (only for InOut message exchange pattern).')
- ]
- ),
- new ExpressionContext('java', [
- new Context('exchange', 'The Exchange itself.'),
- new Context('message', 'The Camel message.'),
- new Context('context', 'The Camel Context.'),
- new Context('body', 'The message body')
- ]
- ),
- new ExpressionContext('javascript', [
- new Context('this', 'the Exchange is the root object.'),
- new Context('context', 'The Camel Context.'),
- new Context('exchange', 'The Exchange itself.'),
- new Context('exchangeId', 'The ExchangeID.'),
- new Context('message', 'The Camel message.'),
- new Context('body', 'The message body'),
- new Context('headers', 'The message headers'),
- new Context('properties', 'The message properties')
- ]
- ),
- new ExpressionContext('jq', [
- new Context('header', 'Allow accessing the Message header ex. header(\\"MyHeader\\")'),
- new Context('property', 'Allow accessing the Message property ex. property(\\"MyProperty\\")'),
- new Context('constant', 'Allow accessing constant value as-is '),
-
- ]
- ),
- new ExpressionContext('simple', [
- new Context('camelId', 'the CamelContext name'),
- new Context('camelContext.*OGNL*', 'the CamelContext invoked using a Camel OGNL expression.'),
- new Context('exchange', 'the Exchange'),
- new Context('exchange.*OGNL*', 'the Exchange invoked using a Camel OGNL expression.'),
- new Context('exchangeId', 'the exchange id'),
- new Context('id', 'the message id'),
- new Context('messageTimestamp', 'the message timestamp (millis since epoc) that this message originates from.'),
- new Context('body ', 'the body'),
- new Context('body.*OGNL*', 'the body invoked using a Camel OGNL expression.'),
- new Context('bodyAs(_type_)', 'Converts the body to the given type determined by its classname. The converted body can be null.'),
- new Context('bodyAs(_type_).*OGNL* ', 'Converts the body to the given type determined by its classname and then invoke methods using a Camel OGNL expression. The converted body can be null.'),
- new Context('bodyOneLine', 'Converts the body to a String and removes all line-breaks so the string is in one line.'),
- new Context('prettyBody', 'Converts the body to a String, and attempts to pretty print if JSon or XML, otherwise the body is returned as the String value.'),
- new Context('originalBody', 'The original incoming body (only available if allowUseOriginalMessage=true).'),
- new Context('mandatoryBodyAs(_type_)', 'Converts the body to the given type determined by its classname, and expects the body to be not null.'),
- new Context('mandatoryBodyAs(_type_).*OGNL* ', 'Converts the body to the given type determined by its classname and then invoke methods using a Camel OGNL expression.'),
- new Context('header.foo ', 'refer to the foo header'),
- new Context('header[foo] ', 'refer to the foo header'),
- new Context('headers.foo ', 'refer to the foo header'),
- new Context('headers:foo ', 'refer to the foo header'),
- new Context('headers[foo] ', 'refer to the foo header'),
- new Context('header.foo[bar] ', 'regard foo header as a map and perform lookup on the map with bar as key'),
- new Context('header.foo.*OGNL*', 'refer to the foo header and invoke its value using a Camel OGNL expression.'),
- new Context('headerAs(_key_,_type_)', 'converts the header to the given type determined by its classname'),
- new Context('headers', 'refer to the headers'),
- new Context('variable.foo ', 'refer to the foo variable'),
- new Context('variable[foo] ', 'refer to the foo variable'),
- new Context('variable.foo.*OGNL* ', 'refer to the foo variable and invoke its value using a Camel OGNL expression.'),
- new Context('variableAs(_key_,_type_)', 'converts the variable to the given type determined by its classname'),
- new Context('variables', 'refer to the variables'),
- new Context('exchangeProperty.foo ', 'refer to the foo property on the exchange'),
- new Context('exchangeProperty[foo] ', 'refer to the foo property on the exchange'),
- new Context('exchangeProperty.foo.*OGNL* ', 'refer to the foo property on the exchange and invoke its value using a Camel OGNL expression.'),
- new Context('messageAs(_type_)', 'Converts the message to the given type determined by its classname. The converted message can be null. '),
- new Context('messageAs(_type_).*OGNL* ', 'Converts the message to the given type determined by its classname and then invoke methods using a Camel OGNL expression. The converted message can be null. '),
- new Context('sys.foo', 'refer to the JVM system property'),
- new Context('sysenv.foo', 'refer to the system environment variable'),
- new Context('env.foo', 'refer to the system environment variable'),
- new Context('exception ', 'refer to the exception object on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
- new Context('exception.*OGNL* ', 'refer to the exchange exception invoked using a Camel OGNL expression object'),
- new Context('exception.message', 'refer to the exception.message on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
- new Context('exception.stacktrace', 'refer to the exception.stracktrace on the exchange, is *null* if no exception set on exchange. Will fallback and grab caught exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.'),
- new Context('date:_command_', `evaluates to a Date object. Supported commands are: *now* for current timestamp,
-*exchangeCreated* for the timestamp when the current exchange was created,
-*header.xxx* to use the Long/Date object in the header with the key xxx.
-*variable.xxx* to use the Long/Date in the variable with the key xxx.
-*exchangeProperty.xxx* to use the Long/Date object in the exchange property with the key xxx.
-*file* for the last modified timestamp of the file (available with a File consumer).
-Command accepts offsets such as: *now-24h* or *header.xxx+1h* or even *now+1h30m-100*.`),
- new Context('date:_command:pattern_', 'Date formatting using `java.text.SimpleDateFormat` patterns.'),
- new Context('date-with-timezone:_command:timezone:pattern_', 'Date formatting using `java.text.SimpleDateFormat` timezones and patterns.'),
- new Context('bean:_bean expression_ ', `Invoking a bean expression using the xref:components::bean-component.adoc[Bean] language.'),
-Specifying a method name you must use dot as separator. We also support
-the ?method=methodname syntax that is used by the xref:components::bean-component.adoc[Bean]
-component. Camel will by default lookup a bean by the given name. However if you need to refer
-to a bean class (such as calling a static method) then you can prefix with type, such as 'bean:type:fqnClassName'. `),
- new Context('properties:key:default', 'Lookup a property with the given key. If the key does not exists or has no value, then an optional default value can be specified.'),
- new Context('propertiesExist:key', 'Checks whether a property placeholder with the given key exists or not. The result can be negated by prefixing the key with `!`.'),
- new Context('routeId', 'Returns the route id of the current route the Exchange is being routed.'),
- new Context('routeGroup', 'Returns the route group of the current route the Exchange is being routed. Not all routes has a group assigned, so this may be null.'),
- new Context('stepId', 'Returns the id of the current step the Exchange is being routed.'),
- new Context('threadId', 'Returns the id of the current thread. Can be used for logging purpose.'),
- new Context('threadName', 'Returns the name of the current thread. Can be used for logging purpose.'),
- new Context('hostname', 'Returns the local hostname (may be empty if not possible to resolve).'),
- new Context('ref:xxx ', 'To lookup a bean from the Registry with the given id.'),
- new Context('type:name.field ', 'To refer to a type or field by its FQN name. To refer to a field you can append .FIELD_NAME. For example, you can refer to the constant field from Exchange as: `org.apache.camel.Exchange.FILE_NAME`'),
- new Context('empty(type)', `Creates a new empty object of the type given as parameter. The type-parameter-Strings are case-insensitive. +
-'string' -> empty String
-'list' -> empty ArrayList
-'map' -> empty HashMap `),
- new Context('null', 'represents a *null*'),
- new Context('random(value)', 'returns a random Integer between 0 (included) and _value_ (excluded)'),
- new Context('random(min,max)', 'returns a random Integer between _min_ (included) and _max_ (excluded)'),
- new Context('collate(group)', `The collate function iterates the message body and groups
-the data into sub lists of specified size. This can be used with the
-Splitter EIP to split a message body and group/batch
-the split sub message into a group of N sub lists. This method works
-similar to the collate method in Groovy.`),
- new Context('skip(number)', ' The skip function iterates the message body and skips the first number of items. This can be used with the Splitter EIP to split a message body and skip the first N number of items.'),
- new Context('join(separator,prefix,exp)', `The join function iterates the message body (by default) and joins the data into a string. The separator is by default a comma. The prefix is optional.'),
-
-The join uses the message body as source by default. It is possible to refer to another
-source (simple language) such as a header via the exp parameter. For example join('&','id=','$\{header.ids}')`),
- new Context('messageHistory', 'The message history of the current exchange how it has been routed. This is similar to the route stack-trace message history the error handler logs in case of an unhandled exception.'),
- new Context('messageHistory(false)', 'As messageHistory but without the exchange details (only includes the route stack-trace). This can be used if you do not want to log sensitive data from the message itself.'),
- new Context('uuid(type)', 'Returns an UUID using the Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and `simple` as the type. If no type is given the default is used. It is also possible to use a custom `UuidGenerator` and bind the bean to the xref:manual::registry.adoc[Registry] with an id. For example `${uuid(myGenerator}` where the ID is _myGenerator_.'),
- new Context('hash(exp,algorithm)', 'Returns a hashed value (string in hex decimal) using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.'),
- new Context('jsonpath(exp)', 'When working with JSon data, then this allows to use the JsonPath language for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath.'),
- new Context('jsonpath(input,exp)', 'When working with JSon data, then this allows to use the JsonPath language for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
- new Context('jq(exp)', 'When working with JSon data, then this allows to use the JQ language for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath.'),
- new Context('jq(input,exp)', 'When working with JSon data, then this allows to use the JQ language for example to extract data from the message body (in JSon format). This requires having camel-jq JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
- new Context('xpath(exp)', 'When working with XML data, then this allows to use the XPath language for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath.'),
- new Context('xpath(input,exp)', 'When working with XML data, then this allows to use the XPath language for example to extract data from the message body (in XML format). This requires having camel-xpath JAR on the classpath. For _input_ you can choose `header:key`, `exchangeProperty:key` or `variable:key` to use as input for the JSon payload instead of the message body.'),
- new Context('pretty(exp)', 'Converts the inlined expression to a String, and attempts to pretty print if JSon or XML, otherwise the expression is returned as the String value.'),
- ]
- )
-]
-
-export const ExpressionFunctions: ExpressionContext[] = [
- new ExpressionContext('java', [
- new Context('bodyAs(type)', 'To convert the body to the given type'),
- new Context('headerAs(name, type)', 'To convert the header with the name to the given type.'),
- new Context('headerAs(name, defaultValue, type)', 'To convert the header with the name to the given type. If no header exists, then use the given default value.'),
- new Context('exchangePropertyAs(name, type)', 'To convert the exchange property with the name to the given type.'),
- new Context('exchangePropertyAs(name, defaultValue, type)', 'To convert the exchange property with the name to the given type. If no exchange property exists, then use the given default value.'),
- new Context('optionalBodyAs(type)', 'To convert the body to the given type, returned wrapped in java.util.Optional.'),
- new Context('optionalHeaderAs(name, type)', 'To convert the header with the name to the given type, returned wrapped in java.util.Optional.'),
- new Context('optionalExchangePropertyAs(name, type)', 'To convert the exchange property with the name to the given type, returned wrapped in java.util.Optional.')
- ]
- ),
- new ExpressionContext('xpath', [
- new Context('in:body', 'Will return the message body.'),
- new Context('in:header', 'Will return the message header.'),
- new Context('function:properties', 'To use a Property Placeholder.'),
- new Context('function:simple', 'To evaluate a Simple language.'),
- ]
- )
-]
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.css
deleted file mode 100644
index 399704ae..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.css
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-.expression-modal {
- height: 80%;
-}
-
-.container {
- height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: stretch;
-}
-
-.panel-top {
- flex: 1;
- height: 100%;
- border: 1px solid lightgray;
-}
-
-.panel-middle {
- /*height: 64px;*/
-}
-@keyframes smooth-appear {
- to {
- bottom: 20px;
- opacity:1;
- }
-}
-
-.panel-bottom {
- flex: 1;
- height: 100%;
- overflow-y: auto;
- opacity:0;
- animation: smooth-appear 1s ease forwards;
-}
-
-.context {
- width: 100%;
- display: flex;
- justify-content: space-between;
- gap: 64px;
-}
-
-.context-column {
- flex: 1;
-}
-
-.context-column-right {
- margin-left: 12px;
-}
-
-.context-column .pf-v6-c-clipboard-copy.pf-m-inline {
- display: flex;
- width: fit-content;
-}
-
-.context-column .pf-v6-c-clipboard-copy__text{
- white-space: nowrap;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.tsx
deleted file mode 100644
index 6b688566..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/expression/ExpressionEditor.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import '@shared/monaco-setup';
-import Editor from "@monaco-editor/react";
-import './ExpressionEditor.css'
-import {ExpressionFunctions, ExpressionVariables} from "./ExpressionContextModel";
-import {useTheme} from "@app/theme/ThemeContext";
-
-interface Props {
- customCode: any,
- onChange: (value: string |undefined) => void,
- title: string,
- dslLanguage?: [string, string, string],
-}
-
-export function ExpressionEditor(props: Props) {
-
- const {isDark} = useTheme();
- const [customCode, setCustomCode] = useState<string | undefined>();
- const [showVariables, setShowVariables] = useState<boolean>(false);
- const [key, setKey] = useState<string>('');
-
- const {dslLanguage, onChange} = props;
-
- useEffect(() => {
- setCustomCode(props.customCode)
- },[]);
-
- const language = dslLanguage?.[0];
- const showVars = ExpressionVariables.findIndex(e => e.name === language) > - 1;
- const showFuncs = ExpressionFunctions.findIndex(e => e.name === language) > - 1;
- const show = showVars || showFuncs;
-
- return (
- <div className='container'>
- <div className='panel-top'>
- <Editor
- key={key}
- height={"100%"}
- width="100%"
- defaultLanguage={'java'}
- language={'java'}
- theme={isDark ? 'vs-dark' : 'light'}
- options={{
- lineNumbers: "off",
- folding: false,
- lineNumbersMinChars: 10,
- showUnused: false,
- fontSize: 12,
- minimap: {enabled: false}
- }}
- value={customCode?.toString()}
- className={'code-editor'}
- onChange={(value, _) => setCustomCode(value)}
- />
- </div>
-
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.css
deleted file mode 100644
index 06b9bea6..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.css
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-.karavan .properties .bean-property {
- display: flex;
- flex-direction: row;
- gap: 3px;
-}
-
-.karavan .properties .bean-property .argument-name,
-.karavan .properties .bean-property .field-name {
- flex: 1;
-}
-
-.karavan .properties .bean-property .field-value {
- flex: 2;
-}
-.karavan .properties .bean-property .argument-value {
- flex: 4;
-}
-
-.karavan .properties .bean-property .delete-button {
- padding: 3px;
- color: #b1b1b7;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.tsx
deleted file mode 100644
index 54cf105e..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/BeanProperties.tsx
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import {
- Button,
- FormGroupLabelHelp,
- InputGroup,
- InputGroupItem,
- Popover,
- TextInput,
- TextInputGroup,
- TextInputGroupMain,
- TextInputGroupUtilities,
- Tooltip,
- ValidatedOptions,
-} from '@patternfly/react-core';
-import './BeanProperties.css';
-import {BeanFactoryDefinition,} from "@karavan-core/model/CamelDefinition";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {SensitiveKeys} from "@karavan-core/model/CamelMetadata";
-import {v4 as uuidv4} from "uuid";
-import {CogIcon, DockerIcon, PlusCircleIcon, TimesIcon} from '@patternfly/react-icons';
-import {ConfigurationSelectorModal} from "./ConfigurationSelectorModal";
-import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-import {useDesignerStore} from "../../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {KubernetesIcon} from "../../icons/ComponentIcons";
-import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
-
-interface Props {
- type: 'constructors' | 'properties'
- onChange: (bean: BeanFactoryDefinition) => void
- onClone: (bean: BeanFactoryDefinition) => void
- expressionEditor: React.ComponentType<any>
-}
-
-export function BeanProperties (props: Props) {
-
- const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow);
- const [configurationSelector, setConfigurationSelector] = useState<boolean>(false);
- const [configurationSelectorProperty, setConfigurationSelectorProperty] = useState<string | undefined>(undefined);
- const [configurationSelectorUuid, setConfigurationSelectorUuid] = useState<string | undefined>(undefined);
- const [properties, setProperties] = useState<Map<string, [string, string]>>(new Map<string, [string, string]>());
- const [constructors, setConstructors] = useState<Map<string, [number, string]>>(new Map<string, [number, string]>());
-
- useEffect(()=> {
- setProperties(preparePropertiesMap((selectedStep as BeanFactoryDefinition)?.properties))
- setConstructors(prepareConstructorsMap((selectedStep as BeanFactoryDefinition)?.constructors))
- }, [selectedStep?.uuid])
-
- function preparePropertiesMap (properties: any): Map<string, [string, string]> {
- const result = new Map<string, [string, string]>();
- if (properties) {
- Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k, properties[k]]));
- }
- return result;
- }
-
- function prepareConstructorsMap (constructors: any): Map<string, [number, string]> {
- const result = new Map<string, [number, string]>();
- if (constructors) {
- Object.keys(constructors).forEach((k, i, a) => result.set(uuidv4(), [parseInt(k), constructors[k]]));
- }
- return result;
- }
-
- function onBeanPropertyUpdate () {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
- const beanProperties: any = {};
- properties.forEach((p: any) => beanProperties[p[0]] = p[1]);
- bean.properties = beanProperties;
- props.onChange(bean);
- }
- }
-
- function onBeanConstructorsUpdate () {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
- const beanConstructors: any = {};
- constructors.forEach((p: any) => beanConstructors[p[0]] = p[1]);
- bean.constructors = beanConstructors;
- props.onChange(bean);
- }
- }
-
- function beanFieldChanged (fieldId: string, value: string) {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
- (bean as any)[fieldId] = value;
- props.onChange(bean);
- }
- }
-
- function propertyChanged (uuid: string, key: string, value: string) {
- setProperties(prevState => {
- prevState.set(uuid, [key, value]);
- return prevState;
- });
- onBeanPropertyUpdate();
- }
-
- function constructorChanged (uuid: string, key: number, value: string) {
- setConstructors(prevState => {
- prevState.set(uuid, [key, value]);
- return prevState;
- });
- onBeanConstructorsUpdate();
- }
-
- function propertyDeleted (uuid: string) {
- setProperties(prevState => {
- prevState.delete(uuid);
- return prevState;
- })
- onBeanPropertyUpdate();
- }
-
- function constructorDeleted (uuid: string) {
- setConstructors(prevState => {
- prevState.delete(uuid);
- return prevState;
- })
- onBeanConstructorsUpdate();
- }
-
- function selectConfiguration (value: string) {
- const propertyId = configurationSelectorProperty;
- const uuid = configurationSelectorUuid;
- if (propertyId && uuid){
- if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
- propertyChanged(uuid, propertyId, value);
- setConfigurationSelector(false);
- setConfigurationSelectorProperty(undefined);
- }
- }
-
- function openConfigurationSelector (uuid: string, propertyName: string) {
- setConfigurationSelector(true);
- setConfigurationSelectorProperty(propertyName);
- setConfigurationSelectorUuid(uuid);
- }
-
- function closeConfigurationSelector () {
- setConfigurationSelector(false);
- }
-
- function getConfigurationSelectorModal() {
- return (
- configurationSelector && <ConfigurationSelectorModal
- dark={false}
- isOpen={configurationSelector}
- onClose={() => closeConfigurationSelector()}
- name={'configurationSelectorProperty'}
- customCode={undefined}
- defaultTabIndex={'properties'}
- dslLanguage={undefined}
- hideEditor={true}
- title={'' + configurationSelectorProperty}
- onSave={(fieldId, value1) => {
- selectConfiguration(value1)
- closeConfigurationSelector();
- }}
- expressionEditor={props.expressionEditor}
- onSelect={selectConfiguration}/>)
- }
-
- function getOpenConfigButton(uuid: string, propertyName: string) {
- return (
- <Tooltip position="bottom-end" content="Open config selector">
- <Button icon={<CogIcon/>} variant="control" className='open-config-buton' onClick={e => {
- openConfigurationSelector(uuid, propertyName)
- }}>
-
- </Button>
- </Tooltip>
- )
- }
-
- function cloneBean () {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep as BeanFactoryDefinition);
- bean.uuid = uuidv4();
- props.onClone(bean);
- }
- }
-
- function getLabelIcon (displayName: string, description: string) {
- return (
- <Popover
- position={"left"}
- headerContent={displayName}
- bodyContent={description}
- footerContent={
- <div>
- <b>Required</b>
- </div>
- }>
- <FormGroupLabelHelp aria-label="More info" />
- </Popover>
- )
- }
-
- function getBeanConstructors() {
- return (
- <>
- {Array.from(constructors.entries()).map((v, index, array) => {
- const i = v[0];
- const key = v[1][0];
- const value = v[1][1];
- const isSecret = false;
- return (
- <div key={"key-" + i} className="bean-property">
- <TextInput placeholder="Argument Index" className="text-field argument-name" isRequired type="text" id={"key-" + i}
- name={"key-" + i} value={key}
- onChange={(_, beanFieldName) => {
- constructorChanged(i, parseInt(beanFieldName) , value)
- }}/>
- <InputGroup className="text-field argument-value">
- <InputGroupItem isFill>
- <TextInput
- placeholder="Argument Value"
- type='text'
- autoComplete="off"
- className="text-field"
- isRequired
- id={"value-" + i}
- name={"value-" + i}
- value={value}
- onChange={(_, value) => {
- constructorChanged(i, key, value)
- }}/>
- </InputGroupItem>
- </InputGroup>
- <Button icon={<TimesIcon/>} variant="link" className="delete-button" onClick={e => constructorDeleted(i)}>
-
- </Button>
- </div>
- )
- })}
- <Button icon={<PlusCircleIcon/>} variant="link" className="add-button" onClick={e => constructorChanged(uuidv4(), constructors.size, '')}>
- Add argument</Button>
- </>
- )
- }
-
- function getBeanProperties() {
- return (
- <>
- {Array.from(properties.entries()).map((v, index, array) => {
- const i = v[0];
- const key = v[1][0];
- const value = v[1][1];
- const isSecret = key !== undefined && SensitiveKeys.includes(key.toLowerCase());
- const validated = (isSecret && !isSensitiveFieldValid(value)) ? ValidatedOptions.error : ValidatedOptions.default;
- const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
- const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? KubernetesIcon("infra-button"): <DockerIcon/>
- return (
- <div key={"key-" + i} className="bean-property">
- <TextInput placeholder="Bean Field Name" className="text-field field-name" isRequired type="text" id={"key-" + i}
- name={"key-" + i} value={key}
- onChange={(_, beanFieldName) => {
- propertyChanged(i, beanFieldName, value)
- }}/>
- <InputGroup className='field-value'>
- <TextInputGroup className='text-field'>
- <TextInputGroupMain
- placeholder="Bean Field Value"
- type='text'
- autoComplete="off"
- className="text-field"
- id={"value-" + i}
- name={"value-" + i}
- value={value}
- onBlur={_ => propertyChanged(i, key, value)}
- onChange={(_, v) => {
- propertyChanged(i, key, v)
- }}
- />
- <TextInputGroupUtilities>
- <Button icon={<TimesIcon aria-hidden={true}/>} variant="plain" className='button-clear' onClick={_ => {
- propertyChanged(i, key,'');
- }} />
- </TextInputGroupUtilities>
- </TextInputGroup>
- <InputGroupItem className=''>
- {getOpenConfigButton(i, key)}
- </InputGroupItem>
- </InputGroup>
- {/*<InputGroup>*/}
- {/* {inInfrastructure &&*/}
- {/* <Tooltip position="bottom-end" content={'Select from ' + capitalize(InfrastructureAPI.infrastructure)}>*/}
- {/* <Button variant="control" onClick={e => openConfigurationSelector(i, key)}>*/}
- {/* {icon}*/}
- {/* </Button>*/}
- {/* </Tooltip>}*/}
- {/* <InputGroupItem isFill>*/}
- {/* <TextInput*/}
- {/* placeholder="Bean Field Value"*/}
- {/* type='text'*/}
- {/* autoComplete="off"*/}
- {/* className="text-field"*/}
- {/* isRequired*/}
- {/* validated={validated}*/}
- {/* id={"value-" + i}*/}
- {/* name={"value-" + i}*/}
- {/* value={value}*/}
- {/* onChange={(_, value) => {*/}
- {/* propertyChanged(i, key, value)*/}
- {/* }}/>*/}
- {/* </InputGroupItem>*/}
- {/*</InputGroup>*/}
- <Button icon={<TimesIcon/>} variant="link" className="delete-button" onClick={e => propertyDeleted(i)}></Button>
- </div>
- )
- })}
- <Button icon={<PlusCircleIcon/>} variant="link" className="add-button" onClick={e => propertyChanged(uuidv4(), '', '')}>
- Add property</Button>
- </>
- )
- }
-
- const bean = (selectedStep as BeanFactoryDefinition);
- return (
- <div className='properties' key={bean ? bean.uuid : 'integration'}>
- {props.type === 'constructors' && getBeanConstructors()}
- {props.type === 'properties' && getBeanProperties()}
- {getConfigurationSelectorModal()}
- </div>
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.css b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.css
deleted file mode 100644
index c56e862a..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.css
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.
- */
-.switch-placeholder {
- margin: auto;
- padding-right: 12px;
-}
-
-.karavan .properties .route-variable .pf-v6-c-toggle-group__button:before,
-.karavan .properties .route-variable .pf-v6-c-toggle-group__button {
- border-start-end-radius: 0;
- border-end-end-radius: 0;
-}
-
-.karavan .properties .infra-button {
- width: 1em;
- height: 1em;
- vertical-align: -0.125em;
-}
-
-.karavan .properties .component-property-form-group:hover .button-clear {
- visibility: visible;
-}
-
-.karavan .properties .component-property-form-group .button-clear {
- visibility: hidden;
-}
-.karavan .properties .component-property-form-group:hover .boolean-field {
- visibility: visible;
-}
-
-.karavan .properties .component-property-form-group .boolean-field {
- visibility: hidden;
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.tsx b/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.tsx
deleted file mode 100644
index ba749f81..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/integration/designer/property/property/ComponentPropertyField.tsx
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * 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, {useEffect, useRef, useState} from 'react';
-import {
- Button,
- Content,
- ContentVariants,
- FormGroup,
- FormGroupLabelHelp,
- FormHelperText,
- HelperText,
- HelperTextItem,
- InputGroup,
- InputGroupItem,
- Popover,
- SelectOptionProps,
- Switch,
- TextArea,
- TextInputGroup,
- TextInputGroupMain,
- TextInputGroupUtilities,
- Tooltip,
- ValidatedOptions
-} from '@patternfly/react-core';
-import './ComponentPropertyField.css';
-import {ComponentProperty} from "@karavan-core/model/ComponentModels";
-import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
-import {CamelElement} from "@karavan-core/model/IntegrationDefinition";
-import {ToDefinition} from "@karavan-core/model/CamelDefinition";
-import {ConfigurationSelectorModal} from "./ConfigurationSelectorModal";
-import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-import {CogIcon, PlusIcon, TimesIcon} from '@patternfly/react-icons';
-import {usePropertiesHook} from "../usePropertiesHook";
-import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
-import {shallow} from "zustand/shallow";
-import {INTERNAL_COMPONENTS} from "@karavan-core/api/ComponentApi";
-import {PropertyUtil} from "./PropertyUtil";
-import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
-import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
-import {CamelDefaultStepProperty} from "../../utils/CamelDefaultStepProperty";
-import {FileReferenceDropdown} from "./FileReferenceDropdown";
-import {FieldSelectWithCreate} from "@shared/ui/FieldSelectWithCreate";
-import {FieldSelectScrollable} from "@shared/ui/FieldSelectScrollable";
-import {CamelMetadataApi} from "@karavan-core/model/CamelMetadata";
-
-const prefix = "parameters";
-const beanPrefix = "#bean:";
-const filePrefix = 'resource:';
-
-interface Props {
- property: ComponentProperty,
- element?: CamelElement,
- value: any,
- onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => void,
- expressionEditor: React.ComponentType<any>
- hideConfigSelector?: boolean,
-}
-
-export function ComponentPropertyField(props: Props) {
-
- const {onParametersChange, getInternalComponentName} = usePropertiesHook();
- const {property, element, value, onParameterChange, expressionEditor, hideConfigSelector} = props;
-
- const [integration, files] = useIntegrationStore((state) => [state.integration, state.files], shallow)
- const [ beans, stepDoubleClicked] = useDesignerStore((s) => [s.beans, s.stepDoubleClicked], shallow)
-
- const [configurationSelector, setConfigurationSelector] = useState<boolean>(false);
- const [configurationSelectorProperty, setConfigurationSelectorProperty] = useState<string | undefined>(undefined);
- const [configurationSelectorDefaultTab, setConfigurationSelectorDefaultTab] = useState<string>('properties');
- const [id, setId] = useState<string>(prefix + "-" + property.name);
- const [dslLanguage, setDslLanguage] = useState<any>();
- const [textValue, setTextValue] = useState<any>();
- const ref = useRef<any>(null);
- const [checkChanges, setCheckChanges] = useState<boolean>(false);
-
- useEffect(() => setTextValue(value), [])
-
- useEffect(() => {
- if (stepDoubleClicked && element) {
- const dsp = CamelDefaultStepProperty.findDslDefaultProperty(element.dslName);
- if (dsp?.propertyName === property.name) {
- if (!property.supportFileReference) {
- setConfigurationSelectorDefaultTab(dsp.tab)
- openConfigurationSelector(property.name);
- } else {
- onFileReferenceClick(value);
- }
- }
- }
- }, [stepDoubleClicked])
-
- useEffect(() => {
- if (checkChanges) {
- const interval = setInterval(() => {
- if (value !== textValue) {
- parametersChanged(property.name, textValue);
- }
- }, 700);
- return () => {
- clearInterval(interval)
- }
- }
- }, [checkChanges, textValue])
-
- function parametersChanged(parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
- setCheckChanges(false);
- onParametersChange(parameter, value, pathParameter, newRoute);
- onParameterChange?.(parameter, value, pathParameter, newRoute);
- }
-
- function getSelectBean(property: ComponentProperty, value: any) {
- const selectOptions: SelectOptionProps[] = [];
- if (beans) {
- selectOptions.push(...beans.map((bean) => ({key: value, value: beanPrefix + bean.name, description: bean.type, children: beanPrefix + bean.name})));
- }
- return (
- <FieldSelectScrollable
- selectOptions={selectOptions}
- value={value}
- placeholder={'Select...'}
- onChange={selectedValue => parametersChanged(property.name, selectedValue)}
- />
- )
- }
-
- function canBeInternalUri(property: ComponentProperty): boolean {
- if (element && ['ToDefinition', 'WireTapDefinition'].includes(element.dslName) && (property.name === 'name' || property.name === 'address')) {
- const uri: string = (element as ToDefinition).uri || '';
- const parts = uri.split(":");
- return parts.length > 0 && INTERNAL_COMPONENTS.includes(parts[0]);
- } else {
- return false;
- }
- }
-
- function checkUri(startsWith: string): boolean {
- if (element && element.dslName === 'ToDefinition' && (property.name === 'name' || property.name === 'address')) {
- const uri: string = (element as ToDefinition).uri || '';
- return uri.startsWith(startsWith);
- } else {
- return false;
- }
- }
-
- function getInternalUriSelect(property: ComponentProperty, value: any) {
- const componentName = getInternalComponentName(property.name, element);
- const internalUris = CamelUi.getInternalRouteUris(integration, componentName, false);
- let uris: string[] = CamelUi.getInternalUris(files, checkUri('direct'), checkUri('seda'), checkUri('vertx'));
- uris.push(...internalUris);
- uris = [...new Set(uris.map(e => e.includes(":") ? e.split(":")?.at(1) || "" : e))]
- if (value && value.length > 0 && !uris.includes(value)) {
- uris.unshift(value);
- }
- return (
- <FieldSelectWithCreate
- placeholder={'Select a URI'}
- className={valueChangedClassName}
- listOfValues={[...uris]}
- onSelectElement={selectedValue => parametersChanged(property.name, selectedValue, property.kind === 'path', undefined)}
- value={value}
- utilities={[
- <Tooltip key={1} position="bottom-end" content={"Create route"}>
- <Button isDisabled={value === undefined} variant="plain" onClick={e => {
- if (value) {
- InfrastructureAPI.onCreateNewRoute(componentName, property.name, value);
- // const newRoute = !internalUris.includes(value.toString())
- // ? CamelUi.createNewInternalRoute(componentName.concat(...':', value.toString()))
- // : undefined;
- // parametersChanged(property.name, value, property.kind === 'path', newRoute);
- }
- }}>
- {<PlusIcon/>}
- </Button>
- </Tooltip>
- ]}
- />
- )
- }
-
- function onFileReferenceClick(text: string) {
- const filename = text?.replace(filePrefix, '');
- if (text?.startsWith(filePrefix) && text?.endsWith("." + property.inputLanguage) && !files.find(f => f.name === filename)) {
- InfrastructureAPI.onCreateNewFile(filename, "", true)
- } else {
- InfrastructureAPI.onInternalConsumerClick(undefined, undefined, undefined, filename)
- }
- }
-
- function getFileReferencedField(property: ComponentProperty, value: any) {
- const isNull: boolean = value === undefined || value === null || value?.toString().trim() === '';
- const isResource: boolean = isNull || value?.startsWith(filePrefix);
- const isText: boolean = isNull || !value?.startsWith(filePrefix);
-
- const options: SelectOptionProps[] = files
- .filter(f => property.inputLanguage === '' || property.inputLanguage === undefined || f.name.endsWith(property.inputLanguage))
- .map(f => {
- const val = f.name;
- return {value: val, label: val, children: val}
- })
- const additionalItems = (!isNull) ? [getOpenConfigButton(property, 'editor')] : []
- return (
- <div>
- {isText &&
- <TextInputGroup className={'text-field ' + valueChangedClassName}>
- <TextArea
- className="text-field" isRequired
- type={"text"}
- id={property.name}
- name={property.name}
- height={"100px"}
- value={textValue?.toString()}
- onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')}
- placeholder={`Type ${property.inputLanguage}`}
- onChange={(_, v) => {
- setTextValue(v);
- setCheckChanges(true);
- }}
- />
- <TextInputGroupUtilities>
- {getOpenConfigButton(property, 'editor')}
- </TextInputGroupUtilities>
- </TextInputGroup>
- }
- {isResource &&
- <FileReferenceDropdown
- initialValue={value}
- placeholder={`Select or Create expression file (.${property.inputLanguage})`}
- valueChangedClassName={valueChangedClassName}
- inputLanguage={property.inputLanguage}
- options={options}
- additionalItems={additionalItems}
- onChange={(text: string) => {
- if (text?.endsWith(`.${property.inputLanguage}`)) {
- const filename = text?.replace(filePrefix, '');
- setTextValue(`${filePrefix}${filename}`)
- } else if (text?.trim().length === 0) {
- setTextValue(text);
- }
- setCheckChanges(true);
- }}
- onFileReferenceClick={onFileReferenceClick}
- />
- }
- </div>
- )
- }
-
... 21118 lines suppressed ...
(camel-karavan) 20/33: Front-end Login for 4.18.0
Posted by ma...@apache.org.
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 803698ebc054c53425f5ff38b61cb07b268804b0
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:39:26 2026 -0500
Front-end Login for 4.18.0
---
.../main/webui/src/karavan/app/login/LoginPage.css | 6 +-
.../main/webui/src/karavan/app/login/LoginPage.tsx | 81 ++++++----------------
2 files changed, 27 insertions(+), 60 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
index 40e29f1a..f7d78315 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
+++ b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
@@ -18,6 +18,9 @@
align-items: center;
background: var(--pf-t--color--gray--95);
gap: 48px;
+ h1 {
+ color: var(--pf-t--color--blue--30);
+ }
}
.brand-content {
@@ -81,8 +84,7 @@
.tagline2 {
font-weight: 400;
line-height: 1.5;
- color: #b9dafc; /* Tblue-200 for subtitle */
- font-size: 20px;
+ font-size: 22px;
letter-spacing: 0.5px;
margin-top: 16px;
text-align: center;
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
index aeac2333..8a22b7be 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
@@ -6,7 +6,6 @@ import {
CardBody,
CardFooter,
CardHeader,
- Checkbox,
Content,
Form,
FormAlert,
@@ -21,10 +20,8 @@ import EyeIcon from '@patternfly/react-icons/dist/esm/icons/eye-icon';
import EyeSlashIcon from '@patternfly/react-icons/dist/esm/icons/eye-slash-icon';
import {AuthContext} from "@api/auth/AuthProvider";
import {AuthApi} from "@api/auth/AuthApi";
-import {CamelIcon, KaravanIcon, OpenApiIcon} from "@features/project/designer/icons/KaravanIcons";
-import {SvgIcon} from "@shared/icons/SvgIcon";
-import jibLogo from '@shared/icons/jib.png';
-import {PlatformNameForToolbar, PlatformVersion} from "@shared/ui/PlatformLogos";
+import {CamelIcon} from "@features/project/designer/icons/KaravanIcons";
+import {PlatformVersion} from "@shared/ui/PlatformLogos";
import PlatformLogo from "@app/navigation/PlatformLogo";
import OrbitLines from "@app/login/OrbitLines";
import {useReadinessStore} from "@stores/ReadinessStore";
@@ -39,8 +36,6 @@ export const LoginPage: React.FunctionComponent = () => {
const {reload} = useContext(AuthContext);
const { readiness } = useReadinessStore();
- const [titleSvg, setTitleSvg] = React.useState<string>();
-
useEffect(() => {
}, []);
@@ -72,49 +67,26 @@ export const LoginPage: React.FunctionComponent = () => {
}
}
-
- function getLogos() {
- return [
- <div className="powered-by-logo counter-rotator">
- <a href="https://github.com/apache/camel-karavan" target="_blank">{KaravanIcon("logo")}</a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://www.openapis.org/" target="_blank"><OpenApiIcon className={"logo"}/></a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://www.asyncapi.com/" target="_blank">{SvgIcon({icon: 'asyncapi', className: 'asyncapi-logo'})}</a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://json-schema.org/" target="_blank">
- {SvgIcon({icon: 'json-schema-dark', className: 'json-schema-logo'})}
- </a>
- </div>,
- // <div className="powered-by-logo counter-rotator">
- // <a href="https://groovy-lang.org/" target="_blank">{SvgIcon({icon: 'groovy', className: 'groovy-logo'})}</a>
- // </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://github.com/GoogleContainerTools/jib" target="_blank">
- <img src={jibLogo} alt="Logo" className="jib-logo"/>
- </a>
- </div>,
+ function getCamel() {
+ return (
<div className="powered-by-logo counter-rotator">
<a href="https://camel.apache.org/" target="_blank">{CamelIcon()}</a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://www.patternfly.org/" target={'_blank'}>
- {SvgIcon({icon: 'patternfly', className: 'patternfly-logo'})}
- </a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://eclipse.dev/jkube/" target="_blank">
- {SvgIcon({icon: 'jkube', className: 'jkube-logo'})}
- </a>
- </div>,
- <div className="powered-by-logo counter-rotator">
- <a href="https://www.keycloak.org/" target="_blank">
- {SvgIcon({icon: 'keycloak', className: 'patternfly-logo'})}
- </a>
</div>
+ )
+ }
+
+ function getLogos() {
+ return [
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel(),
+ getCamel()
];
}
@@ -198,16 +170,12 @@ export const LoginPage: React.FunctionComponent = () => {
<div className="karavan-brand-panel">
<div className="brand-content">
<div className="brand-name">
- <div className="brand-logo-container">
- {PlatformLogo("logo")}
- <span className="platform-name-text">{PlatformNameForToolbar()}</span>
- </div>
<div>
- <div className="tagline1 gradient-text-blue">Accelerate</div>
- <div className="tagline1 gradient-text-blue-gold">Integration</div>
- <div className="tagline1 gradient-text-gold">Development</div>
+ <div className="tagline1 gradient-text-blue">Apache</div>
+ <div className="tagline1 gradient-text-blue">Camel</div>
+ <div className="tagline1 gradient-text-blue">Karavan</div>
</div>
- <Content component='p' className="tagline2">Unified Design and Runtime for <br/> APIs • Events • Data Pipelines</Content>
+ <Content component='p' className="tagline2 gradient-text-blue-gold">Low-Code Data Integration Platform</Content>
</div>
</div>
<div className="solar-content">
@@ -222,7 +190,6 @@ export const LoginPage: React.FunctionComponent = () => {
{LOGOS.map((logo, index) => {
const total = LOGOS.length;
const angle = (360 / total) * index;
- // Increased radius slightly to make room for the center logo
const radius = 150;
const style = {'--angle': `${angle}deg`, '--radius': `${radius}px`,} as React.CSSProperties;
return (
@@ -232,8 +199,6 @@ export const LoginPage: React.FunctionComponent = () => {
);
})}
</div>
- <div className="anchor-line"></div>
- <p className="brand-footer">Powered by</p>
</div>
</div>
</div>
(camel-karavan) 22/33: Front-end Navigation for 4.18.0
Posted by ma...@apache.org.
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 0b4e525bfefb89386ee53b89dd395921f90067c3
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:47:27 2026 -0500
Front-end Navigation for 4.18.0
---
.../main/webui/src/karavan/app/navigation/PageNavigation.css | 11 ++++++-----
.../main/webui/src/karavan/app/navigation/PageNavigation.tsx | 6 +++---
.../main/webui/src/karavan/app/navigation/PlatformLogo.tsx | 2 +-
.../webui/src/karavan/app/navigation/ProjectFunctionHook.tsx | 2 --
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
index a5d0ce44..6c4b9d6d 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
@@ -37,7 +37,7 @@
flex-direction: column;
justify-content: center;
align-items: center;
- margin-bottom: 16px;
+ margin-bottom: 8px;
gap: 3px;
color: var(--pf-t--color--blue--10);
/*margin-top: 6px;*/
@@ -73,10 +73,11 @@
}
.karavan .nav-buttons .logo {
- margin-top: 16px;
- margin-bottom: 16px;
- width: 32px;
- height: 32px;
+ margin-top: 6px;
+ padding-left: 3px;
+ /*margin-bottom: 6px;*/
+ width: 64px;
+ height: 64px;
}
.karavan .nav-buttons .pf-v6-c-button svg {
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
index 5a1a59bf..ca61442f 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
@@ -108,9 +108,9 @@ function PageNavigation() {
<div className="nav-buttons pf-v6-theme-dark">
<div className='nav-button-part-wrapper'>
<img src={PlatformLogoBase64()} className="logo" alt='logo'/>
- </div>
- <div style={{alignSelf: 'center'}} className='environment-wrapper'>
- <Badge isRead className='environment'>{config.environment}</Badge>
+ <div style={{alignSelf: 'center'}} className='environment-wrapper'>
+ <Badge isRead className='environment'>{config.environment}</Badge>
+ </div>
</div>
{getMenu(firstMenu)}
<div style={{flex: 2}}/>
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
index 3a116817..d2cfe0e9 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
@@ -22,7 +22,7 @@ export function PlatformLogoBase64() {
}
export function PlatformLogo(classNames?: string) {
- return KaravanIcon()
+ return KaravanIcon(classNames)
}
export default PlatformLogo;
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
index 5e2d14c4..f709efdb 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
@@ -260,8 +260,6 @@ export function ProjectFunctionHook() {
if (tabIndex === "build") {
ProjectService.refreshAllDeploymentStatuses();
ProjectService.refreshImages(project.projectId);
- } else if (tabIndex === 'camel' && refreshTrace) {
- ProjectService.refreshCamelTraces(project.projectId, config.environment);
} if (tabIndex === 'topology') {
}
}
(camel-karavan) 06/33: Karavan-core for 4.18.0
Posted by ma...@apache.org.
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 6203d0a2b9f54cf1edd1bd635ea616cc4821ab8c
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:19:00 2026 -0500
Karavan-core for 4.18.0
---
.../src/karavan-core/api/CamelDefinitionApi.ts | 92 +++--
.../src/karavan-core/api/CamelDefinitionApiExt.ts | 31 +-
.../src/karavan-core/api/CamelDefinitionYaml.ts | 12 +-
.../karavan-core/api/CamelDefinitionYamlStep.ts | 129 ++++---
.../main/webui/src/karavan-core/api/CamelUtil.ts | 43 ++-
.../webui/src/karavan-core/api/TopologyUtils.ts | 100 ++++--
.../src/main/webui/src/karavan-core/contants.ts | 6 +-
.../src/karavan-core/model/CamelDefinition.ts | 220 +++++++++---
.../webui/src/karavan-core/model/CamelMetadata.ts | 387 +++++++++++++--------
.../src/karavan-core/model/TopologyDefinition.ts | 4 +-
10 files changed, 714 insertions(+), 310 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApi.ts b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApi.ts
index db35234f..920fffe8 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApi.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApi.ts
@@ -122,6 +122,7 @@ import {
TokenizerDefinition,
TokenizerImplementationDefinition,
TransactedDefinition,
+ TransformDataTypeDefinition,
TransformDefinition,
TryDefinition,
UnmarshalDefinition,
@@ -153,6 +154,7 @@ import {
FlatpackDataFormat,
ForyDataFormat,
GrokDataFormat,
+ GroovyXmlDataFormat,
GzipDeflaterDataFormat,
HL7DataFormat,
IcalDataFormat,
@@ -163,7 +165,9 @@ import {
JsonDataFormat,
LZFDataFormat,
MimeMultipartDataFormat,
+ OcsfDataFormat,
PGPDataFormat,
+ PQCDataFormat,
ParquetAvroDataFormat,
ProtobufDataFormat,
RssDataFormat,
@@ -174,14 +178,12 @@ import {
SyslogDataFormat,
TarFileDataFormat,
ThriftDataFormat,
- TidyMarkupDataFormat,
UniVocityCsvDataFormat,
UniVocityFixedDataFormat,
UniVocityHeader,
UniVocityTsvDataFormat,
XMLSecurityDataFormat,
YAMLDataFormat,
- YAMLTypeFilterDefinition,
ZipDeflaterDataFormat,
ZipFileDataFormat,
DeadLetterChannelDefinition,
@@ -436,6 +438,9 @@ export class CamelDefinitionApi {
if (element?.transacted !== undefined) {
def.transacted = CamelDefinitionApi.createTransactedDefinition(element.transacted);
}
+ if (element?.transformDataType !== undefined) {
+ def.transformDataType = CamelDefinitionApi.createTransformDataTypeDefinition(element.transformDataType);
+ }
if (element?.transform !== undefined) {
def.transform = CamelDefinitionApi.createTransformDefinition(element.transform);
}
@@ -931,6 +936,9 @@ export class CamelDefinitionApi {
if (element?.grok !== undefined) {
def.grok = CamelDefinitionApi.createGrokDataFormat(element.grok);
}
+ if (element?.groovyXml !== undefined) {
+ def.groovyXml = CamelDefinitionApi.createGroovyXmlDataFormat(element.groovyXml);
+ }
if (element?.gzipDeflater !== undefined) {
def.gzipDeflater = CamelDefinitionApi.createGzipDeflaterDataFormat(element.gzipDeflater);
}
@@ -961,12 +969,18 @@ export class CamelDefinitionApi {
if (element?.mimeMultipart !== undefined) {
def.mimeMultipart = CamelDefinitionApi.createMimeMultipartDataFormat(element.mimeMultipart);
}
+ if (element?.ocsf !== undefined) {
+ def.ocsf = CamelDefinitionApi.createOcsfDataFormat(element.ocsf);
+ }
if (element?.parquetAvro !== undefined) {
def.parquetAvro = CamelDefinitionApi.createParquetAvroDataFormat(element.parquetAvro);
}
if (element?.pgp !== undefined) {
def.pgp = CamelDefinitionApi.createPGPDataFormat(element.pgp);
}
+ if (element?.pqc !== undefined) {
+ def.pqc = CamelDefinitionApi.createPQCDataFormat(element.pqc);
+ }
if (element?.protobuf !== undefined) {
def.protobuf = CamelDefinitionApi.createProtobufDataFormat(element.protobuf);
}
@@ -994,9 +1008,6 @@ export class CamelDefinitionApi {
if (element?.thrift !== undefined) {
def.thrift = CamelDefinitionApi.createThriftDataFormat(element.thrift);
}
- if (element?.tidyMarkup !== undefined) {
- def.tidyMarkup = CamelDefinitionApi.createTidyMarkupDataFormat(element.tidyMarkup);
- }
if (element?.univocityCsv !== undefined) {
def.univocityCsv = CamelDefinitionApi.createUniVocityCsvDataFormat(element.univocityCsv);
}
@@ -1560,6 +1571,12 @@ export class CamelDefinitionApi {
return def;
}
+ static createTransformDataTypeDefinition = (element: any): TransformDataTypeDefinition => {
+ const def = element ? new TransformDataTypeDefinition({...element}) : new TransformDataTypeDefinition();
+ def.uuid = element?.uuid ? element.uuid : def.uuid;
+ return def;
+ }
+
static createTransformDefinition = (element: any): TransformDefinition => {
const def = element ? new TransformDefinition({...element}) : new TransformDefinition();
def.uuid = element?.uuid ? element.uuid : def.uuid;
@@ -1630,6 +1647,9 @@ export class CamelDefinitionApi {
if (element?.grok !== undefined) {
def.grok = CamelDefinitionApi.createGrokDataFormat(element.grok);
}
+ if (element?.groovyXml !== undefined) {
+ def.groovyXml = CamelDefinitionApi.createGroovyXmlDataFormat(element.groovyXml);
+ }
if (element?.gzipDeflater !== undefined) {
def.gzipDeflater = CamelDefinitionApi.createGzipDeflaterDataFormat(element.gzipDeflater);
}
@@ -1660,12 +1680,18 @@ export class CamelDefinitionApi {
if (element?.mimeMultipart !== undefined) {
def.mimeMultipart = CamelDefinitionApi.createMimeMultipartDataFormat(element.mimeMultipart);
}
+ if (element?.ocsf !== undefined) {
+ def.ocsf = CamelDefinitionApi.createOcsfDataFormat(element.ocsf);
+ }
if (element?.parquetAvro !== undefined) {
def.parquetAvro = CamelDefinitionApi.createParquetAvroDataFormat(element.parquetAvro);
}
if (element?.pgp !== undefined) {
def.pgp = CamelDefinitionApi.createPGPDataFormat(element.pgp);
}
+ if (element?.pqc !== undefined) {
+ def.pqc = CamelDefinitionApi.createPQCDataFormat(element.pqc);
+ }
if (element?.protobuf !== undefined) {
def.protobuf = CamelDefinitionApi.createProtobufDataFormat(element.protobuf);
}
@@ -1693,9 +1719,6 @@ export class CamelDefinitionApi {
if (element?.thrift !== undefined) {
def.thrift = CamelDefinitionApi.createThriftDataFormat(element.thrift);
}
- if (element?.tidyMarkup !== undefined) {
- def.tidyMarkup = CamelDefinitionApi.createTidyMarkupDataFormat(element.tidyMarkup);
- }
if (element?.univocityCsv !== undefined) {
def.univocityCsv = CamelDefinitionApi.createUniVocityCsvDataFormat(element.univocityCsv);
}
@@ -1910,6 +1933,9 @@ export class CamelDefinitionApi {
if (element?.grok !== undefined) {
def.grok = CamelDefinitionApi.createGrokDataFormat(element.grok);
}
+ if (element?.groovyXml !== undefined) {
+ def.groovyXml = CamelDefinitionApi.createGroovyXmlDataFormat(element.groovyXml);
+ }
if (element?.gzipDeflater !== undefined) {
def.gzipDeflater = CamelDefinitionApi.createGzipDeflaterDataFormat(element.gzipDeflater);
}
@@ -1973,9 +1999,6 @@ export class CamelDefinitionApi {
if (element?.thrift !== undefined) {
def.thrift = CamelDefinitionApi.createThriftDataFormat(element.thrift);
}
- if (element?.tidyMarkup !== undefined) {
- def.tidyMarkup = CamelDefinitionApi.createTidyMarkupDataFormat(element.tidyMarkup);
- }
if (element?.univocityCsv !== undefined) {
def.univocityCsv = CamelDefinitionApi.createUniVocityCsvDataFormat(element.univocityCsv);
}
@@ -2039,6 +2062,12 @@ export class CamelDefinitionApi {
return def;
}
+ static createGroovyXmlDataFormat = (element: any): GroovyXmlDataFormat => {
+ const def = element ? new GroovyXmlDataFormat({...element}) : new GroovyXmlDataFormat();
+ def.uuid = element?.uuid ? element.uuid : def.uuid;
+ return def;
+ }
+
static createGzipDeflaterDataFormat = (element: any): GzipDeflaterDataFormat => {
const def = element ? new GzipDeflaterDataFormat({...element}) : new GzipDeflaterDataFormat();
def.uuid = element?.uuid ? element.uuid : def.uuid;
@@ -2099,12 +2128,24 @@ export class CamelDefinitionApi {
return def;
}
+ static createOcsfDataFormat = (element: any): OcsfDataFormat => {
+ const def = element ? new OcsfDataFormat({...element}) : new OcsfDataFormat();
+ def.uuid = element?.uuid ? element.uuid : def.uuid;
+ return def;
+ }
+
static createPGPDataFormat = (element: any): PGPDataFormat => {
const def = element ? new PGPDataFormat({...element}) : new PGPDataFormat();
def.uuid = element?.uuid ? element.uuid : def.uuid;
return def;
}
+ static createPQCDataFormat = (element: any): PQCDataFormat => {
+ const def = element ? new PQCDataFormat({...element}) : new PQCDataFormat();
+ def.uuid = element?.uuid ? element.uuid : def.uuid;
+ return def;
+ }
+
static createParquetAvroDataFormat = (element: any): ParquetAvroDataFormat => {
const def = element ? new ParquetAvroDataFormat({...element}) : new ParquetAvroDataFormat();
def.uuid = element?.uuid ? element.uuid : def.uuid;
@@ -2168,12 +2209,6 @@ export class CamelDefinitionApi {
return def;
}
- static createTidyMarkupDataFormat = (element: any): TidyMarkupDataFormat => {
- const def = element ? new TidyMarkupDataFormat({...element}) : new TidyMarkupDataFormat();
- def.uuid = element?.uuid ? element.uuid : def.uuid;
- return def;
- }
-
static createUniVocityCsvDataFormat = (element: any): UniVocityCsvDataFormat => {
const def = element ? new UniVocityCsvDataFormat({...element}) : new UniVocityCsvDataFormat();
def.uuid = element?.uuid ? element.uuid : def.uuid;
@@ -2210,13 +2245,6 @@ export class CamelDefinitionApi {
static createYAMLDataFormat = (element: any): YAMLDataFormat => {
const def = element ? new YAMLDataFormat({...element}) : new YAMLDataFormat();
def.uuid = element?.uuid ? element.uuid : def.uuid;
- def.typeFilter = element && element?.typeFilter ? element?.typeFilter.map((x:any) => CamelDefinitionApi.createYAMLTypeFilterDefinition(x)) :[];
- return def;
- }
-
- static createYAMLTypeFilterDefinition = (element: any): YAMLTypeFilterDefinition => {
- const def = element ? new YAMLTypeFilterDefinition({...element}) : new YAMLTypeFilterDefinition();
- def.uuid = element?.uuid ? element.uuid : def.uuid;
return def;
}
@@ -2915,6 +2943,9 @@ export class CamelDefinitionApi {
if (element?.grok !== undefined) {
def.grok = CamelDefinitionApi.createGrokDataFormat(element.grok);
}
+ if (element?.groovyXml !== undefined) {
+ def.groovyXml = CamelDefinitionApi.createGroovyXmlDataFormat(element.groovyXml);
+ }
if (element?.gzipDeflater !== undefined) {
def.gzipDeflater = CamelDefinitionApi.createGzipDeflaterDataFormat(element.gzipDeflater);
}
@@ -2978,9 +3009,6 @@ export class CamelDefinitionApi {
if (element?.thrift !== undefined) {
def.thrift = CamelDefinitionApi.createThriftDataFormat(element.thrift);
}
- if (element?.tidyMarkup !== undefined) {
- def.tidyMarkup = CamelDefinitionApi.createTidyMarkupDataFormat(element.tidyMarkup);
- }
if (element?.univocityCsv !== undefined) {
def.univocityCsv = CamelDefinitionApi.createUniVocityCsvDataFormat(element.univocityCsv);
}
@@ -3175,6 +3203,7 @@ export class CamelDefinitionApi {
case 'TokenizerDefinition': return CamelDefinitionApi.createTokenizerDefinition(newBody);
case 'TokenizerImplementationDefinition': return CamelDefinitionApi.createTokenizerImplementationDefinition(newBody);
case 'TransactedDefinition': return CamelDefinitionApi.createTransactedDefinition(newBody);
+ case 'TransformDataTypeDefinition': return CamelDefinitionApi.createTransformDataTypeDefinition(newBody);
case 'TransformDefinition': return CamelDefinitionApi.createTransformDefinition(newBody);
case 'TryDefinition': return CamelDefinitionApi.createTryDefinition(newBody);
case 'UnmarshalDefinition': return CamelDefinitionApi.createUnmarshalDefinition(newBody);
@@ -3206,6 +3235,7 @@ export class CamelDefinitionApi {
case 'FlatpackDataFormat': return CamelDefinitionApi.createFlatpackDataFormat(newBody);
case 'ForyDataFormat': return CamelDefinitionApi.createForyDataFormat(newBody);
case 'GrokDataFormat': return CamelDefinitionApi.createGrokDataFormat(newBody);
+ case 'GroovyXmlDataFormat': return CamelDefinitionApi.createGroovyXmlDataFormat(newBody);
case 'GzipDeflaterDataFormat': return CamelDefinitionApi.createGzipDeflaterDataFormat(newBody);
case 'HL7DataFormat': return CamelDefinitionApi.createHL7DataFormat(newBody);
case 'IcalDataFormat': return CamelDefinitionApi.createIcalDataFormat(newBody);
@@ -3216,7 +3246,9 @@ export class CamelDefinitionApi {
case 'JsonDataFormat': return CamelDefinitionApi.createJsonDataFormat(newBody);
case 'LZFDataFormat': return CamelDefinitionApi.createLZFDataFormat(newBody);
case 'MimeMultipartDataFormat': return CamelDefinitionApi.createMimeMultipartDataFormat(newBody);
+ case 'OcsfDataFormat': return CamelDefinitionApi.createOcsfDataFormat(newBody);
case 'PGPDataFormat': return CamelDefinitionApi.createPGPDataFormat(newBody);
+ case 'PQCDataFormat': return CamelDefinitionApi.createPQCDataFormat(newBody);
case 'ParquetAvroDataFormat': return CamelDefinitionApi.createParquetAvroDataFormat(newBody);
case 'ProtobufDataFormat': return CamelDefinitionApi.createProtobufDataFormat(newBody);
case 'RssDataFormat': return CamelDefinitionApi.createRssDataFormat(newBody);
@@ -3227,14 +3259,12 @@ export class CamelDefinitionApi {
case 'SyslogDataFormat': return CamelDefinitionApi.createSyslogDataFormat(newBody);
case 'TarFileDataFormat': return CamelDefinitionApi.createTarFileDataFormat(newBody);
case 'ThriftDataFormat': return CamelDefinitionApi.createThriftDataFormat(newBody);
- case 'TidyMarkupDataFormat': return CamelDefinitionApi.createTidyMarkupDataFormat(newBody);
case 'UniVocityCsvDataFormat': return CamelDefinitionApi.createUniVocityCsvDataFormat(newBody);
case 'UniVocityFixedDataFormat': return CamelDefinitionApi.createUniVocityFixedDataFormat(newBody);
case 'UniVocityHeader': return CamelDefinitionApi.createUniVocityHeader(newBody);
case 'UniVocityTsvDataFormat': return CamelDefinitionApi.createUniVocityTsvDataFormat(newBody);
case 'XMLSecurityDataFormat': return CamelDefinitionApi.createXMLSecurityDataFormat(newBody);
case 'YAMLDataFormat': return CamelDefinitionApi.createYAMLDataFormat(newBody);
- case 'YAMLTypeFilterDefinition': return CamelDefinitionApi.createYAMLTypeFilterDefinition(newBody);
case 'ZipDeflaterDataFormat': return CamelDefinitionApi.createZipDeflaterDataFormat(newBody);
case 'ZipFileDataFormat': return CamelDefinitionApi.createZipFileDataFormat(newBody);
case 'DeadLetterChannelDefinition': return CamelDefinitionApi.createDeadLetterChannelDefinition(newBody);
@@ -3371,6 +3401,7 @@ export class CamelDefinitionApi {
case 'FlatpackDataFormat': return CamelDefinitionApi.createFlatpackDataFormat(newBody);
case 'ForyDataFormat': return CamelDefinitionApi.createForyDataFormat(newBody);
case 'GrokDataFormat': return CamelDefinitionApi.createGrokDataFormat(newBody);
+ case 'GroovyXmlDataFormat': return CamelDefinitionApi.createGroovyXmlDataFormat(newBody);
case 'GzipDeflaterDataFormat': return CamelDefinitionApi.createGzipDeflaterDataFormat(newBody);
case 'HL7DataFormat': return CamelDefinitionApi.createHL7DataFormat(newBody);
case 'IcalDataFormat': return CamelDefinitionApi.createIcalDataFormat(newBody);
@@ -3381,8 +3412,10 @@ export class CamelDefinitionApi {
case 'JsonApiDataFormat': return CamelDefinitionApi.createJsonApiDataFormat(newBody);
case 'LZFDataFormat': return CamelDefinitionApi.createLZFDataFormat(newBody);
case 'MimeMultipartDataFormat': return CamelDefinitionApi.createMimeMultipartDataFormat(newBody);
+ case 'OcsfDataFormat': return CamelDefinitionApi.createOcsfDataFormat(newBody);
case 'ParquetAvroDataFormat': return CamelDefinitionApi.createParquetAvroDataFormat(newBody);
case 'PGPDataFormat': return CamelDefinitionApi.createPGPDataFormat(newBody);
+ case 'PQCDataFormat': return CamelDefinitionApi.createPQCDataFormat(newBody);
case 'ProtobufDataFormat': return CamelDefinitionApi.createProtobufDataFormat(newBody);
case 'RssDataFormat': return CamelDefinitionApi.createRssDataFormat(newBody);
case 'SmooksDataFormat': return CamelDefinitionApi.createSmooksDataFormat(newBody);
@@ -3392,7 +3425,6 @@ export class CamelDefinitionApi {
case 'SyslogDataFormat': return CamelDefinitionApi.createSyslogDataFormat(newBody);
case 'TarFileDataFormat': return CamelDefinitionApi.createTarFileDataFormat(newBody);
case 'ThriftDataFormat': return CamelDefinitionApi.createThriftDataFormat(newBody);
- case 'TidyMarkupDataFormat': return CamelDefinitionApi.createTidyMarkupDataFormat(newBody);
case 'UniVocityCsvDataFormat': return CamelDefinitionApi.createUniVocityCsvDataFormat(newBody);
case 'UniVocityFixedDataFormat': return CamelDefinitionApi.createUniVocityFixedDataFormat(newBody);
case 'UniVocityTsvDataFormat': return CamelDefinitionApi.createUniVocityTsvDataFormat(newBody);
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApiExt.ts b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApiExt.ts
index f8dbfa27..96fd385e 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApiExt.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionApiExt.ts
@@ -14,17 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { CamelMetadataApi, ElementMeta, Languages, PropertyMeta } from '../model/CamelMetadata';
-import { CamelUtil } from './CamelUtil';
+import {CamelMetadataApi, ElementMeta, Languages, PropertyMeta} from '../model/CamelMetadata';
+import {CamelUtil} from './CamelUtil';
import {
BeanFactoryDefinition,
ExpressionDefinition,
- RouteDefinition,
+ FromDefinition,
RestDefinition,
- RouteConfigurationDefinition, FromDefinition, RouteTemplateDefinition,
+ RouteConfigurationDefinition,
+ RouteDefinition,
+ RouteTemplateDefinition,
+ TemplatedRouteDefinition,
} from '../model/CamelDefinition';
-import { Beans, CamelElement, CamelElementMeta, Integration } from '../model/IntegrationDefinition';
-import { CamelDefinitionApi } from './CamelDefinitionApi';
+import {Beans, CamelElement, CamelElementMeta, Integration} from '../model/IntegrationDefinition';
+import {CamelDefinitionApi} from './CamelDefinitionApi';
const coreRoutishElements = ['RouteConfigurationDefinition', 'RouteTemplateDefinition', 'RouteDefinition']
@@ -430,6 +433,22 @@ export class CamelDefinitionApiExt {
return integration;
};
+ static addTemplatedRouteToIntegration = (
+ integration: Integration,
+ templatedRoute: TemplatedRouteDefinition,
+ ): Integration => {
+ integration.spec.flows?.push(templatedRoute);
+ return integration;
+ };
+
+ static addTemplatedRoutesToIntegration = (
+ integration: Integration,
+ templatedRoutes: TemplatedRouteDefinition[],
+ ): Integration => {
+ integration.spec.flows?.push(...templatedRoutes);
+ return integration;
+ };
+
static deleteRouteTemplateFromIntegration = (
integration: Integration,
routeTemplate: RouteTemplateDefinition,
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYaml.ts b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYaml.ts
index 8239d2f9..5f3ac44d 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYaml.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYaml.ts
@@ -15,14 +15,10 @@
* limitations under the License.
*/
import * as yaml from 'js-yaml';
-import { Beans, CamelElement, Integration } from '../model/IntegrationDefinition';
-import {
- BeanFactoryDefinition,
- RouteConfigurationDefinition,
- RouteDefinition,
-} from '../model/CamelDefinition';
-import { CamelUtil } from './CamelUtil';
-import { CamelDefinitionYamlStep } from './CamelDefinitionYamlStep';
+import {Beans, CamelElement, Integration} from '../model/IntegrationDefinition';
+import {BeanFactoryDefinition, RouteConfigurationDefinition, RouteDefinition,} from '../model/CamelDefinition';
+import {CamelUtil} from './CamelUtil';
+import {CamelDefinitionYamlStep} from './CamelDefinitionYamlStep';
export class CamelDefinitionYaml {
private constructor() {
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYamlStep.ts b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYamlStep.ts
index bbc3bf6d..cd52cd75 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYamlStep.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/CamelDefinitionYamlStep.ts
@@ -123,6 +123,7 @@ import {
TokenizerDefinition,
TokenizerImplementationDefinition,
TransactedDefinition,
+ TransformDataTypeDefinition,
TransformDefinition,
TryDefinition,
UnmarshalDefinition,
@@ -154,6 +155,7 @@ import {
FlatpackDataFormat,
ForyDataFormat,
GrokDataFormat,
+ GroovyXmlDataFormat,
GzipDeflaterDataFormat,
HL7DataFormat,
IcalDataFormat,
@@ -164,7 +166,9 @@ import {
JsonDataFormat,
LZFDataFormat,
MimeMultipartDataFormat,
+ OcsfDataFormat,
PGPDataFormat,
+ PQCDataFormat,
ParquetAvroDataFormat,
ProtobufDataFormat,
RssDataFormat,
@@ -175,14 +179,12 @@ import {
SyslogDataFormat,
TarFileDataFormat,
ThriftDataFormat,
- TidyMarkupDataFormat,
UniVocityCsvDataFormat,
UniVocityFixedDataFormat,
UniVocityHeader,
UniVocityTsvDataFormat,
XMLSecurityDataFormat,
YAMLDataFormat,
- YAMLTypeFilterDefinition,
ZipDeflaterDataFormat,
ZipFileDataFormat,
DeadLetterChannelDefinition,
@@ -656,6 +658,13 @@ export class CamelDefinitionYamlStep {
def.tokenizer = CamelDefinitionYamlStep.readTokenizerDefinition(element.tokenizer);
}
}
+ if (element?.transformDataType !== undefined) {
+ if (Array.isArray(element.transformDataType)) {
+ def.transformDataType = CamelDefinitionYamlStep.readTransformDataTypeDefinition(element.transformDataType[0]);
+ } else {
+ def.transformDataType = CamelDefinitionYamlStep.readTransformDataTypeDefinition(element.transformDataType);
+ }
+ }
if (element?.filter !== undefined) {
if (Array.isArray(element.filter)) {
def.filter = CamelDefinitionYamlStep.readFilterDefinition(element.filter[0]);
@@ -1455,11 +1464,11 @@ export class CamelDefinitionYamlStep {
def.tarFile = CamelDefinitionYamlStep.readTarFileDataFormat(element.tarFile);
}
}
- if (element?.tidyMarkup !== undefined) {
- if (Array.isArray(element.tidyMarkup)) {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup[0]);
+ if (element?.pqc !== undefined) {
+ if (Array.isArray(element.pqc)) {
+ def.pqc = CamelDefinitionYamlStep.readPQCDataFormat(element.pqc[0]);
} else {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup);
+ def.pqc = CamelDefinitionYamlStep.readPQCDataFormat(element.pqc);
}
}
if (element?.csv !== undefined) {
@@ -1532,6 +1541,13 @@ export class CamelDefinitionYamlStep {
def.smooks = CamelDefinitionYamlStep.readSmooksDataFormat(element.smooks);
}
}
+ if (element?.ocsf !== undefined) {
+ if (Array.isArray(element.ocsf)) {
+ def.ocsf = CamelDefinitionYamlStep.readOcsfDataFormat(element.ocsf[0]);
+ } else {
+ def.ocsf = CamelDefinitionYamlStep.readOcsfDataFormat(element.ocsf);
+ }
+ }
if (element?.mimeMultipart !== undefined) {
if (Array.isArray(element.mimeMultipart)) {
def.mimeMultipart = CamelDefinitionYamlStep.readMimeMultipartDataFormat(element.mimeMultipart[0]);
@@ -1651,6 +1667,13 @@ export class CamelDefinitionYamlStep {
def.flatpack = CamelDefinitionYamlStep.readFlatpackDataFormat(element.flatpack);
}
}
+ if (element?.groovyXml !== undefined) {
+ if (Array.isArray(element.groovyXml)) {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml[0]);
+ } else {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml);
+ }
+ }
if (element?.swiftMx !== undefined) {
if (Array.isArray(element.swiftMx)) {
def.swiftMx = CamelDefinitionYamlStep.readSwiftMxDataFormat(element.swiftMx[0]);
@@ -2531,6 +2554,13 @@ export class CamelDefinitionYamlStep {
return def;
}
+ static readTransformDataTypeDefinition = (element: any): TransformDataTypeDefinition => {
+
+ let def = element ? new TransformDataTypeDefinition({...element}) : new TransformDataTypeDefinition();
+
+ return def;
+ }
+
static readTransformDefinition = (element: any): TransformDefinition => {
let def = element ? new TransformDefinition({...element}) : new TransformDefinition();
@@ -2589,11 +2619,11 @@ export class CamelDefinitionYamlStep {
def.tarFile = CamelDefinitionYamlStep.readTarFileDataFormat(element.tarFile);
}
}
- if (element?.tidyMarkup !== undefined) {
- if (Array.isArray(element.tidyMarkup)) {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup[0]);
+ if (element?.pqc !== undefined) {
+ if (Array.isArray(element.pqc)) {
+ def.pqc = CamelDefinitionYamlStep.readPQCDataFormat(element.pqc[0]);
} else {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup);
+ def.pqc = CamelDefinitionYamlStep.readPQCDataFormat(element.pqc);
}
}
if (element?.csv !== undefined) {
@@ -2666,6 +2696,13 @@ export class CamelDefinitionYamlStep {
def.smooks = CamelDefinitionYamlStep.readSmooksDataFormat(element.smooks);
}
}
+ if (element?.ocsf !== undefined) {
+ if (Array.isArray(element.ocsf)) {
+ def.ocsf = CamelDefinitionYamlStep.readOcsfDataFormat(element.ocsf[0]);
+ } else {
+ def.ocsf = CamelDefinitionYamlStep.readOcsfDataFormat(element.ocsf);
+ }
+ }
if (element?.mimeMultipart !== undefined) {
if (Array.isArray(element.mimeMultipart)) {
def.mimeMultipart = CamelDefinitionYamlStep.readMimeMultipartDataFormat(element.mimeMultipart[0]);
@@ -2785,6 +2822,13 @@ export class CamelDefinitionYamlStep {
def.flatpack = CamelDefinitionYamlStep.readFlatpackDataFormat(element.flatpack);
}
}
+ if (element?.groovyXml !== undefined) {
+ if (Array.isArray(element.groovyXml)) {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml[0]);
+ } else {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml);
+ }
+ }
if (element?.swiftMx !== undefined) {
if (Array.isArray(element.swiftMx)) {
def.swiftMx = CamelDefinitionYamlStep.readSwiftMxDataFormat(element.swiftMx[0]);
@@ -3091,13 +3135,6 @@ export class CamelDefinitionYamlStep {
def.tarFile = CamelDefinitionYamlStep.readTarFileDataFormat(element.tarFile);
}
}
- if (element?.tidyMarkup !== undefined) {
- if (Array.isArray(element.tidyMarkup)) {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup[0]);
- } else {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup);
- }
- }
if (element?.csv !== undefined) {
if (Array.isArray(element.csv)) {
def.csv = CamelDefinitionYamlStep.readCsvDataFormat(element.csv[0]);
@@ -3287,6 +3324,13 @@ export class CamelDefinitionYamlStep {
def.flatpack = CamelDefinitionYamlStep.readFlatpackDataFormat(element.flatpack);
}
}
+ if (element?.groovyXml !== undefined) {
+ if (Array.isArray(element.groovyXml)) {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml[0]);
+ } else {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml);
+ }
+ }
if (element?.swiftMx !== undefined) {
if (Array.isArray(element.swiftMx)) {
def.swiftMx = CamelDefinitionYamlStep.readSwiftMxDataFormat(element.swiftMx[0]);
@@ -3431,6 +3475,13 @@ export class CamelDefinitionYamlStep {
return def;
}
+ static readGroovyXmlDataFormat = (element: any): GroovyXmlDataFormat => {
+
+ let def = element ? new GroovyXmlDataFormat({...element}) : new GroovyXmlDataFormat();
+
+ return def;
+ }
+
static readGzipDeflaterDataFormat = (element: any): GzipDeflaterDataFormat => {
let def = element ? new GzipDeflaterDataFormat({...element}) : new GzipDeflaterDataFormat();
@@ -3501,6 +3552,13 @@ export class CamelDefinitionYamlStep {
return def;
}
+ static readOcsfDataFormat = (element: any): OcsfDataFormat => {
+
+ let def = element ? new OcsfDataFormat({...element}) : new OcsfDataFormat();
+
+ return def;
+ }
+
static readPGPDataFormat = (element: any): PGPDataFormat => {
let def = element ? new PGPDataFormat({...element}) : new PGPDataFormat();
@@ -3508,6 +3566,13 @@ export class CamelDefinitionYamlStep {
return def;
}
+ static readPQCDataFormat = (element: any): PQCDataFormat => {
+
+ let def = element ? new PQCDataFormat({...element}) : new PQCDataFormat();
+
+ return def;
+ }
+
static readParquetAvroDataFormat = (element: any): ParquetAvroDataFormat => {
let def = element ? new ParquetAvroDataFormat({...element}) : new ParquetAvroDataFormat();
@@ -3578,13 +3643,6 @@ export class CamelDefinitionYamlStep {
return def;
}
- static readTidyMarkupDataFormat = (element: any): TidyMarkupDataFormat => {
-
- let def = element ? new TidyMarkupDataFormat({...element}) : new TidyMarkupDataFormat();
-
- return def;
- }
-
static readUniVocityCsvDataFormat = (element: any): UniVocityCsvDataFormat => {
let def = element ? new UniVocityCsvDataFormat({...element}) : new UniVocityCsvDataFormat();
@@ -3626,7 +3684,6 @@ export class CamelDefinitionYamlStep {
static readYAMLDataFormat = (element: any): YAMLDataFormat => {
let def = element ? new YAMLDataFormat({...element}) : new YAMLDataFormat();
- def.typeFilter = element && element?.typeFilter ? element?.typeFilter.map((x:any) => CamelDefinitionYamlStep.readYAMLTypeFilterDefinition(x)) :[];
if (element.constructor !== undefined) {
def._constructor = element.constructor;
delete (def as any).constructor;
@@ -3634,13 +3691,6 @@ export class CamelDefinitionYamlStep {
return def;
}
- static readYAMLTypeFilterDefinition = (element: any): YAMLTypeFilterDefinition => {
-
- let def = element ? new YAMLTypeFilterDefinition({...element}) : new YAMLTypeFilterDefinition();
-
- return def;
- }
-
static readZipDeflaterDataFormat = (element: any): ZipDeflaterDataFormat => {
let def = element ? new ZipDeflaterDataFormat({...element}) : new ZipDeflaterDataFormat();
@@ -4454,13 +4504,6 @@ export class CamelDefinitionYamlStep {
def.tarFile = CamelDefinitionYamlStep.readTarFileDataFormat(element.tarFile);
}
}
- if (element?.tidyMarkup !== undefined) {
- if (Array.isArray(element.tidyMarkup)) {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup[0]);
- } else {
- def.tidyMarkup = CamelDefinitionYamlStep.readTidyMarkupDataFormat(element.tidyMarkup);
- }
- }
if (element?.csv !== undefined) {
if (Array.isArray(element.csv)) {
def.csv = CamelDefinitionYamlStep.readCsvDataFormat(element.csv[0]);
@@ -4650,6 +4693,13 @@ export class CamelDefinitionYamlStep {
def.flatpack = CamelDefinitionYamlStep.readFlatpackDataFormat(element.flatpack);
}
}
+ if (element?.groovyXml !== undefined) {
+ if (Array.isArray(element.groovyXml)) {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml[0]);
+ } else {
+ def.groovyXml = CamelDefinitionYamlStep.readGroovyXmlDataFormat(element.groovyXml);
+ }
+ }
if (element?.swiftMx !== undefined) {
if (Array.isArray(element.swiftMx)) {
def.swiftMx = CamelDefinitionYamlStep.readSwiftMxDataFormat(element.swiftMx[0]);
@@ -4925,6 +4975,7 @@ export class CamelDefinitionYamlStep {
case 'toD': return CamelDefinitionYamlStep.readToDynamicDefinition(newBody);
case 'tokenizer': return CamelDefinitionYamlStep.readTokenizerDefinition(newBody);
case 'transacted': return CamelDefinitionYamlStep.readTransactedDefinition(newBody);
+ case 'transformDataType': return CamelDefinitionYamlStep.readTransformDataTypeDefinition(newBody);
case 'transform': return CamelDefinitionYamlStep.readTransformDefinition(newBody);
case 'doTry': return CamelDefinitionYamlStep.readTryDefinition(newBody);
case 'unmarshal': return CamelDefinitionYamlStep.readUnmarshalDefinition(newBody);
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/CamelUtil.ts b/karavan-app/src/main/webui/src/karavan-core/api/CamelUtil.ts
index c05c20a8..b87af3b2 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/CamelUtil.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/CamelUtil.ts
@@ -14,22 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Integration, CamelElement, Beans, MetadataLabels, KameletTypes } from '../model/IntegrationDefinition';
-import { CamelDefinitionApi } from './CamelDefinitionApi';
+import {Beans, CamelElement, Integration, KameletTypes, MetadataLabels} from '../model/IntegrationDefinition';
+import {CamelDefinitionApi} from './CamelDefinitionApi';
import {
- KameletDefinition,
BeanFactoryDefinition,
+ KameletDefinition,
RouteConfigurationDefinition,
- ToDefinition, RouteTemplateDefinition, SetVariableDefinition, SetHeaderDefinition,
+ RouteTemplateDefinition,
+ SetHeaderDefinition,
+ SetVariableDefinition,
+ ToDefinition,
} from '../model/CamelDefinition';
-import { KameletApi } from './KameletApi';
-import { KameletModel, Property } from '../model/KameletModels';
-import { ComponentProperty } from '../model/ComponentModels';
-import { ComponentApi } from './ComponentApi';
-import { CamelMetadataApi, SensitiveKeys } from '../model/CamelMetadata';
-import { CamelDefinitionApiExt } from './CamelDefinitionApiExt';
-import { v4 as uuidv4 } from 'uuid';
-import { CamelDefinitionYaml } from './CamelDefinitionYaml';
+import {KameletApi} from './KameletApi';
+import {KameletModel, Property} from '../model/KameletModels';
+import {ComponentProperty} from '../model/ComponentModels';
+import {ComponentApi} from './ComponentApi';
+import {CamelMetadataApi, SensitiveKeys} from '../model/CamelMetadata';
+import {CamelDefinitionApiExt} from './CamelDefinitionApiExt';
+import {v4 as uuidv4} from 'uuid';
+import {CamelDefinitionYaml} from './CamelDefinitionYaml';
+import {ProjectFile} from "@models/ProjectModels";
+import {KARAVAN_DOT_EXTENSION} from "@karavan-core/contants";
export class CamelUtil {
private constructor() {
@@ -387,4 +392,18 @@ export class CamelUtil {
}
return CamelDefinitionYaml.integrationToYaml(integration);
};
+
+ static hasRouteTemplateDefinitions = (file: ProjectFile): boolean => {
+ try {
+ if (file.name.endsWith(KARAVAN_DOT_EXTENSION.CAMEL_YAML)) {
+ const integration = CamelDefinitionYaml.yamlToIntegration("", file.code);
+ const templates = integration.spec.flows?.filter(flow => flow.dslName === 'RouteTemplateDefinition');
+ return templates?.length !== undefined && templates?.length > 0;
+ } else {
+ return false;
+ }
+ } catch (e) {
+ return false;
+ }
+ };
}
diff --git a/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts b/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
index ae3ab09f..7b9c1005 100644
--- a/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/api/TopologyUtils.ts
@@ -23,25 +23,30 @@ import {
PatchDefinition,
PostDefinition,
PutDefinition,
- RestDefinition, RouteConfigurationDefinition, RouteDefinition, SagaDefinition,
+ RestDefinition,
+ RouteConfigurationDefinition,
+ RouteDefinition,
+ SagaDefinition,
} from '../model/CamelDefinition';
+import {CamelElement, Integration,} from '../model/IntegrationDefinition';
import {
- CamelElement,
- Integration,
-} from '../model/IntegrationDefinition';
-import {
- TopologyAsyncApiNode, TopologyAsyncApiOperation,
+ TopologyAsyncApiNode,
+ TopologyAsyncApiOperation,
TopologyBeanNode,
- TopologyIncomingNode, TopologyOpenApiNode, TopologyOpenApiOperation,
+ TopologyIncomingNode,
+ TopologyOpenApiNode,
+ TopologyOpenApiOperation,
TopologyOutgoingNode,
- TopologyRestNode, TopologyRouteConfigurationNode,
+ TopologyRestNode,
+ TopologyRouteConfigurationNode,
TopologyRouteNode,
} from '../model/TopologyDefinition';
-import { ComponentApi, INTERNAL_COMPONENTS } from './ComponentApi';
-import { CamelDefinitionApiExt } from './CamelDefinitionApiExt';
-import { CamelDisplayUtil } from './CamelDisplayUtil';
-import { CamelUtil } from './CamelUtil';
-import { ASYNCAPI_FILE_NAME_JSON, OPENAPI_FILE_NAME_JSON } from '../contants';
+import {ComponentApi, INTERNAL_COMPONENTS} from './ComponentApi';
+import {CamelDefinitionApiExt} from './CamelDefinitionApiExt';
+import {CamelDisplayUtil} from './CamelDisplayUtil';
+import {CamelUtil} from './CamelUtil';
+import {LANDSCAPE_FILE_NAME_JSON, OPENAPI_FILE_NAME_JSON} from '../contants';
+import {X_APPLICATION_ID} from "@models/CatalogModels";
const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', 'PollEnrichDefinition', 'EnrichDefinition', 'WireTapDefinition', 'SagaDefinition', 'PollDefinition'];
@@ -217,7 +222,7 @@ export class TopologyUtils {
return new TopologyOpenApiNode(OPENAPI_FILE_NAME_JSON, title, operations);
};
- static findTopologyAsyncApiNodes = (json: string): TopologyAsyncApiNode => {
+ static findTopologyAsyncApiNodes = (json: string, applicationName?: string): TopologyAsyncApiNode => {
const operations: TopologyAsyncApiOperation[] = [];
let title = 'AsyncAPI';
@@ -230,20 +235,23 @@ export class TopologyUtils {
if (asyncapi.operations) {
Object.keys(asyncapi.operations).forEach((operationId) => {
const operation = asyncapi.operations[operationId];
- operations.push(
- new TopologyAsyncApiOperation(
- operation.operationId,
- operation.title,
- operation.action,
- operation.channel?.$ref
- )
- );
+ const xApplication: string = operation?.[X_APPLICATION_ID]
+ if (applicationName === undefined || applicationName === xApplication) {
+ operations.push(
+ new TopologyAsyncApiOperation(
+ operationId,
+ operation.summary,
+ operation.action,
+ operation.channel?.$ref
+ )
+ );
+ }
});
}
} catch (err) {
console.error(err);
}
- return new TopologyAsyncApiNode(ASYNCAPI_FILE_NAME_JSON, title, operations);
+ return new TopologyAsyncApiNode(LANDSCAPE_FILE_NAME_JSON, title, operations);
};
static findTopologyIncomingNodes = (integration: Integration[]): TopologyIncomingNode[] => {
@@ -271,7 +279,7 @@ export class TopologyUtils {
const uniqueUri = TopologyUtils.getUniqueUri(r.from);
return new TopologyIncomingNode(id, type, connectorType, r.id, title, filename, r.from, uniqueUri);
}) || [];
- result.push(...templateElements);
+ // result.push(...templateElements);
} catch (e) {
console.error(e);
}
@@ -279,6 +287,21 @@ export class TopologyUtils {
return result;
};
+ static findTopologyRoutesIncomingNodes = (routes: TopologyRouteNode[]): TopologyIncomingNode[] => {
+ const result: TopologyIncomingNode[] = [];
+ const routeElements = routes?.map(r => {
+ const id = 'incoming-' + r.id;
+ const title = CamelDisplayUtil.getStepDescription(r.from);
+ const type = TopologyUtils.isElementInternalComponent(r.from) ? 'internal' : 'external';
+ const connectorType = TopologyUtils.getConnectorType(r.from);
+ let from = CamelUtil.cloneStep(r.from) as FromDefinition;
+ let uniqueUri = TopologyUtils.getUniqueUri(r.from);
+ return new TopologyIncomingNode(id, type, connectorType, r.routeId, title, r.fileName, from, uniqueUri);
+ }) || [];
+ result.push(...routeElements);
+ return result;
+ };
+
static findTopologyRouteNodes = (integration: Integration[]): TopologyRouteNode[] => {
const result: TopologyRouteNode[] = [];
integration.forEach(i => {
@@ -357,6 +380,35 @@ export class TopologyUtils {
return result;
};
+ static findTopologyRoutesOutgoingNodes = (routes: TopologyRouteNode[]): TopologyOutgoingNode[] => {
+ const result: TopologyOutgoingNode[] = [];
+ routes.forEach(route => {
+ try {
+ const filename = route.fileName;
+ const from: FromDefinition = route.from;
+ const elements = TopologyUtils.findOutgoingInStep(from, []);
+ elements.forEach((e: any) => {
+ const step: any = CamelUtil.cloneStep(e)
+ const id = 'outgoing-' + route.id + '-' + step.id;
+ const title = CamelDisplayUtil.getStepDescription(step);
+ const type = TopologyUtils.isElementInternalComponent(step) ? 'internal' : 'external';
+ const connectorType = TopologyUtils.getConnectorType(step);
+ let uniqueUri = TopologyUtils.getUniqueUri(step);
+ if (
+ connectorType !== 'kamelet' ||
+ CamelUtil.getKamelet(e)?.metadata.labels['camel.apache.org/kamelet.type'] !== 'action'
+ ) {
+ result.push(new TopologyOutgoingNode(id, type, connectorType, route.routeId, title, filename, step, uniqueUri));
+ }
+ });
+ result.push(...TopologyUtils.findDeadLetterChannelNodes(route.route, filename));
+ } catch (e) {
+ console.error(e);
+ }
+ });
+ return result;
+ };
+
static findDeadLetterChannelNodes(route: RouteDefinition, filename: string): TopologyOutgoingNode[] {
const result: TopologyOutgoingNode[] = [];
try {
diff --git a/karavan-app/src/main/webui/src/karavan-core/contants.ts b/karavan-app/src/main/webui/src/karavan-core/contants.ts
index 925025ae..adda84ce 100644
--- a/karavan-app/src/main/webui/src/karavan-core/contants.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/contants.ts
@@ -21,6 +21,6 @@ export const KARAVAN_DOT_EXTENSION = {
export const FILE_WORDS_SEPARATOR = '-'
export const OPENAPI_FILE_NAME_JSON = 'openapi.json';
export const OPENAPI_FILE_NAME_YAML = 'openapi.yaml';
-export const ASYNCAPI_FILE_NAME_JSON = 'asyncapi.json';
-export const ASYNCAPI_FILE_NAME_YAML = 'asyncapi.yaml';
-export const JSON_SCHEMA_EXTENSION = ".schema.json";
\ No newline at end of file
+export const JSON_SCHEMA_EXTENSION = ".schema.json";
+
+export const WIZARD_BEAN_TEMPLATE_FILENAME_PREFIX = "wizard-bean-";
diff --git a/karavan-app/src/main/webui/src/karavan-core/model/CamelDefinition.ts b/karavan-app/src/main/webui/src/karavan-core/model/CamelDefinition.ts
index d3d2ae64..cc8a7f99 100644
--- a/karavan-app/src/main/webui/src/karavan-core/model/CamelDefinition.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/model/CamelDefinition.ts
@@ -80,6 +80,7 @@ export class ProcessorDefinition extends CamelElement {
toD?: string;
tokenizer?: TokenizerDefinition;
transacted?: TransactedDefinition;
+ transformDataType?: TransformDataTypeDefinition;
transform?: TransformDefinition;
doTry?: TryDefinition;
unmarshal?: UnmarshalDefinition;
@@ -138,6 +139,7 @@ export class OutputAwareFromDefinition extends CamelElement {
export class AggregateDefinition extends CamelElement {
stepName?: string = 'aggregate';
id?: string = 'aggregate' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
correlationExpression?: ExpressionSubElementDefinition;
@@ -177,6 +179,7 @@ export class AggregateDefinition extends CamelElement {
export class BeanDefinition extends CamelElement {
stepName?: string = 'bean';
id?: string = 'bean' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
ref?: string;
@@ -213,6 +216,7 @@ export class BeanFactoryDefinition extends CamelElement {
export class CatchDefinition extends CamelElement {
stepName?: string = 'doCatch';
id?: string = 'doCatch' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
exception?: string[] = [];
@@ -227,6 +231,7 @@ export class CatchDefinition extends CamelElement {
export class ChoiceDefinition extends CamelElement {
stepName?: string = 'choice';
id?: string = 'choice' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
when?: WhenDefinition[] = [];
@@ -241,6 +246,7 @@ export class ChoiceDefinition extends CamelElement {
export class CircuitBreakerDefinition extends CamelElement {
stepName?: string = 'circuitBreaker';
id?: string = 'circuitBreaker' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
configuration?: string;
@@ -257,6 +263,7 @@ export class CircuitBreakerDefinition extends CamelElement {
export class ClaimCheckDefinition extends CamelElement {
stepName?: string = 'claimCheck';
id?: string = 'claimCheck' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
operation?: string;
@@ -284,6 +291,7 @@ export class ContextScanDefinition extends CamelElement {
export class ConvertBodyDefinition extends CamelElement {
stepName?: string = 'convertBodyTo';
id?: string = 'convertBodyTo' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
type: string = '';
@@ -298,6 +306,7 @@ export class ConvertBodyDefinition extends CamelElement {
export class ConvertHeaderDefinition extends CamelElement {
stepName?: string = 'convertHeaderTo';
id?: string = 'convertHeaderTo' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -314,6 +323,7 @@ export class ConvertHeaderDefinition extends CamelElement {
export class ConvertVariableDefinition extends CamelElement {
stepName?: string = 'convertVariableTo';
id?: string = 'convertVariableTo' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -339,6 +349,7 @@ export class DataFormatDefinition extends CamelElement {
export class DelayDefinition extends CamelElement {
stepName?: string = 'delay';
id?: string = 'delay' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -354,6 +365,7 @@ export class DelayDefinition extends CamelElement {
export class DynamicRouterDefinition extends CamelElement {
stepName?: string = 'dynamicRouter';
id?: string = 'dynamicRouter' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -369,6 +381,7 @@ export class DynamicRouterDefinition extends CamelElement {
export class EnrichDefinition extends CamelElement {
stepName?: string = 'enrich';
id?: string = 'enrich' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -460,6 +473,7 @@ export class FaultToleranceConfigurationDefinition extends CamelElement {
export class FilterDefinition extends CamelElement {
stepName?: string = 'filter';
id?: string = 'filter' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -474,6 +488,7 @@ export class FilterDefinition extends CamelElement {
export class FinallyDefinition extends CamelElement {
stepName?: string = 'doFinally';
id?: string = 'doFinally' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
steps?: CamelElement[] = [];
@@ -486,6 +501,7 @@ export class FinallyDefinition extends CamelElement {
export class FromDefinition extends CamelElement {
stepName?: string = 'from';
id?: string = 'from' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
uri: string = '';
variableReceive?: string;
@@ -519,6 +535,7 @@ export class GlobalOptionsDefinition extends CamelElement {
export class IdempotentConsumerDefinition extends CamelElement {
stepName?: string = 'idempotentConsumer';
id?: string = 'idempotentConsumer' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -537,6 +554,7 @@ export class IdempotentConsumerDefinition extends CamelElement {
export class InputTypeDefinition extends CamelElement {
stepName?: string = 'inputType';
id?: string = 'inputType' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
urn: string = '';
validate?: boolean;
@@ -549,6 +567,7 @@ export class InputTypeDefinition extends CamelElement {
export class InterceptDefinition extends CamelElement {
stepName?: string = 'intercept';
id?: string = 'intercept' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
onWhen?: OnWhenDefinition;
@@ -562,6 +581,7 @@ export class InterceptDefinition extends CamelElement {
export class InterceptFromDefinition extends CamelElement {
stepName?: string = 'interceptFrom';
id?: string = 'interceptFrom' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
uri?: string;
@@ -576,6 +596,7 @@ export class InterceptFromDefinition extends CamelElement {
export class InterceptSendToEndpointDefinition extends CamelElement {
stepName?: string = 'interceptSendToEndpoint';
id?: string = 'interceptSendToEndpoint' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
uri: string = '';
@@ -602,6 +623,7 @@ export class KameletDefinition extends CamelElement {
export class LoadBalanceDefinition extends CamelElement {
stepName?: string = 'loadBalance';
id?: string = 'loadBalance' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
customLoadBalancer?: CustomLoadBalancerDefinition | string;
@@ -621,6 +643,7 @@ export class LoadBalanceDefinition extends CamelElement {
export class LogDefinition extends CamelElement {
stepName?: string = 'log';
id?: string = 'log' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
message: string = '';
@@ -638,6 +661,7 @@ export class LogDefinition extends CamelElement {
export class LoopDefinition extends CamelElement {
stepName?: string = 'loop';
id?: string = 'loop' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -655,6 +679,7 @@ export class LoopDefinition extends CamelElement {
export class MarshalDefinition extends CamelElement {
stepName?: string = 'marshal';
id?: string = 'marshal' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
variableSend?: string;
@@ -675,6 +700,7 @@ export class MarshalDefinition extends CamelElement {
flatpack?: FlatpackDataFormat;
fory?: ForyDataFormat;
grok?: GrokDataFormat;
+ groovyXml?: GroovyXmlDataFormat;
gzipDeflater?: GzipDeflaterDataFormat;
hl7?: HL7DataFormat;
ical?: IcalDataFormat;
@@ -685,8 +711,10 @@ export class MarshalDefinition extends CamelElement {
jsonApi?: JsonApiDataFormat;
lzf?: LZFDataFormat;
mimeMultipart?: MimeMultipartDataFormat;
+ ocsf?: OcsfDataFormat;
parquetAvro?: ParquetAvroDataFormat | string;
pgp?: PGPDataFormat;
+ pqc?: PQCDataFormat;
protobuf?: ProtobufDataFormat | string;
rss?: RssDataFormat;
smooks?: SmooksDataFormat;
@@ -696,7 +724,6 @@ export class MarshalDefinition extends CamelElement {
syslog?: SyslogDataFormat;
tarFile?: TarFileDataFormat;
thrift?: ThriftDataFormat | string;
- tidyMarkup?: TidyMarkupDataFormat;
univocityCsv?: UniVocityCsvDataFormat;
univocityFixed?: UniVocityFixedDataFormat;
univocityTsv?: UniVocityTsvDataFormat;
@@ -713,6 +740,7 @@ export class MarshalDefinition extends CamelElement {
export class MulticastDefinition extends CamelElement {
stepName?: string = 'multicast';
id?: string = 'multicast' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
aggregationStrategy?: string;
@@ -737,6 +765,7 @@ export class MulticastDefinition extends CamelElement {
export class OnCompletionDefinition extends CamelElement {
stepName?: string = 'onCompletion';
id?: string = 'onCompletion' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
mode?: string;
@@ -756,6 +785,7 @@ export class OnCompletionDefinition extends CamelElement {
export class OnExceptionDefinition extends CamelElement {
stepName?: string = 'onException';
id?: string = 'onException' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
exception?: string[] = [];
@@ -779,6 +809,7 @@ export class OnExceptionDefinition extends CamelElement {
export class OnFallbackDefinition extends CamelElement {
stepName?: string = 'onFallback';
id?: string = 'onFallback' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
fallbackViaNetwork?: boolean;
steps?: CamelElement[] = [];
@@ -791,6 +822,7 @@ export class OnFallbackDefinition extends CamelElement {
export class OnWhenDefinition extends CamelElement {
stepName?: string = 'onWhen';
id?: string = 'onWhen' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
expression?: ExpressionDefinition;
public constructor(init?: Partial<OnWhenDefinition>) {
@@ -815,6 +847,7 @@ export class OptimisticLockRetryPolicyDefinition extends CamelElement {
export class OtherwiseDefinition extends CamelElement {
stepName?: string = 'otherwise';
id?: string = 'otherwise' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
steps?: CamelElement[] = [];
@@ -829,6 +862,7 @@ export class OutputDefinition extends CamelElement {
description?: string;
disabled?: boolean;
id?: string = 'output' + uuidv4().substring(0,4);
+ note?: string;
steps?: CamelElement[] = [];
public constructor(init?: Partial<OutputDefinition>) {
super('OutputDefinition');
@@ -839,6 +873,7 @@ export class OutputDefinition extends CamelElement {
export class OutputTypeDefinition extends CamelElement {
stepName?: string = 'outputType';
id?: string = 'outputType' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
urn: string = '';
validate?: boolean;
@@ -862,6 +897,7 @@ export class PackageScanDefinition extends CamelElement {
export class PausableDefinition extends CamelElement {
stepName?: string = 'pausable';
id?: string = 'pausable' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
consumerListener: string = '';
@@ -875,6 +911,7 @@ export class PausableDefinition extends CamelElement {
export class PipelineDefinition extends CamelElement {
stepName?: string = 'pipeline';
id?: string = 'pipeline' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
steps?: CamelElement[] = [];
@@ -887,6 +924,7 @@ export class PipelineDefinition extends CamelElement {
export class PolicyDefinition extends CamelElement {
stepName?: string = 'policy';
id?: string = 'policy' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
ref: string = '';
@@ -900,6 +938,7 @@ export class PolicyDefinition extends CamelElement {
export class PollDefinition extends CamelElement {
stepName?: string = 'poll';
id?: string = 'poll' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
variableReceive?: string;
@@ -915,6 +954,7 @@ export class PollDefinition extends CamelElement {
export class PollEnrichDefinition extends CamelElement {
stepName?: string = 'pollEnrich';
id?: string = 'pollEnrich' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -937,6 +977,7 @@ export class PollEnrichDefinition extends CamelElement {
export class ProcessDefinition extends CamelElement {
stepName?: string = 'process';
id?: string = 'process' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
ref: string = '';
@@ -969,6 +1010,7 @@ export class PropertyExpressionDefinition extends CamelElement {
export class RecipientListDefinition extends CamelElement {
stepName?: string = 'recipientList';
id?: string = 'recipientList' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1029,6 +1071,7 @@ export class RedeliveryPolicyDefinition extends CamelElement {
export class RemoveHeaderDefinition extends CamelElement {
stepName?: string = 'removeHeader';
id?: string = 'removeHeader' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1041,6 +1084,7 @@ export class RemoveHeaderDefinition extends CamelElement {
export class RemoveHeadersDefinition extends CamelElement {
stepName?: string = 'removeHeaders';
id?: string = 'removeHeaders' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
pattern: string = '';
@@ -1054,6 +1098,7 @@ export class RemoveHeadersDefinition extends CamelElement {
export class RemovePropertiesDefinition extends CamelElement {
stepName?: string = 'removeProperties';
id?: string = 'removeProperties' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
pattern: string = '';
@@ -1067,6 +1112,7 @@ export class RemovePropertiesDefinition extends CamelElement {
export class RemovePropertyDefinition extends CamelElement {
stepName?: string = 'removeProperty';
id?: string = 'removeProperty' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1079,6 +1125,7 @@ export class RemovePropertyDefinition extends CamelElement {
export class RemoveVariableDefinition extends CamelElement {
stepName?: string = 'removeVariable';
id?: string = 'removeVariable' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1091,6 +1138,7 @@ export class RemoveVariableDefinition extends CamelElement {
export class ResequenceDefinition extends CamelElement {
stepName?: string = 'resequence';
id?: string = 'resequence' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1126,6 +1174,7 @@ export class Resilience4jConfigurationDefinition extends CamelElement {
timeoutExecutorService?: string;
timeoutDuration?: number;
timeoutCancelRunningFuture?: boolean;
+ micrometerEnabled?: boolean;
recordException?: string[] = [];
ignoreException?: string[] = [];
public constructor(init?: Partial<Resilience4jConfigurationDefinition>) {
@@ -1146,6 +1195,7 @@ export class RestContextRefDefinition extends CamelElement {
export class ResumableDefinition extends CamelElement {
stepName?: string = 'resumable';
id?: string = 'resumable' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
resumeStrategy: string = '';
@@ -1160,6 +1210,7 @@ export class ResumableDefinition extends CamelElement {
export class RollbackDefinition extends CamelElement {
stepName?: string = 'rollback';
id?: string = 'rollback' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
message?: string;
@@ -1219,6 +1270,7 @@ export class RouteContextRefDefinition extends CamelElement {
export class RouteDefinition extends CamelElement {
stepName?: string = 'route';
id?: string = 'route' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
group?: string;
nodePrefixId?: string;
@@ -1246,6 +1298,7 @@ export class RouteDefinition extends CamelElement {
export class RouteTemplateDefinition extends CamelElement {
stepName?: string = 'routeTemplate';
id: string = 'routeTemplate' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
route?: RouteDefinition;
beans?: BeanFactoryDefinition[] = [];
@@ -1272,6 +1325,7 @@ export class RouteTemplateParameterDefinition extends CamelElement {
export class RoutingSlipDefinition extends CamelElement {
stepName?: string = 'routingSlip';
id?: string = 'routingSlip' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1289,6 +1343,7 @@ export class SagaActionUriDefinition extends CamelElement {
description?: string;
disabled?: boolean;
id?: string = 'sagaActionUri' + uuidv4().substring(0,4);
+ note?: string;
parameters?: any = {};
uri: string = '';
public constructor(init?: Partial<SagaActionUriDefinition>) {
@@ -1300,6 +1355,7 @@ export class SagaActionUriDefinition extends CamelElement {
export class SagaDefinition extends CamelElement {
stepName?: string = 'saga';
id?: string = 'saga' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
sagaService?: string;
@@ -1319,6 +1375,7 @@ export class SagaDefinition extends CamelElement {
export class SamplingDefinition extends CamelElement {
stepName?: string = 'sample';
id?: string = 'sample' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
samplePeriod?: string;
@@ -1332,6 +1389,7 @@ export class SamplingDefinition extends CamelElement {
export class ScriptDefinition extends CamelElement {
stepName?: string = 'script';
id?: string = 'script' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1344,6 +1402,7 @@ export class ScriptDefinition extends CamelElement {
export class SetBodyDefinition extends CamelElement {
stepName?: string = 'setBody';
id?: string = 'setBody' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1356,6 +1415,7 @@ export class SetBodyDefinition extends CamelElement {
export class SetExchangePatternDefinition extends CamelElement {
stepName?: string = 'setExchangePattern';
id?: string = 'setExchangePattern' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
pattern?: string;
@@ -1368,6 +1428,7 @@ export class SetExchangePatternDefinition extends CamelElement {
export class SetHeaderDefinition extends CamelElement {
stepName?: string = 'setHeader';
id?: string = 'setHeader' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1381,6 +1442,7 @@ export class SetHeaderDefinition extends CamelElement {
export class SetHeadersDefinition extends CamelElement {
stepName?: string = 'setHeaders';
id?: string = 'setHeaders' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
headers?: SetHeaderDefinition[] = [];
@@ -1393,6 +1455,7 @@ export class SetHeadersDefinition extends CamelElement {
export class SetPropertyDefinition extends CamelElement {
stepName?: string = 'setProperty';
id?: string = 'setProperty' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1406,6 +1469,7 @@ export class SetPropertyDefinition extends CamelElement {
export class SetVariableDefinition extends CamelElement {
stepName?: string = 'setVariable';
id?: string = 'setVariable' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
name: string = '';
@@ -1419,6 +1483,7 @@ export class SetVariableDefinition extends CamelElement {
export class SetVariablesDefinition extends CamelElement {
stepName?: string = 'setVariables';
id?: string = 'setVariables' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
variables?: SetVariableDefinition[] = [];
@@ -1431,6 +1496,7 @@ export class SetVariablesDefinition extends CamelElement {
export class SortDefinition extends CamelElement {
stepName?: string = 'sort';
id?: string = 'sort' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1444,6 +1510,7 @@ export class SortDefinition extends CamelElement {
export class SplitDefinition extends CamelElement {
stepName?: string = 'split';
id?: string = 'split' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1470,6 +1537,7 @@ export class SplitDefinition extends CamelElement {
export class StepDefinition extends CamelElement {
stepName?: string = 'step';
id?: string = 'step' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
steps?: CamelElement[] = [];
@@ -1482,6 +1550,7 @@ export class StepDefinition extends CamelElement {
export class StopDefinition extends CamelElement {
stepName?: string = 'stop';
id?: string = 'stop' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
public constructor(init?: Partial<StopDefinition>) {
@@ -1516,6 +1585,7 @@ export class TemplatedRouteParameterDefinition extends CamelElement {
export class ThreadPoolProfileDefinition extends CamelElement {
stepName?: string = 'threadPoolProfile';
id?: string = 'threadPoolProfile' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
defaultProfile?: boolean;
poolSize?: number;
@@ -1534,6 +1604,7 @@ export class ThreadPoolProfileDefinition extends CamelElement {
export class ThreadsDefinition extends CamelElement {
stepName?: string = 'threads';
id?: string = 'threads' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
executorService?: string;
@@ -1545,7 +1616,7 @@ export class ThreadsDefinition extends CamelElement {
allowCoreThreadTimeOut?: boolean;
threadName?: string;
rejectedPolicy?: string;
- callerRunsWhenRejected?: string;
+ callerRunsWhenRejected?: boolean;
public constructor(init?: Partial<ThreadsDefinition>) {
super('ThreadsDefinition');
Object.assign(this, init);
@@ -1555,6 +1626,7 @@ export class ThreadsDefinition extends CamelElement {
export class ThrottleDefinition extends CamelElement {
stepName?: string = 'throttle';
id?: string = 'throttle' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1574,6 +1646,7 @@ export class ThrottleDefinition extends CamelElement {
export class ThrowExceptionDefinition extends CamelElement {
stepName?: string = 'throwException';
id?: string = 'throwException' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
message?: string;
@@ -1588,6 +1661,7 @@ export class ThrowExceptionDefinition extends CamelElement {
export class ToDefinition extends CamelElement {
stepName?: string = 'to';
id?: string = 'to' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
variableSend?: string;
@@ -1604,6 +1678,7 @@ export class ToDefinition extends CamelElement {
export class ToDynamicDefinition extends CamelElement {
stepName?: string = 'toD';
id?: string = 'toD' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
uri: string = '';
@@ -1624,6 +1699,7 @@ export class ToDynamicDefinition extends CamelElement {
export class TokenizerDefinition extends CamelElement {
stepName?: string = 'tokenizer';
id?: string = 'tokenizer' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
langChain4jCharacterTokenizer?: LangChain4jCharacterTokenizerDefinition;
@@ -1649,6 +1725,7 @@ export class TokenizerImplementationDefinition extends CamelElement {
export class TransactedDefinition extends CamelElement {
stepName?: string = 'transacted';
id?: string = 'transacted' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
ref?: string;
@@ -1659,14 +1736,27 @@ export class TransactedDefinition extends CamelElement {
}
}
+export class TransformDataTypeDefinition extends CamelElement {
+ stepName?: string = 'transformDataType';
+ id?: string = 'transformDataType' + uuidv4().substring(0,4);
+ note?: string;
+ description?: string;
+ disabled?: boolean;
+ fromType?: string;
+ toType: string = '';
+ public constructor(init?: Partial<TransformDataTypeDefinition>) {
+ super('TransformDataTypeDefinition');
+ Object.assign(this, init);
+ }
+}
+
export class TransformDefinition extends CamelElement {
stepName?: string = 'transform';
id?: string = 'transform' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
- fromType?: string;
- toType?: string;
public constructor(init?: Partial<TransformDefinition>) {
super('TransformDefinition');
Object.assign(this, init);
@@ -1676,6 +1766,7 @@ export class TransformDefinition extends CamelElement {
export class TryDefinition extends CamelElement {
stepName?: string = 'doTry';
id?: string = 'doTry' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
doCatch?: CatchDefinition[] = [];
@@ -1690,6 +1781,7 @@ export class TryDefinition extends CamelElement {
export class UnmarshalDefinition extends CamelElement {
stepName?: string = 'unmarshal';
id?: string = 'unmarshal' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
variableSend?: string;
@@ -1711,6 +1803,7 @@ export class UnmarshalDefinition extends CamelElement {
flatpack?: FlatpackDataFormat;
fory?: ForyDataFormat;
grok?: GrokDataFormat;
+ groovyXml?: GroovyXmlDataFormat;
gzipDeflater?: GzipDeflaterDataFormat;
hl7?: HL7DataFormat;
ical?: IcalDataFormat;
@@ -1721,8 +1814,10 @@ export class UnmarshalDefinition extends CamelElement {
jsonApi?: JsonApiDataFormat;
lzf?: LZFDataFormat;
mimeMultipart?: MimeMultipartDataFormat;
+ ocsf?: OcsfDataFormat;
parquetAvro?: ParquetAvroDataFormat | string;
pgp?: PGPDataFormat;
+ pqc?: PQCDataFormat;
protobuf?: ProtobufDataFormat | string;
rss?: RssDataFormat;
smooks?: SmooksDataFormat;
@@ -1732,7 +1827,6 @@ export class UnmarshalDefinition extends CamelElement {
syslog?: SyslogDataFormat;
tarFile?: TarFileDataFormat;
thrift?: ThriftDataFormat | string;
- tidyMarkup?: TidyMarkupDataFormat;
univocityCsv?: UniVocityCsvDataFormat;
univocityFixed?: UniVocityFixedDataFormat;
univocityTsv?: UniVocityTsvDataFormat;
@@ -1749,6 +1843,7 @@ export class UnmarshalDefinition extends CamelElement {
export class ValidateDefinition extends CamelElement {
stepName?: string = 'validate';
id?: string = 'validate' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1771,6 +1866,7 @@ export class ValueDefinition extends CamelElement {
export class WhenDefinition extends CamelElement {
stepName?: string = 'when';
id?: string = 'when' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
expression?: ExpressionDefinition;
@@ -1784,6 +1880,7 @@ export class WhenDefinition extends CamelElement {
export class WireTapDefinition extends CamelElement {
stepName?: string = 'wireTap';
id?: string = 'wireTap' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
copy?: boolean;
@@ -1965,6 +2062,7 @@ export class BindyDataFormat extends CamelElement {
id?: string = 'bindy' + uuidv4().substring(0,4);
type?: string;
classType?: string;
+ defaultValueStringAsNull?: boolean;
allowEmptyStream?: boolean;
unwrapSingleInstance?: boolean;
locale?: string;
@@ -1997,10 +2095,10 @@ export class CryptoDataFormat extends CamelElement {
dataFormatName?: string = 'crypto';
id?: string = 'crypto' + uuidv4().substring(0,4);
algorithm?: string;
- keyRef?: string;
+ key?: string;
cryptoProvider?: string;
- initVectorRef?: string;
- algorithmParameterRef?: string;
+ initVector?: string;
+ algorithmParameterSpec?: string;
bufferSize?: number;
macAlgorithm?: string;
shouldAppendHMAC?: boolean;
@@ -2014,15 +2112,14 @@ export class CryptoDataFormat extends CamelElement {
export class CsvDataFormat extends CamelElement {
dataFormatName?: string = 'csv';
id?: string = 'csv' + uuidv4().substring(0,4);
- formatRef?: string;
- formatName?: string;
+ format?: string;
commentMarkerDisabled?: boolean;
commentMarker?: string;
delimiter?: string;
escapeDisabled?: boolean;
escape?: string;
headerDisabled?: boolean;
- header?: string[] = [];
+ header?: string;
allowMissingColumnNames?: boolean;
ignoreEmptyLines?: boolean;
ignoreSurroundingSpaces?: boolean;
@@ -2077,6 +2174,7 @@ export class DataFormatsDefinition extends CamelElement {
flatpack?: FlatpackDataFormat;
fory?: ForyDataFormat;
grok?: GrokDataFormat;
+ groovyXml?: GroovyXmlDataFormat;
gzipDeflater?: GzipDeflaterDataFormat;
hl7?: HL7DataFormat;
ical?: IcalDataFormat;
@@ -2098,7 +2196,6 @@ export class DataFormatsDefinition extends CamelElement {
syslog?: SyslogDataFormat;
tarFile?: TarFileDataFormat;
thrift?: ThriftDataFormat | string;
- tidyMarkup?: TidyMarkupDataFormat;
univocityCsv?: UniVocityCsvDataFormat;
univocityFixed?: UniVocityFixedDataFormat;
univocityTsv?: UniVocityTsvDataFormat;
@@ -2188,7 +2285,7 @@ export class FlatpackDataFormat extends CamelElement {
allowShortLines?: boolean;
ignoreExtraColumns?: boolean;
textQualifier?: string;
- parserFactoryRef?: string;
+ parserFactory?: string;
public constructor(init?: Partial<FlatpackDataFormat>) {
super('FlatpackDataFormat');
Object.assign(this, init);
@@ -2221,6 +2318,16 @@ export class GrokDataFormat extends CamelElement {
}
}
+export class GroovyXmlDataFormat extends CamelElement {
+ dataFormatName?: string = 'groovyXml';
+ id?: string = 'groovyXml' + uuidv4().substring(0,4);
+ attributeMapping?: boolean;
+ public constructor(init?: Partial<GroovyXmlDataFormat>) {
+ super('GroovyXmlDataFormat');
+ Object.assign(this, init);
+ }
+}
+
export class GzipDeflaterDataFormat extends CamelElement {
dataFormatName?: string = 'gzipDeflater';
id?: string = 'gzipDeflater' + uuidv4().substring(0,4);
@@ -2233,6 +2340,7 @@ export class GzipDeflaterDataFormat extends CamelElement {
export class HL7DataFormat extends CamelElement {
dataFormatName?: string = 'hl7';
id?: string = 'hl7' + uuidv4().substring(0,4);
+ parser?: string;
validate?: boolean;
public constructor(init?: Partial<HL7DataFormat>) {
super('HL7DataFormat');
@@ -2304,7 +2412,7 @@ export class JaxbDataFormat extends CamelElement {
fragment?: boolean;
partClass?: string;
partNamespace?: string;
- namespacePrefixRef?: string;
+ namespacePrefix?: string;
xmlStreamWriterWrapper?: string;
schemaLocation?: string;
noNamespaceSchemaLocation?: string;
@@ -2385,6 +2493,22 @@ export class MimeMultipartDataFormat extends CamelElement {
}
}
+export class OcsfDataFormat extends CamelElement {
+ dataFormatName?: string = 'null';
+ allowUnmarshallType?: boolean;
+ collectionType?: string;
+ id?: string;
+ objectMapper?: string;
+ prettyPrint?: boolean;
+ unmarshalType?: string;
+ useDefaultObjectMapper?: boolean;
+ useList?: boolean;
+ public constructor(init?: Partial<OcsfDataFormat>) {
+ super('OcsfDataFormat');
+ Object.assign(this, init);
+ }
+}
+
export class PGPDataFormat extends CamelElement {
dataFormatName?: string = 'pgp';
id?: string = 'pgp' + uuidv4().substring(0,4);
@@ -2408,6 +2532,22 @@ export class PGPDataFormat extends CamelElement {
}
}
+export class PQCDataFormat extends CamelElement {
+ dataFormatName?: string = 'null';
+ bufferSize?: number;
+ id?: string;
+ keyEncapsulationAlgorithm?: string;
+ keyGenerator?: string;
+ keyPair?: string;
+ provider?: string;
+ symmetricKeyAlgorithm?: string;
+ symmetricKeyLength?: number;
+ public constructor(init?: Partial<PQCDataFormat>) {
+ super('PQCDataFormat');
+ Object.assign(this, init);
+ }
+}
+
export class ParquetAvroDataFormat extends CamelElement {
dataFormatName?: string = 'parquetAvro';
id?: string = 'parquetAvro' + uuidv4().substring(0,4);
@@ -2474,10 +2614,11 @@ export class SoapDataFormat extends CamelElement {
id?: string = 'soap' + uuidv4().substring(0,4);
contextPath: string = '';
encoding?: string;
- elementNameStrategyRef?: string;
+ elementNameStrategy?: string;
version?: string;
- namespacePrefixRef?: string;
+ namespacePrefix?: string;
schema?: string;
+ ignoreUnmarshalledHeaders?: boolean;
public constructor(init?: Partial<SoapDataFormat>) {
super('SoapDataFormat');
Object.assign(this, init);
@@ -2497,10 +2638,10 @@ export class SwiftMtDataFormat extends CamelElement {
export class SwiftMxDataFormat extends CamelElement {
dataFormatName?: string = 'swiftMx';
id?: string = 'swiftMx' + uuidv4().substring(0,4);
- writeConfigRef?: string;
writeInJson?: boolean;
readMessageId?: string;
- readConfigRef?: string;
+ readConfig?: string;
+ writeConfig?: string;
public constructor(init?: Partial<SwiftMxDataFormat>) {
super('SwiftMxDataFormat');
Object.assign(this, init);
@@ -2541,17 +2682,6 @@ export class ThriftDataFormat extends CamelElement {
}
}
-export class TidyMarkupDataFormat extends CamelElement {
- dataFormatName?: string = 'tidyMarkup';
- id?: string = 'tidyMarkup' + uuidv4().substring(0,4);
- dataObjectType?: string;
- omitXmlDeclaration?: boolean;
- public constructor(init?: Partial<TidyMarkupDataFormat>) {
- super('TidyMarkupDataFormat');
- Object.assign(this, init);
- }
-}
-
export class UniVocityCsvDataFormat extends CamelElement {
dataFormatName?: string = 'univocityCsv';
id?: string = 'univocityCsv' + uuidv4().substring(0,4);
@@ -2648,11 +2778,12 @@ export class XMLSecurityDataFormat extends CamelElement {
secureTagContents?: boolean;
keyCipherAlgorithm?: string;
recipientKeyAlias?: string;
- keyOrTrustStoreParametersRef?: string;
+ keyOrTrustStoreParameters?: string;
keyPassword?: string;
digestAlgorithm?: string;
mgfAlgorithm?: string;
addKeyValueForEncryptedKey?: boolean;
+ namespace?: string;
public constructor(init?: Partial<XMLSecurityDataFormat>) {
super('XMLSecurityDataFormat');
Object.assign(this, init);
@@ -2671,7 +2802,7 @@ export class YAMLDataFormat extends CamelElement {
useApplicationContextClassLoader?: boolean;
prettyFlow?: boolean;
allowAnyType?: boolean;
- typeFilter?: YAMLTypeFilterDefinition[] = [];
+ typeFilter?: string;
maxAliasesForCollections?: number;
allowRecursiveKeys?: boolean;
public constructor(init?: Partial<YAMLDataFormat>) {
@@ -2680,16 +2811,6 @@ export class YAMLDataFormat extends CamelElement {
}
}
-export class YAMLTypeFilterDefinition extends CamelElement {
- stepName?: string = 'yAMLTypeFilter';
- type?: string;
- value?: string;
- public constructor(init?: Partial<YAMLTypeFilterDefinition>) {
- super('YAMLTypeFilterDefinition');
- Object.assign(this, init);
- }
-}
-
export class ZipDeflaterDataFormat extends CamelElement {
dataFormatName?: string = 'zipDeflater';
id?: string = 'zipDeflater' + uuidv4().substring(0,4);
@@ -2826,6 +2947,8 @@ export class CSimpleExpression extends CamelElement {
expressionName?: string = 'csimple';
id?: string = 'csimple' + uuidv4().substring(0,4);
expression: string = '';
+ trimResult?: boolean;
+ pretty?: boolean;
resultType?: string;
trim?: boolean;
public constructor(init?: Partial<CSimpleExpression>) {
@@ -3066,6 +3189,9 @@ export class SimpleExpression extends CamelElement {
expressionName?: string = 'simple';
id?: string = 'simple' + uuidv4().substring(0,4);
expression: string = '';
+ trimResult?: boolean;
+ pretty?: boolean;
+ nested?: boolean;
resultType?: string;
trim?: boolean;
public constructor(init?: Partial<SimpleExpression>) {
@@ -3294,6 +3420,7 @@ export class BearerTokenDefinition extends CamelElement {
export class DeleteDefinition extends CamelElement {
stepName?: string = 'delete';
id?: string = 'delete' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3324,6 +3451,7 @@ export class DeleteDefinition extends CamelElement {
export class GetDefinition extends CamelElement {
stepName?: string = 'get';
id?: string = 'get' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3354,6 +3482,7 @@ export class GetDefinition extends CamelElement {
export class HeadDefinition extends CamelElement {
stepName?: string = 'head';
id?: string = 'head' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3409,6 +3538,7 @@ export class OAuth2Definition extends CamelElement {
export class OpenApiDefinition extends CamelElement {
stepName?: string = 'openApi';
id?: string = 'openApi' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
specification: string = '';
@@ -3455,6 +3585,7 @@ export class ParamDefinition extends CamelElement {
export class PatchDefinition extends CamelElement {
stepName?: string = 'patch';
id?: string = 'patch' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3485,6 +3616,7 @@ export class PatchDefinition extends CamelElement {
export class PostDefinition extends CamelElement {
stepName?: string = 'post';
id?: string = 'post' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3515,6 +3647,7 @@ export class PostDefinition extends CamelElement {
export class PutDefinition extends CamelElement {
stepName?: string = 'put';
id?: string = 'put' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3575,6 +3708,7 @@ export class ResponseMessageDefinition extends CamelElement {
export class RestBindingDefinition extends CamelElement {
stepName?: string = 'restBinding';
id?: string = 'restBinding' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
consumes?: string;
produces?: string;
@@ -3635,6 +3769,7 @@ export class RestConfigurationDefinition extends CamelElement {
export class RestDefinition extends CamelElement {
stepName?: string = 'rest';
id?: string = 'rest' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
disabled?: boolean;
path?: string;
@@ -3690,6 +3825,7 @@ export class RestSecuritiesDefinition extends CamelElement {
export class RestsDefinition extends CamelElement {
stepName?: string = 'rests';
id?: string = 'rests' + uuidv4().substring(0,4);
+ note?: string;
description?: string;
rest?: RestDefinition[] = [];
public constructor(init?: Partial<RestsDefinition>) {
@@ -3822,6 +3958,7 @@ export class DataFormatTransformerDefinition extends CamelElement {
flatpack?: FlatpackDataFormat;
fory?: ForyDataFormat;
grok?: GrokDataFormat;
+ groovyXml?: GroovyXmlDataFormat;
gzipDeflater?: GzipDeflaterDataFormat;
hl7?: HL7DataFormat;
ical?: IcalDataFormat;
@@ -3843,7 +3980,6 @@ export class DataFormatTransformerDefinition extends CamelElement {
syslog?: SyslogDataFormat;
tarFile?: TarFileDataFormat;
thrift?: ThriftDataFormat | string;
- tidyMarkup?: TidyMarkupDataFormat;
univocityCsv?: UniVocityCsvDataFormat;
univocityFixed?: UniVocityFixedDataFormat;
univocityTsv?: UniVocityTsvDataFormat;
diff --git a/karavan-app/src/main/webui/src/karavan-core/model/CamelMetadata.ts b/karavan-app/src/main/webui/src/karavan-core/model/CamelMetadata.ts
index d774d7fc..4da402ce 100644
--- a/karavan-app/src/main/webui/src/karavan-core/model/CamelMetadata.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/model/CamelMetadata.ts
@@ -143,6 +143,7 @@ export const DataFormats: [string, string, string][] = [
['flatpack','Flatpack',"Marshal and unmarshal Java lists and maps to/from flat files (such as CSV, delimited, or fixed length formats) using Flatpack library."],
['fory','Fory',"Serialize and deserialize messages using Apache Fory"],
['grok','Grok',"Unmarshal unstructured data to objects using Logstash based Grok patterns."],
+ ['groovyXml','Groovy XML',"Transform between XML and Groovy Node (Map structure) objects."],
['gzipDeflater','GZip Deflater',"Compress and decompress messages using java.util.zip.GZIPStream."],
['hl7','HL7',"Marshal and unmarshal HL7 (Health Care) model objects using the HL7 MLLP codec."],
['ical','iCal',"Marshal and unmarshal iCal (.ics) documents to/from model objects."],
@@ -164,7 +165,6 @@ export const DataFormats: [string, string, string][] = [
['syslog','Syslog',"Marshall SyslogMessages to RFC3164 and RFC5424 messages and back."],
['tarFile','Tar File',"Archive files into tarballs or extract files from tarballs."],
['thrift','Thrift',"Serialize and deserialize messages using Apache Thrift binary data format."],
- ['tidyMarkup','TidyMarkup',"Parse (potentially invalid) HTML into valid HTML or DOM."],
['univocityCsv','uniVocity CSV',"Marshal and unmarshal Java objects from and to CSV (Comma Separated Values) using UniVocity Parsers."],
['univocityFixed','uniVocity Fixed Length',"Marshal and unmarshal Java objects from and to fixed length records using UniVocity Parsers."],
['univocityTsv','uniVocity TSV',"Marshal and unmarshal Java objects from and to TSV (Tab-Separated Values) records using UniVocity Parsers."],
@@ -207,10 +207,10 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
]),
new ElementMeta('barcode', 'BarcodeDataFormat', 'Barcode', "Transform strings to various 1D/2D barcode bitmap formats and back.", 'dataformat,transformation', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('barcodeFormat', 'Barcode Format', "Barcode format such as QR-Code", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('imageType', 'Image Type', "Image type of the barcode such as png", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('width', 'Width', "Width of the barcode", 'number', '', '', false, false, false, false, '', ''),
- new PropertyMeta('height', 'Height', "Height of the barcode", 'number', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('barcodeFormat', 'Barcode Format', "Barcode format such as QR-Code", 'string', 'AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, RSS_14, RSS_EXPANDED, UPC_A, UPC_E, UPC_EAN_EXTENSION', 'QR_CODE', false, false, false, false, '', ''),
+ new PropertyMeta('imageType', 'Image Type', "Image type of the barcode such as png", 'string', 'JPG, GIF, PNG', 'PNG', false, false, false, false, '', ''),
+ new PropertyMeta('width', 'Width', "Width of the barcode", 'number', '', '100', false, false, false, false, '', ''),
+ new PropertyMeta('height', 'Height', "Height of the barcode", 'number', '', '100', false, false, false, false, '', ''),
], [
]),
new ElementMeta('base64', 'Base64DataFormat', 'Base64', "Encode and decode data using Base64.", 'dataformat,transformation', [
@@ -236,6 +236,7 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('type', 'Type', "Whether to use Csv, Fixed, or KeyValue.", 'string', 'Csv, Fixed, KeyValue', '', true, false, false, false, '', ''),
new PropertyMeta('classType', 'Class Type', "Name of model class to use.", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('defaultValueStringAsNull', 'Default Value String As Null', "To change the default value for string types to be null instead of an empty string.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('allowEmptyStream', 'Allow Empty Stream', "Whether to allow empty streams in the unmarshal process. If true, no exception will be thrown when a body without records is provided.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('unwrapSingleInstance', 'Unwrap Single Instance', "When unmarshalling should a single instance be unwrapped and returned instead of wrapped in a java.util.List.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
new PropertyMeta('locale', 'Locale', "To configure a default locale to use, such as us for united states. To use the JVM platform default locale then use the name default", 'string', '', '', false, false, false, false, 'advanced', ''),
@@ -258,10 +259,10 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new ElementMeta('crypto', 'CryptoDataFormat', 'Crypto (Java Cryptographic Extension)', "Encrypt and decrypt messages using Java Cryptography Extension (JCE).", 'dataformat,transformation,security', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('algorithm', 'Algorithm', "The JCE algorithm name indicating the cryptographic algorithm that will be used.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('keyRef', 'Key Ref', "Refers to the secret key to lookup from the register to use.", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('key', 'Key', "Refers to the secret key to lookup from the register to use.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('cryptoProvider', 'Crypto Provider', "The name of the JCE Security Provider that should be used.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('initVectorRef', 'Init Vector Ref', "Refers to a byte array containing the Initialization Vector that will be used to initialize the Cipher.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('algorithmParameterRef', 'Algorithm Parameter Ref', "A JCE AlgorithmParameterSpec used to initialize the Cipher. Will lookup the type using the given name as a java.security.spec.AlgorithmParameterSpec type.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('initVector', 'Init Vector', "Refers to a byte array containing the Initialization Vector that will be used to initialize the Cipher.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('algorithmParameterSpec', 'Algorithm Parameter Spec', "A JCE AlgorithmParameterSpec used to initialize the Cipher. Will lookup the type using the given name as a java.security.spec.AlgorithmParameterSpec type.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('bufferSize', 'Buffer Size', "The size of the buffer used in the signature process.", 'number', '', '4096', false, false, false, false, '', ''),
new PropertyMeta('macAlgorithm', 'Mac Algorithm', "The JCE algorithm name indicating the Message Authentication algorithm.", 'string', '', 'HmacSHA1', false, false, false, false, '', ''),
new PropertyMeta('shouldAppendHMAC', 'Should Append HMAC', "Flag indicating that a Message Authentication Code should be calculated and appended to the encrypted data.", 'boolean', '', 'true', false, false, false, false, '', ''),
@@ -270,15 +271,14 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
]),
new ElementMeta('csv', 'CsvDataFormat', 'CSV', "Handle CSV (Comma Separated Values) payloads.", 'dataformat,transformation,csv', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('formatRef', 'Format Ref', "The reference format to use, it will be updated with the other format options, the default value is CSVFormat.DEFAULT", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('formatName', 'Format Name', "The name of the format to use, the default value is CSVFormat.DEFAULT", 'string', 'DEFAULT, EXCEL, INFORMIX_UNLOAD, INFORMIX_UNLOAD_CSV, MYSQL, RFC4180', 'DEFAULT', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('format', 'Format', "The format to use.", 'string', 'DEFAULT, EXCEL, INFORMIX_UNLOAD, INFORMIX_UNLOAD_CSV, MONGODB_CSV, MONGODB_TSV, MYSQL, ORACLE, POSTGRESQL_CSV, POSTGRESQL_TEXT, RFC4180', 'DEFAULT', false, false, false, false, '', ''),
new PropertyMeta('commentMarkerDisabled', 'Comment Marker Disabled', "Disables the comment marker of the reference format.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('commentMarker', 'Comment Marker', "Sets the comment marker of the reference format.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('delimiter', 'Delimiter', "Sets the delimiter to use. The default value is , (comma)", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('escapeDisabled', 'Escape Disabled', "Use for disabling using escape character", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('escape', 'Escape', "Sets the escape character to use", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('headerDisabled', 'Header Disabled', "Use for disabling headers", 'boolean', '', 'false', false, false, false, false, '', ''),
- new PropertyMeta('header', 'Header', "To configure the CSV headers", 'string', '', '', false, false, true, true, '', ''),
+ new PropertyMeta('header', 'Header', "To configure the CSV headers. Multiple headers can be separated by comma.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('allowMissingColumnNames', 'Allow Missing Column Names', "Whether to allow missing column names.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('ignoreEmptyLines', 'Ignore Empty Lines', "Whether to ignore empty lines.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('ignoreSurroundingSpaces', 'Ignore Surrounding Spaces', "Whether to ignore surrounding spaces", 'boolean', '', 'false', false, false, false, false, '', ''),
@@ -323,6 +323,7 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('flatpack', 'flatpack', "flatpack", 'FlatpackDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('fory', 'fory', "fory", 'ForyDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('grok', 'grok', "grok", 'GrokDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('groovyXml', 'groovyXml', "groovyXml", 'GroovyXmlDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('gzipDeflater', 'gzipDeflater', "gzipDeflater", 'GzipDeflaterDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('hl7', 'hl7', "hl7", 'HL7DataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('ical', 'ical', "ical", 'IcalDataFormat', '', '', false, false, false, true, '', ''),
@@ -344,7 +345,6 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('syslog', 'syslog', "syslog", 'SyslogDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('tarFile', 'tarFile', "tarFile", 'TarFileDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('thrift', 'thrift', "thrift", 'ThriftDataFormat', '', '', false, false, false, true, '', ''),
- new PropertyMeta('tidyMarkup', 'tidyMarkup', "tidyMarkup", 'TidyMarkupDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityCsv', 'univocityCsv', "univocityCsv", 'UniVocityCsvDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityFixed', 'univocityFixed', "univocityFixed", 'UniVocityFixedDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityTsv', 'univocityTsv', "univocityTsv", 'UniVocityTsvDataFormat', '', '', false, false, false, true, '', ''),
@@ -414,7 +414,7 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('allowShortLines', 'Allow Short Lines', "Allows for lines to be shorter than expected and ignores the extra characters", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('ignoreExtraColumns', 'Ignore Extra Columns', "Allows for lines to be longer than expected and ignores the extra characters.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('textQualifier', 'Text Qualifier', "If the text is qualified with a character. Uses quote character by default.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('parserFactoryRef', 'Parser Factory Ref', "References to a custom parser factory to lookup in the registry", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('parserFactory', 'Parser Factory', "References to a custom parser factory to lookup in the registry", 'string', '', '', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('fory', 'ForyDataFormat', 'Fory', "Serialize and deserialize messages using Apache Fory", 'dataformat,transformation', [
@@ -433,12 +433,18 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('namedOnly', 'Named Only', "Whether to capture named expressions only or not (i.e. %{IP:ip} but not ${IP})", 'boolean', '', 'false', false, false, false, false, '', ''),
], [
]),
+ new ElementMeta('groovyXml', 'GroovyXmlDataFormat', 'Groovy XML', "Transform between XML and Groovy Node (Map structure) objects.", 'dataformat,transformation,xml', [
+ new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('attributeMapping', 'Attribute Mapping', "To turn on or off attribute mapping. When enabled then keys that start with _ or character will be mapped to an XML attribute, and vise versa. This rule is what Jackson and other XML or JSon libraries uses.", 'boolean', '', 'true', false, false, false, false, '', ''),
+ ], [
+ ]),
new ElementMeta('gzipDeflater', 'GzipDeflaterDataFormat', 'GZip Deflater', "Compress and decompress messages using java.util.zip.GZIPStream.", 'dataformat,transformation', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
], [
]),
new ElementMeta('hl7', 'HL7DataFormat', 'HL7', "Marshal and unmarshal HL7 (Health Care) model objects using the HL7 MLLP codec.", 'dataformat,transformation,health', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('parser', 'Parser', "To use a custom HL7 parser", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('validate', 'Validate', "Whether to validate the HL7 message Is by default true.", 'boolean', '', 'true', false, false, false, false, '', ''),
], [
]),
@@ -490,13 +496,13 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('fragment', 'Fragment', "To turn on marshalling XML fragment trees. By default JAXB looks for XmlRootElement annotation on given class to operate on whole XML tree. This is useful but not always - sometimes generated code does not have XmlRootElement annotation, sometimes you need unmarshall only part of tree. In that case you can use partial unmarshalling. To enable this behaviours you need set property partClass. Camel will pass this class to JAXB's unmarshaler [...]
new PropertyMeta('partClass', 'Part Class', "Name of class used for fragment parsing. See more details at the fragment option.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('partNamespace', 'Part Namespace', "XML namespace to use for fragment parsing. See more details at the fragment option.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('namespacePrefixRef', 'Namespace Prefix Ref', "When marshalling using JAXB or SOAP then the JAXB implementation will automatic assign namespace prefixes, such as ns2, ns3, ns4 etc. To control this mapping, Camel allows you to refer to a map which contains the desired mapping.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('namespacePrefix', 'Namespace Prefix', "When marshalling using JAXB or SOAP then the JAXB implementation will automatically assign namespace prefixes, such as ns2, ns3, ns4 etc. To control this mapping, Camel allows you to refer to a map which contains the desired mapping.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('xmlStreamWriterWrapper', 'Xml Stream Writer Wrapper', "To use a custom xml stream writer.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('schemaLocation', 'Schema Location', "To define the location of the schema", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('noNamespaceSchemaLocation', 'No Namespace Schema Location', "To define the location of the namespaceless schema", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('jaxbProviderProperties', 'Jaxb Provider Properties', "Refers to a custom java.util.Map to lookup in the registry containing custom JAXB provider properties to be used with the JAXB marshaller.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('contentTypeHeader', 'Content Type Header', "Whether the data format should set the Content-Type header with the type from the data format. For example application/xml for data formats marshalling to XML, or application/json for data formats marshalling to JSON", 'boolean', '', 'true', false, false, false, false, '', ''),
- new PropertyMeta('accessExternalSchemaProtocols', 'Access External Schema Protocols', "Only in use if schema validation has been enabled. Restrict access to the protocols specified for external reference set by the schemaLocation attribute, Import and Include element. Examples of protocols are file, http, jar:file. false or none to deny all access to external references; a specific protocol, such as file, to give permission to only the protocol; the keyword all to grant permissio [...]
+ new PropertyMeta('accessExternalSchemaProtocols', 'Access External Schema Protocols', "Only in use if schema validation has been enabled. Restrict access to the protocols specified for external reference set by the schemaLocation attribute, Import and Include element. Examples of protocols are file, http, jar:file. empty, false or none to deny all access to external references; a specific protocol, such as file, to give permission to only the protocol; the keyword all to grant pe [...]
], [
]),
new ElementMeta('jsonApi', 'JsonApiDataFormat', 'JSonApi', "Marshal and unmarshal JSON:API resources using JSONAPI-Converter library.", 'dataformat,transformation', [
@@ -610,23 +616,24 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('contextPath', 'Context Path', "Package name where your JAXB classes are located.", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('encoding', 'Encoding', "To overrule and use a specific encoding", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('elementNameStrategyRef', 'Element Name Strategy Ref', "Refers to an element strategy to lookup from the registry. An element name strategy is used for two purposes. The first is to find a xml element name for a given object and soap action when marshaling the object into a SOAP message. The second is to find an Exception class for a given soap fault name. The following three element strategy class name is provided out of the box. QNameStrategy - Uses a fixed qNa [...]
+ new PropertyMeta('elementNameStrategy', 'Element Name Strategy', "Refers to an element strategy to lookup from the registry. An element name strategy is used for two purposes. The first is to find a xml element name for a given object and soap action when marshaling the object into a SOAP message. The second is to find an Exception class for a given soap fault name. The following three element strategy class name is provided out of the box. QNameStrategy - Uses a fixed qName that [...]
new PropertyMeta('version', 'Version', "SOAP version should either be 1.1 or 1.2. Is by default 1.1", 'string', '1.1, 1.2', '1.1', false, false, false, false, '', ''),
- new PropertyMeta('namespacePrefixRef', 'Namespace Prefix Ref', "When marshalling using JAXB or SOAP then the JAXB implementation will automatic assign namespace prefixes, such as ns2, ns3, ns4 etc. To control this mapping, Camel allows you to refer to a map which contains the desired mapping.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('namespacePrefix', 'Namespace Prefix', "When marshalling using JAXB or SOAP then the JAXB implementation will automatic assign namespace prefixes, such as ns2, ns3, ns4 etc. To control this mapping, Camel allows you to refer to a map which contains the desired mapping.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('schema', 'Schema', "To validate against an existing schema. Your can use the prefix classpath:, file: or http: to specify how the resource should be resolved. You can separate multiple schema files by using the ',' character.", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('ignoreUnmarshalledHeaders', 'Ignore Unmarshalled Headers', "Whether to ignore headers that was not unmarshalled. By default, headers which could not be unmarshalled is recorded in the org.apache.camel.dataformat.soap.UNMARSHALLED_HEADER_LIST header which allows to inspect any problematic header.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('swiftMt', 'SwiftMtDataFormat', 'SWIFT MT', "Encode and decode SWIFT MT messages.", 'dataformat,transformation,finance', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('writeInJson', 'Write In Json', "The flag indicating that messages must be marshalled in a JSON format.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('writeInJson', 'Write In Json', "The flag indicating that messages must be marshalled in a JSON format.", 'boolean', '', 'false', false, false, false, false, '', ''),
], [
]),
new ElementMeta('swiftMx', 'SwiftMxDataFormat', 'SWIFT MX', "Encode and decode SWIFT MX messages.", 'dataformat,transformation,finance', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('writeConfigRef', 'Write Config Ref', "Refers to a specific configuration to use when marshalling a message to lookup from the registry.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('writeInJson', 'Write In Json', "The flag indicating that messages must be marshalled in a JSON format.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('writeInJson', 'Write In Json', "The flag indicating that messages must be marshalled in a JSON format.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('readMessageId', 'Read Message Id', "The type of MX message to produce when unmarshalling an input stream. If not set, it will be automatically detected from the namespace used.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('readConfigRef', 'Read Config Ref', "Refers to a specific configuration to use when unmarshalling an input stream to lookup from the registry.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('readConfig', 'Read Config', "Refers to a specific configuration to use when unmarshalling an input stream to lookup from the registry.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('writeConfig', 'Write Config', "Refers to a specific configuration to use when marshalling a message to lookup from the registry.", 'string', '', '', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('syslog', 'SyslogDataFormat', 'Syslog', "Marshall SyslogMessages to RFC3164 and RFC5424 messages and back.", 'dataformat,transformation,monitoring', [
@@ -648,12 +655,6 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('contentTypeHeader', 'Content Type Header', "Whether the data format should set the Content-Type header with the type from the data format. For example application/xml for data formats marshalling to XML, or application/json for data formats marshalling to JSON", 'boolean', '', 'true', false, false, false, false, '', ''),
], [
]),
- new ElementMeta('tidyMarkup', 'TidyMarkupDataFormat', 'TidyMarkup', "Parse (potentially invalid) HTML into valid HTML or DOM.", 'dataformat,transformation', [
- new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('dataObjectType', 'Data Object Type', "What data type to unmarshal as, can either be org.w3c.dom.Node or java.lang.String. Is by default org.w3c.dom.Node", 'string', 'org.w3c.dom.Node, java.lang.String', 'org.w3c.dom.Node', false, false, false, false, '', ''),
- new PropertyMeta('omitXmlDeclaration', 'Omit Xml Declaration', "When returning a String, do we omit the XML declaration in the top.", 'boolean', '', 'false', false, false, false, false, '', ''),
- ], [
- ]),
new ElementMeta('univocityCsv', 'UniVocityCsvDataFormat', 'uniVocity CSV', "Marshal and unmarshal Java objects from and to CSV (Comma Separated Values) using UniVocity Parsers.", 'dataformat,transformation,csv', [
new PropertyMeta('id', 'Id', "The id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('delimiter', 'Delimiter', "The delimiter of values", 'string', '', ',', false, false, false, false, '', ''),
@@ -725,11 +726,12 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('secureTagContents', 'Secure Tag Contents', "A boolean value to specify whether the XML Element is to be encrypted or the contents of the XML Element. false = Element Level. true = Element Content Level.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('keyCipherAlgorithm', 'Key Cipher Algorithm', "The cipher algorithm to be used for encryption/decryption of the asymmetric key. The available choices are: XMLCipher.RSA_v1dot5 XMLCipher.RSA_OAEP XMLCipher.RSA_OAEP_11 The default value is XMLCipher.RSA_OAEP", 'string', 'RSA_v1dot5, RSA_OAEP, RSA_OAEP_11', 'RSA_OAEP', false, false, false, false, '', ''),
new PropertyMeta('recipientKeyAlias', 'Recipient Key Alias', "The key alias to be used when retrieving the recipient's public or private key from a KeyStore when performing asymmetric key encryption or decryption.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('keyOrTrustStoreParametersRef', 'Key Or Trust Store Parameters Ref', "Refers to a KeyStore instance to lookup in the registry, which is used for configuration options for creating and loading a KeyStore instance that represents the sender's trustStore or recipient's keyStore.", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('keyOrTrustStoreParameters', 'Key Or Trust Store Parameters', "Refers to a KeyStore instance to lookup in the registry, which is used for configuration options for creating and loading a KeyStore instance that represents the sender's trustStore or recipient's keyStore.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('keyPassword', 'Key Password', "The password to be used for retrieving the private key from the KeyStore. This key is used for asymmetric decryption.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('digestAlgorithm', 'Digest Algorithm', "The digest algorithm to use with the RSA OAEP algorithm. The available choices are: XMLCipher.SHA1 XMLCipher.SHA256 XMLCipher.SHA512 The default value is XMLCipher.SHA1", 'string', 'SHA1, SHA256, SHA512', 'SHA1', false, false, false, false, '', ''),
new PropertyMeta('mgfAlgorithm', 'Mgf Algorithm', "The MGF Algorithm to use with the RSA OAEP algorithm. The available choices are: EncryptionConstants.MGF1_SHA1 EncryptionConstants.MGF1_SHA256 EncryptionConstants.MGF1_SHA512 The default value is EncryptionConstants.MGF1_SHA1", 'string', 'MGF1_SHA1, MGF1_SHA256, MGF1_SHA512', 'MGF1_SHA1', false, false, false, false, '', ''),
new PropertyMeta('addKeyValueForEncryptedKey', 'Add Key Value For Encrypted Key', "Whether to add the public key used to encrypt the session key as a KeyValue in the EncryptedKey structure or not.", 'boolean', '', 'true', false, false, false, false, '', ''),
+ new PropertyMeta('namespace', 'Namespace', "Refers to a Map XML Namespaces of prefix - uri mappings", 'string', '', '', false, false, false, false, '', ''),
], [
]),
new ElementMeta('yaml', 'YAMLDataFormat', 'YAML', "Marshal and unmarshal Java objects to and from YAML.", 'dataformat,transformation,yaml', [
@@ -743,7 +745,7 @@ export const CamelDataFormatMetadata: ElementMeta[] = [
new PropertyMeta('useApplicationContextClassLoader', 'Use Application Context Class Loader', "Use ApplicationContextClassLoader as custom ClassLoader", 'boolean', '', 'true', false, false, false, false, '', ''),
new PropertyMeta('prettyFlow', 'Pretty Flow', "Force the emitter to produce a pretty YAML document when using the flow style.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('allowAnyType', 'Allow Any Type', "Allow any class to be un-marshaled", 'boolean', '', 'false', false, false, false, false, '', ''),
- new PropertyMeta('typeFilter', 'Type Filter', "Set the types SnakeYAML is allowed to un-marshall", 'YAMLTypeFilterDefinition', '', '', false, false, true, true, '', ''),
+ new PropertyMeta('typeFilter', 'Type Filter', "Set the types SnakeYAML is allowed to un-marshall. Multiple types can be separated by comma.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('maxAliasesForCollections', 'Max Aliases For Collections', "Set the maximum amount of aliases allowed for collections.", 'number', '', '50', false, false, false, false, 'advanced', ''),
new PropertyMeta('allowRecursiveKeys', 'Allow Recursive Keys', "Set whether recursive keys are allowed.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
], [
@@ -795,15 +797,17 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new ElementMeta('csimple', 'CSimpleExpression', 'CSimple', "Evaluate a compiled simple expression.", 'language,java', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
+ new PropertyMeta('trimResult', 'Trim Result', "Whether to trim the returned values when this language are in use. For example the output result may contain unwanted line breaks at the beginning and end such as when using Java DSL with multi-line blocks. Is default false to be backwards compatible with existing behavior.", 'boolean', '', 'false', false, false, false, false, '', ''),
+ new PropertyMeta('pretty', 'Pretty', "To pretty format the output (only JSon or XML supported)", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('constant', 'ConstantExpression', 'Constant', "A fixed value set only once during the route startup.", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('datasonnet', 'DatasonnetExpression', 'DataSonnet', "To use DataSonnet scripts for message transformations.", 'language,transformation', [
@@ -813,26 +817,26 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('outputMediaType', 'Output Media Type', "The String representation of the MediaType to output", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('exchangeProperty', 'ExchangePropertyExpression', 'ExchangeProperty', "Gets a property from the Exchange.", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('groovy', 'GroovyExpression', 'Groovy', "Evaluates a Groovy script.", 'language,script', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('header', 'HeaderExpression', 'Header', "Gets a header from the Exchange.", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('hl7terser', 'Hl7TerserExpression', 'HL7 Terser', "Get the value of a HL7 message field specified by terse location specification syntax.", 'language,hl7', [
@@ -840,7 +844,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('java', 'JavaExpression', 'Java', "Evaluates a Java (Java compiled once at runtime) expression.", 'language', [
@@ -849,14 +853,14 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('preCompile', 'Pre Compile', "Whether the expression should be pre compiled once during initialization phase. If this is turned off, then the expression is reloaded and compiled on each evaluation.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
new PropertyMeta('singleQuotes', 'Single Quotes', "Whether single quotes can be used as replacement for double quotes. This is convenient when you need to work with strings inside strings.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('js', 'JavaScriptExpression', 'JavaScript', "Evaluates a JavaScript expression.", 'language,javascript', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('jq', 'JqExpression', 'JQ', "Evaluates a JQ expression against a JSON message body.", 'language,json', [
@@ -864,7 +868,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('jsonpath', 'JsonPathExpression', 'JSONPath', "Evaluates a JSONPath expression against a JSON message body.", 'language,json', [
@@ -878,14 +882,14 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('option', 'Option', "To configure additional options on JSONPath. Multiple values can be separated by comma.", 'string', 'DEFAULT_PATH_LEAF_TO_NULL, ALWAYS_RETURN_LIST, AS_PATH_LIST, SUPPRESS_EXCEPTIONS, REQUIRE_PROPERTIES', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('language', 'LanguageExpression', 'Language', "Evaluates a custom language.", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('language', 'Language', "The name of the language to use", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('method', 'MethodCallExpression', 'Bean Method', "Calls a Java bean method.", 'language,core,java', [
@@ -896,42 +900,45 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('scope', 'Scope', "Scope of bean. When using singleton scope (default) the bean is created or looked up only once and reused for the lifetime of the endpoint. The bean should be thread-safe in case concurrent threads is calling the bean at the same time. When using request scope the bean is created or looked up once per request (exchange). This can be used if you want to store state on a bean while processing a request and you want to call the same bean instance [...]
new PropertyMeta('validate', 'Validate', "Whether to validate the bean has the configured method.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('mvel', 'MvelExpression', 'MVEL', "Evaluates a MVEL template.", 'language,java', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('python', 'PythonExpression', 'Python', "Evaluates a Python expression.", 'language,python', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('ref', 'RefExpression', 'Ref', "Uses an existing expression from the registry.", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('simple', 'SimpleExpression', 'Simple', "Evaluates a Camel simple expression.", 'language,core,java', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
+ new PropertyMeta('trimResult', 'Trim Result', "Whether to trim the returned values when this language are in use. For example the output result may contain unwanted line breaks at the beginning and end such as when using Java DSL with multi-line blocks. Is default false to be backwards compatible with existing behavior.", 'boolean', '', 'false', false, false, false, false, '', ''),
+ new PropertyMeta('pretty', 'Pretty', "To pretty format the output (only JSon or XML supported)", 'boolean', '', 'false', false, false, false, false, '', ''),
+ new PropertyMeta('nested', 'Nested', "If the result is a nested simple expression should this expression be evaluated as well", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('spel', 'SpELExpression', 'SpEL', "Evaluates a Spring expression (SpEL).", 'language,spring', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('tokenize', 'TokenizerExpression', 'Tokenize', "Tokenize text payloads using delimiter patterns.", 'language,core', [
@@ -947,13 +954,13 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('skipFirst', 'Skip First', "To skip the very first element", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('variable', 'VariableExpression', 'Variable', "Gets a variable", 'language,core', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('wasm', 'WasmExpression', 'Wasm', "Call a wasm (web assembly) function.", 'language', [
@@ -961,7 +968,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('expression', 'Expression', "The expression value in your chosen language syntax", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('module', 'Module', "Set the module (the distributable, loadable, and executable unit of code in WebAssembly) resource that provides the expression function.", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('xtokenize', 'XMLTokenizerExpression', 'XML Tokenize', "Tokenize XML payloads.", 'language,core,xml', [
@@ -972,7 +979,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('namespace', 'Namespace', "Injects the XML Namespaces of prefix - uri mappings", 'PropertyDefinition', '', '', false, false, true, true, 'common', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('xpath', 'XPathExpression', 'XPath', "Evaluates an XPath expression against an XML payload.", 'language,core,xml', [
@@ -989,7 +996,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('namespace', 'Namespace', "Injects the XML Namespaces of prefix - uri mappings", 'PropertyDefinition', '', '', false, false, true, true, 'common', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('xquery', 'XQueryExpression', 'XQuery', "Evaluates an XQuery expressions against an XML payload.", 'language,xml', [
@@ -999,7 +1006,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
new PropertyMeta('namespace', 'Namespace', "Injects the XML Namespaces of prefix - uri mappings", 'PropertyDefinition', '', '', false, false, true, true, 'common', ''),
new PropertyMeta('source', 'Source', "Source to use, instead of message body. You can prefix with variable:, header:, or property: to specify kind of source. Otherwise, the source is assumed to be a variable. Use empty or null to use default source, which is the message body.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('resultType', 'Result Type', "Sets the class of the result type (type from output)", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('trim', 'Trim', "Whether to trim the value to remove leading and trailing whitespaces and line breaks", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('trim', 'Trim', "Whether to trim the source code to remove leading and trailing whitespaces and line breaks. For example when using DSLs where the source will span across multiple lines and there may be additional line breaks at both the beginning and end.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
]
@@ -1007,6 +1014,7 @@ export const CamelLanguageMetadata: ElementMeta[] = [
export const CamelModelMetadata: ElementMeta[] = [
new ElementMeta('aggregate', 'AggregateDefinition', 'Aggregate', "Aggregates many messages into a single message", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('correlationExpression', 'Correlation Expression', "The expression used to calculate the correlation key to use for aggregation. The Exchange which has the same correlation key is aggregated together. If the correlation key could not be evaluated an Exception is thrown. You can disable this by using the ignoreBadCorrelationKeys option.", 'ExpressionSubElementDefinition', '', '', true, false, false, true, '', ''),
@@ -1027,7 +1035,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('completionInterval', 'Completion Interval', "A repeating period in millis by which the aggregator will complete all current aggregated exchanges. Camel has a background task which is triggered every period. You cannot use this option together with completionTimeout, only one of them can be used.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('completionTimeout', 'Completion Timeout', "Time in millis that an aggregated exchange should be inactive before its complete (timeout). This option can be set as either a fixed value or using an Expression which allows you to evaluate a timeout dynamically - will use Long as result. If both are set Camel will fallback to use the fixed value if the Expression result was null or 0. You cannot use this option together with completionInterval, only one of the two ca [...]
new PropertyMeta('completionTimeoutCheckerInterval', 'Completion Timeout Checker Interval', "Interval in millis that is used by the background task that checks for timeouts ( org.apache.camel.TimeoutMap ). By default the timeout checker runs every second. The timeout is an approximation and there is no guarantee that the a timeout is triggered exactly after the timeout value. It is not recommended to use very low timeout values or checker intervals.", 'string', '', '1000', false, [...]
- new PropertyMeta('completionFromBatchConsumer', 'Completion From Batch Consumer', "Enables the batch completion mode where we aggregate from a org.apache.camel.BatchConsumer and aggregate the total number of exchanges the org.apache.camel.BatchConsumer has reported as total by checking the exchange property org.apache.camel.Exchange#BATCH_COMPLETE when its complete. This option cannot be used together with discardOnAggregationFailure.", 'boolean', '', 'false', false, false, false [...]
+ new PropertyMeta('completionFromBatchConsumer', 'Completion From Batch Consumer', "Enables the batch completion mode where we aggregate from a org.apache.camel.BatchConsumer and aggregate the total number of exchanges the org.apache.camel.BatchConsumer has reported as total by checking the exchange property org.apache.camel.Exchange#BATCH_COMPLETE when its complete. This option cannot be used together with discardOnAggregationFailure. Important: When using this option, you should [...]
new PropertyMeta('completionOnNewCorrelationGroup', 'Completion On New Correlation Group', "Enables completion on all previous groups when a new incoming correlation group. This can for example be used to complete groups with same correlation keys when they are in consecutive order. Notice when this is enabled then only 1 correlation group can be in progress as when a new correlation group starts, then the previous groups is forced completed.", 'boolean', '', 'false', false, fals [...]
new PropertyMeta('eagerCheckCompletion', 'Eager Check Completion', "Use eager completion checking which means that the completionPredicate will use the incoming Exchange. As opposed to without eager completion checking the completionPredicate will use the aggregated Exchange.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('ignoreInvalidCorrelationKeys', 'Ignore Invalid Correlation Keys', "If a correlation key cannot be successfully evaluated it will be ignored by logging a DEBUG and then just ignore the incoming Exchange.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
@@ -1048,6 +1056,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('bean', 'BeanDefinition', 'Bean', "Calls a Java bean", 'eip,endpoint', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('ref', 'Ref', "Sets a reference to an existing bean to use, which is looked up from the registry", 'string', '', '', false, false, false, false, '', ''),
@@ -1058,6 +1067,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('doCatch', 'CatchDefinition', 'Do Catch', "Catches exceptions as part of a try, catch, finally block", 'error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('exception', 'Exception', "The exception(s) to catch.", 'string', '', '', false, false, true, true, '', ''),
@@ -1070,6 +1080,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('choice', 'ChoiceDefinition', 'Choice', "Route messages based on a series of predicates", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('when', 'When', "Sets the when nodes", 'WhenDefinition', '', '', false, false, true, true, '', ''),
@@ -1079,6 +1090,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('circuitBreaker', 'CircuitBreakerDefinition', 'Circuit Breaker', "Route messages in a fault tolerance way using Circuit Breaker", 'eip,routing,error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('configuration', 'Configuration', "Refers to a circuit breaker configuration (such as resillience4j, or microprofile-fault-tolerance) to use for configuring the circuit breaker EIP.", 'string', '', '', false, false, false, false, '', ''),
@@ -1097,6 +1109,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('claimCheck', 'ClaimCheckDefinition', 'Claim Check', "The Claim Check EIP allows you to replace message content with a claim check (a unique key), which can be used to retrieve the message content at a later time.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('operation', 'Operation', "The claim check operation to use. The following operations are supported: Get - Gets (does not remove) the claim check by the given key. GetAndRemove - Gets and removes the claim check by the given key. Set - Sets a new (will override if key already exists) claim check with the given key. Push - Sets a new claim check on the stack (does not use key). Pop - Gets the latest claim check from the stack (does not use key).", 'string', 'Get, [...]
@@ -1108,6 +1121,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('convertBodyTo', 'ConvertBodyDefinition', 'Convert Body To', "Converts the message body to another type", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('type', 'Type', "The java type to convert to", 'string', '', '', true, false, false, false, '', ''),
@@ -1117,6 +1131,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('convertHeaderTo', 'ConvertHeaderDefinition', 'Convert Header To', "Converts the message header to another type", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of message header to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used.", 'string', '', '', true, false, false, false, '', ''),
@@ -1128,6 +1143,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('convertVariableTo', 'ConvertVariableDefinition', 'Convert Variable To', "Converts the variable to another type", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of variable to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used.", 'string', '', '', true, false, false, false, '', ''),
@@ -1139,6 +1155,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('delay', 'DelayDefinition', 'Delay', "Delays processing for a specified length of time", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to define how long time to wait (in millis)", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1149,6 +1166,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('dynamicRouter', 'DynamicRouterDefinition', 'Dynamic Router', "Route messages based on dynamic rules", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to call that returns the endpoint(s) to route to in the dynamic routing. Important: The expression will be called in a while loop fashion, until the expression returns null which means the dynamic router is finished.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1159,6 +1177,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('enrich', 'EnrichDefinition', 'Enrich', "Enriches a message with data from a secondary resource", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression that computes the endpoint uri to use as the resource endpoint to enrich from", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1178,6 +1197,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('filter', 'FilterDefinition', 'Filter', "Filter out messages based using a predicate", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to determine if the message should be filtered or not. If the expression returns an empty value or false then the message is filtered (dropped), otherwise the message is continued being routed.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1187,6 +1207,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('doFinally', 'FinallyDefinition', 'Do Finally', "Path traversed when a try, catch, finally block exits", 'error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
@@ -1197,6 +1218,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('idempotentConsumer', 'IdempotentConsumerDefinition', 'Idempotent Consumer', "Filters out duplicate messages", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression used to calculate the correlation key to use for duplicate check. The Exchange which has the same correlation key is regarded as a duplicate and will be rejected.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1217,6 +1239,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('loadBalance', 'LoadBalanceDefinition', 'Load Balance', "Balances message processing among a number of nodes", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('customLoadBalancer', 'customLoadBalancer', "customLoadBalancer", 'CustomLoadBalancerDefinition', '', '', false, false, false, true, '', ''),
@@ -1231,6 +1254,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('log', 'LogDefinition', 'Logger', "Used for printing custom messages to the logger.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('message', 'Message', "Sets the log message (uses simple language)", 'string', '', '', true, false, false, false, '', ''),
@@ -1243,6 +1267,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('loop', 'LoopDefinition', 'Loop', "Processes a message multiple times", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to define how many times we should loop. Notice the expression is only evaluated once, and should return a number as how many times to loop. A value of zero or negative means no looping. The loop is like a for-loop fashion, if you want a while loop, then the dynamic router may be a better choice.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1257,6 +1282,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('marshal', 'MarshalDefinition', 'Marshal', "Marshals data into a specified format for transmission over a transport or component", 'eip,dataformat,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('variableSend', 'Variable Send', "To use a variable as the source for the message body to send. This makes it handy to use variables for user data and to easily control what data to use for sending and receiving. Important: When using send variable then the message body is taken from this variable instead of the current message, however the headers from the message will still be used as well. In other words, the variable is used instead of the message body, but e [...]
@@ -1277,6 +1303,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('flatpack', 'flatpack', "flatpack", 'FlatpackDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('fory', 'fory', "fory", 'ForyDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('grok', 'grok', "grok", 'GrokDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('groovyXml', 'groovyXml', "groovyXml", 'GroovyXmlDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('gzipDeflater', 'gzipDeflater', "gzipDeflater", 'GzipDeflaterDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('hl7', 'hl7', "hl7", 'HL7DataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('ical', 'ical', "ical", 'IcalDataFormat', '', '', false, false, false, true, '', ''),
@@ -1287,8 +1314,10 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('jsonApi', 'jsonApi', "jsonApi", 'JsonApiDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('lzf', 'lzf', "lzf", 'LZFDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('mimeMultipart', 'mimeMultipart', "mimeMultipart", 'MimeMultipartDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('ocsf', 'ocsf', "ocsf", 'OcsfDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('parquetAvro', 'parquetAvro', "parquetAvro", 'ParquetAvroDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('pgp', 'pgp', "pgp", 'PGPDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('pqc', 'pqc', "pqc", 'PQCDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('protobuf', 'protobuf', "protobuf", 'ProtobufDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('rss', 'rss', "rss", 'RssDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('smooks', 'smooks', "smooks", 'SmooksDataFormat', '', '', false, false, false, true, '', ''),
@@ -1298,7 +1327,6 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('syslog', 'syslog', "syslog", 'SyslogDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('tarFile', 'tarFile', "tarFile", 'TarFileDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('thrift', 'thrift', "thrift", 'ThriftDataFormat', '', '', false, false, false, true, '', ''),
- new PropertyMeta('tidyMarkup', 'tidyMarkup', "tidyMarkup", 'TidyMarkupDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityCsv', 'univocityCsv', "univocityCsv", 'UniVocityCsvDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityFixed', 'univocityFixed', "univocityFixed", 'UniVocityFixedDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityTsv', 'univocityTsv', "univocityTsv", 'UniVocityTsvDataFormat', '', '', false, false, false, true, '', ''),
@@ -1310,6 +1338,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('multicast', 'MulticastDefinition', 'Multicast', "Routes the same message to multiple paths either sequentially or in parallel.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('aggregationStrategy', 'Aggregation Strategy', "Refers to an AggregationStrategy to be used to assemble the replies from the multicasts, into a single outgoing message from the Multicast. By default Camel will use the last reply as the outgoing message. You can also use a POJO as the AggregationStrategy", 'string', '', '', false, false, false, false, '', 'org.apache.camel.AggregationStrategy'),
@@ -1320,7 +1349,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('synchronous', 'Synchronous', "Sets whether synchronous processing should be strictly used. When enabled then the same thread is used to continue routing after the multicast is complete, even if parallel processing is enabled.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('streaming', 'Streaming', "If enabled then Camel will process replies out-of-order, eg in the order they come back. If disabled, Camel will process replies in the same order as defined by the multicast.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('stopOnException', 'Stop On Exception', "Will now stop further processing if an exception or failure occurred during processing of an org.apache.camel.Exchange and the caused exception will be thrown. Will also stop if processing the exchange failed (has a fault message) or an exception was thrown and handled by the error handler (such as using onException). In all situations the multicast will stop further processing. This is the same behavior as in pipeline, wh [...]
- new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Multicast hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Multicast breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for which it is di [...]
+ new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Multicast hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Multicast breaks out and continues. The timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for which it is difficult for Camel to shut down in a graceful manner may conti [...]
new PropertyMeta('executorService', 'Executor Service', "Refers to a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('onPrepare', 'On Prepare', "Uses the Processor when preparing the org.apache.camel.Exchange to be send. This can be used to deep-clone messages that should be send, or any custom logic needed before the exchange is send.", 'string', '', '', false, false, false, false, 'advanced', 'org.apache.camel.Processor'),
new PropertyMeta('shareUnitOfWork', 'Share Unit Of Work', "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Multicast will by default not share unit of work between the parent exchange and each multicasted exchange. This means each sub exchange has its own individual unit of work.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
@@ -1332,6 +1361,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('pausable', 'PausableDefinition', 'Pausable', "Pausable EIP to support resuming processing from last known offset.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('consumerListener', 'Consumer Listener', "Sets the consumer listener to use", 'string', '', '', true, false, false, false, '', ''),
@@ -1340,6 +1370,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('pipeline', 'PipelineDefinition', 'Pipeline', "Routes the message to a sequence of processors.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
@@ -1347,6 +1378,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('policy', 'PolicyDefinition', 'Policy', "Defines a policy the route will use", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('ref', 'Ref', "Sets a reference to use for lookup the policy in the registry.", 'string', '', '', true, false, false, false, '', ''),
@@ -1355,6 +1387,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('poll', 'PollDefinition', 'Poll', "Polls a message from a static endpoint", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('variableReceive', 'Variable Receive', "To use a variable to store the received message body (only body, not headers). This makes it handy to use variables for user data and to easily control what data to use for sending and receiving. Important: When using receive variable then the received body is stored only in this variable and not on the current message.", 'string', '', '', false, false, false, false, '', ''),
@@ -1365,6 +1398,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('pollEnrich', 'PollEnrichDefinition', 'Poll Enrich', "Enriches messages with data polled from a secondary resource", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression that computes the endpoint uri to use as the resource endpoint to enrich from", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1383,6 +1417,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('process', 'ProcessDefinition', 'Process', "Calls a Camel processor", 'eip,endpoint', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('ref', 'Ref', "Reference to the Processor to lookup in the registry to use. A Processor is a class of type org.apache.camel.Processor, which can are to be called by this EIP. In this processor you have custom Java code, that can work with the message, such as to do custom business logic, special message manipulations and so on. By default, the ref, will lookup the bean in the Camel registry. The ref can use prefix that controls how the processor is obtained. You [...]
@@ -1390,6 +1425,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('recipientList', 'RecipientListDefinition', 'Recipient List', "Route messages to a number of dynamically specified recipients", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression that returns which endpoints (url) to send the message to (the recipients). If the expression return an empty value then the message is not sent to any recipients.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1400,7 +1436,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('parallelAggregate', 'Parallel Aggregate', "If enabled then the aggregate method on AggregationStrategy can be called concurrently. Notice that this would require the implementation of AggregationStrategy to be implemented as thread-safe. By default this is false meaning that Camel synchronizes the call to the aggregate method. Though in some use-cases this can be used to archive higher performance when the AggregationStrategy is implemented as thread-safe.", 'bo [...]
new PropertyMeta('parallelProcessing', 'Parallel Processing', "If enabled then sending messages to the recipients occurs concurrently. Note the caller thread will still wait until all messages has been fully processed, before it continues. Its only the sending and processing the replies from the recipients which happens concurrently. When parallel processing is enabled, then the Camel routing engin will continue processing using last used thread from the parallel thread pool. How [...]
new PropertyMeta('synchronous', 'Synchronous', "Sets whether synchronous processing should be strictly used. When enabled then the same thread is used to continue routing after the recipient list is complete, even if parallel processing is enabled.", 'boolean', '', 'false', false, false, false, false, '', ''),
- new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Recipient List hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Recipient List breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for whic [...]
+ new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Recipient List hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Recipient List breaks out and continues. The timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for which it is difficult for Camel to shut down in a graceful manner [...]
new PropertyMeta('executorService', 'Executor Service', "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatic implied, and you do not have to enable that option as well.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('stopOnException', 'Stop On Exception', "Will now stop further processing if an exception or failure occurred during processing of an org.apache.camel.Exchange and the caused exception will be thrown. Will also stop if processing the exchange failed (has a fault message) or an exception was thrown and handled by the error handler (such as using onException). In all situations the recipient list will stop further processing. This is the same behavior as in pipelin [...]
new PropertyMeta('ignoreInvalidEndpoints', 'Ignore Invalid Endpoints', "Ignore the invalidate endpoint exception when try to create a producer with that endpoint", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
@@ -1414,6 +1450,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('removeHeader', 'RemoveHeaderDefinition', 'Remove Header', "Removes a named header from the message", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of header to remove", 'string', '', '', true, false, false, false, '', ''),
@@ -1421,6 +1458,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('removeHeaders', 'RemoveHeadersDefinition', 'Remove Headers', "Removes message headers whose name matches a specified pattern", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('pattern', 'Pattern', "Name or pattern of headers to remove. The pattern is matched in the following order: 1 = exact match 2 = wildcard (pattern ends with a and the name starts with the pattern) 3 = regular expression (all of above is case in-sensitive).", 'string', '', '', true, false, false, false, '', ''),
@@ -1429,6 +1467,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('removeProperties', 'RemovePropertiesDefinition', 'Remove Properties', "Removes message exchange properties whose name matches a specified pattern", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('pattern', 'Pattern', "Name or pattern of properties to remove. The pattern is matched in the following order: 1 = exact match 2 = wildcard (pattern ends with a and the name starts with the pattern) 3 = regular expression (all of above is case in-sensitive).", 'string', '', '', true, false, false, false, '', ''),
@@ -1437,6 +1476,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('removeProperty', 'RemovePropertyDefinition', 'Remove Property', "Removes a named property from the message exchange", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of property to remove.", 'string', '', '', true, false, false, false, '', ''),
@@ -1444,6 +1484,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('removeVariable', 'RemoveVariableDefinition', 'Remove Variable', "Removes a named variable", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of variable to remove.", 'string', '', '', true, false, false, false, '', ''),
@@ -1451,6 +1492,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('resequence', 'ResequenceDefinition', 'Resequence', "Resequences (re-order) messages based on an expression", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to use for re-ordering the messages, such as a header with a sequence number", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1461,6 +1503,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('resumable', 'ResumableDefinition', 'Resumable', "Resume EIP to support resuming processing from last known offset.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('resumeStrategy', 'Resume Strategy', "Sets the resume strategy to use", 'string', '', '', true, false, false, false, '', ''),
@@ -1470,6 +1513,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('rollback', 'RollbackDefinition', 'Rollback', "Forces a rollback by stopping routing the message", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('message', 'Message', "Message to use in rollback exception", 'string', '', '', false, false, false, false, '', ''),
@@ -1479,6 +1523,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('routingSlip', 'RoutingSlipDefinition', 'Routing Slip', "Routes a message through a series of steps that are pre-determined (the slip)", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to define the routing slip, which defines which endpoints to route the message in a pipeline style. Notice the expression is evaluated once, if you want a more dynamic style, then the dynamic router eip is a better choice.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1491,6 +1536,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('saga', 'SagaDefinition', 'Saga', "Enables Sagas on the route", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('sagaService', 'Saga Service', "Refers to the id to lookup in the registry for the specific CamelSagaService to use.", 'string', '', '', false, false, false, false, 'advanced', ''),
@@ -1505,6 +1551,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('sample', 'SamplingDefinition', 'Sample', "Extract a sample of the messages passing through a route", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('samplePeriod', 'Sample Period', "Sets the sample period during which only a single Exchange will pass through.", 'string', '', '1000', false, false, false, false, '', ''),
@@ -1513,6 +1560,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('script', 'ScriptDefinition', 'Script', "Executes a script from a language which does not change the message body.", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Script to be executed.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1520,6 +1568,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setBody', 'SetBodyDefinition', 'Set Body', "Sets the contents of the message body", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression that returns the new body to use", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1527,6 +1576,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setExchangePattern', 'SetExchangePatternDefinition', 'Set Exchange Pattern', "Sets the exchange pattern on the message exchange", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('pattern', 'Pattern', "Sets the new exchange pattern of the Exchange to be used from this point forward", 'string', 'InOnly, InOut', '', true, false, false, false, '', ''),
@@ -1534,6 +1584,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setHeader', 'SetHeaderDefinition', 'Set Header', "Sets the value of a message header", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of message header to set a new value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used.", 'string', '', '', true, false, false, false, '', ''),
@@ -1542,6 +1593,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setHeaders', 'SetHeadersDefinition', 'Set Headers', "Allows setting multiple headers on the message at the same time.", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('headers', 'Headers', "Contains the headers to be set", 'SetHeaderDefinition', '', '', true, false, true, true, '', ''),
@@ -1549,6 +1601,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setProperty', 'SetPropertyDefinition', 'Set Property', "Sets a named property on the message exchange", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of exchange property to set a new value. The simple language can be used to define a dynamic evaluated exchange property name to be used. Otherwise a constant name will be used.", 'string', '', '', true, false, false, false, '', ''),
@@ -1557,6 +1610,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setVariable', 'SetVariableDefinition', 'Set Variable', "Sets the value of a variable", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('name', 'Name', "Name of variable to set a new value The simple language can be used to define a dynamic evaluated variable name to be used. Otherwise a constant name will be used.", 'string', '', '', true, false, false, false, '', ''),
@@ -1565,6 +1619,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('setVariables', 'SetVariablesDefinition', 'Set Variables', "Allows setting multiple variables at the same time.", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('variables', 'Variables', "Contains the variables to be set", 'SetVariableDefinition', '', '', true, false, true, true, '', ''),
@@ -1572,6 +1627,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('sort', 'SortDefinition', 'Sort', "Sorts the contents of the message", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Optional expression to sort by something else than the message body", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1580,6 +1636,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('split', 'SplitDefinition', 'Split', "Splits a single message into many sub-messages.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression of how to split the message body, such as as-is, using a tokenizer, or using a xpath.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1592,7 +1649,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('synchronous', 'Synchronous', "Sets whether synchronous processing should be strictly used. When enabled then the same thread is used to continue routing after the split is complete, even if parallel processing is enabled.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('streaming', 'Streaming', "When in streaming mode, then the splitter splits the original message on-demand, and each split message is processed one by one. This reduces memory usage as the splitter do not split all the messages first, but then we do not know the total size, and therefore the org.apache.camel.Exchange#SPLIT_SIZE is empty. In non-streaming mode (default) the splitter will split each message first, to know the total size, and then process each messa [...]
new PropertyMeta('stopOnException', 'Stop On Exception', "Will now stop further processing if an exception or failure occurred during processing of an org.apache.camel.Exchange and the caused exception will be thrown. Will also stop if processing the exchange failed (has a fault message) or an exception was thrown and handled by the error handler (such as using onException). In all situations the splitter will stop further processing. This is the same behavior as in pipeline, whi [...]
- new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Splitter hasn't been able to split and process all the sub messages within the given timeframe, then the timeout triggers and the Splitter breaks out and continues. Notice if you provide a TimeoutAwareAggregationStrategy then the timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for which [...]
+ new PropertyMeta('timeout', 'Timeout', "Sets a total timeout specified in millis, when using parallel processing. If the Splitter hasn't been able to send and process all replies within the given timeframe, then the timeout triggers and the Splitter breaks out and continues. The timeout method is invoked before breaking out. If the timeout is reached with running tasks still remaining, certain tasks for which it is difficult for Camel to shut down in a graceful manner may continu [...]
new PropertyMeta('executorService', 'Executor Service', "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatically implied, and you do not have to enable that option as well.", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('onPrepare', 'On Prepare', "Uses the Processor when preparing the org.apache.camel.Exchange to be sent. This can be used to deep-clone messages that should be sent, or any custom logic needed before the exchange is sent.", 'string', '', '', false, false, false, false, 'advanced', 'org.apache.camel.Processor'),
new PropertyMeta('shareUnitOfWork', 'Share Unit Of Work', "Shares the org.apache.camel.spi.UnitOfWork with the parent and each of the sub messages. Splitter will by default not share unit of work between the parent exchange and each split exchange. This means each split exchange has its own individual unit of work.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
@@ -1604,6 +1661,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('step', 'StepDefinition', 'Step', "Routes the message to a sequence of processors which is grouped together as one logical name", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
@@ -1612,12 +1670,14 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('stop', 'StopDefinition', 'Stop', "Stops the processing of the current message", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('threads', 'ThreadsDefinition', 'Threads', "Specifies that all steps after this node are processed asynchronously", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('executorService', 'Executor Service', "To use a custom thread pool", 'string', '', '', false, false, false, false, 'advanced', ''),
@@ -1629,11 +1689,12 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('allowCoreThreadTimeOut', 'Allow Core Thread Time Out', "Whether idle core threads are allowed to timeout and therefore can shrink the pool size below the core pool size Is by default false", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('threadName', 'Thread Name', "Sets the thread name to use.", 'string', '', 'Threads', false, false, false, false, '', ''),
new PropertyMeta('rejectedPolicy', 'Rejected Policy', "Sets the handler for tasks which cannot be executed by the thread pool.", 'string', 'Abort, CallerRuns', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('callerRunsWhenRejected', 'Caller Runs When Rejected', "Whether or not to use as caller runs as fallback when a task is rejected being added to the thread pool (when its full). This is only used as fallback if no rejectedPolicy has been configured, or the thread pool has no configured rejection handler. Is by default true", 'string', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('callerRunsWhenRejected', 'Caller Runs When Rejected', "Whether or not to use as caller runs as fallback when a task is rejected being added to the thread pool (when its full). This is only used as fallback if no rejectedPolicy has been configured, or the thread pool has no configured rejection handler. Is by default true", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
], [
]),
new ElementMeta('throttle', 'ThrottleDefinition', 'Throttle', "Controls the rate at which messages are passed to the next node in the route", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to configure the maximum number of messages to throttle per request", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1648,6 +1709,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('throwException', 'ThrowExceptionDefinition', 'Throw Exception', "Throws an exception", 'error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('message', 'Message', "To create a new exception instance and use the given message as caused message (supports simple language)", 'string', '', '', false, false, false, false, '', ''),
@@ -1657,6 +1719,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('to', 'ToDefinition', 'To', "Sends the message to a static endpoint", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('variableSend', 'Variable Send', "To use a variable as the source for the message body to send. This makes it handy to use variables for user data and to easily control what data to use for sending and receiving. Important: When using send variable then the message body is taken from this variable instead of the current message, however the headers from the message will still be used as well. In other words, the variable is used instead of the message body, but e [...]
@@ -1669,6 +1732,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('toD', 'ToDynamicDefinition', 'To D', "Sends the message to a dynamic endpoint", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('uri', 'Uri', "The uri of the endpoint to send to. The uri can be dynamic computed using the org.apache.camel.language.simple.SimpleLanguage expression.", 'string', '', '', true, false, false, false, '', ''),
@@ -1685,6 +1749,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('tokenizer', 'TokenizerDefinition', 'Specialized tokenizer for AI applications', "Represents a Camel tokenizer for AI.", 'eip,transformation,ai', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('langChain4jCharacterTokenizer', 'langChain4jCharacterTokenizer', "langChain4jCharacterTokenizer", 'LangChain4jCharacterTokenizerDefinition', '', '', false, false, false, true, '', ''),
@@ -1696,23 +1761,33 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('transacted', 'TransactedDefinition', 'Transacted', "Enables transaction on the route", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('ref', 'Ref', "Sets a reference to use for lookup the policy in the registry.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
], [
]),
+ new ElementMeta('transformDataType', 'TransformDataTypeDefinition', 'Transform Data Type', "Transforms the message body based on known data type transformers.", 'eip,transformation', [
+ new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('fromType', 'From Type', "From type used in data type transformation.", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('toType', 'To Type', "To type used as a target data type in the transformation.", 'string', '', '', true, false, false, false, '', ''),
+ ], [
+ ]),
new ElementMeta('transform', 'TransformDefinition', 'Transform', "Transforms the message body based on an expression", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to return the transformed message body (the new message body to use)", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
- new PropertyMeta('fromType', 'From Type', "From type used in data type transformation.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('toType', 'To Type', "To type used as a target data type in the transformation.", 'string', '', '', false, false, false, false, '', ''),
], [
]),
new ElementMeta('doTry', 'TryDefinition', 'Do Try', "Marks the beginning of a try, catch, finally block", 'eip,routing,error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('doCatch', 'Do Catch', "Catches exceptions as part of a try, catch, finally block", 'CatchDefinition', '', '', false, false, true, true, '', ''),
@@ -1722,6 +1797,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('unmarshal', 'UnmarshalDefinition', 'Unmarshal', "Converts the message data received from the wire into a format that Apache Camel processors can consume", 'eip,dataformat,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('variableSend', 'Variable Send', "To use a variable as the source for the message body to send. This makes it handy to use variables for user data and to easily control what data to use for sending and receiving. Important: When using send variable then the message body is taken from this variable instead of the current message, however the headers from the message will still be used as well. In other words, the variable is used instead of the message body, but e [...]
@@ -1743,6 +1819,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('flatpack', 'flatpack', "flatpack", 'FlatpackDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('fory', 'fory', "fory", 'ForyDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('grok', 'grok', "grok", 'GrokDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('groovyXml', 'groovyXml', "groovyXml", 'GroovyXmlDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('gzipDeflater', 'gzipDeflater', "gzipDeflater", 'GzipDeflaterDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('hl7', 'hl7', "hl7", 'HL7DataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('ical', 'ical', "ical", 'IcalDataFormat', '', '', false, false, false, true, '', ''),
@@ -1753,8 +1830,10 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('jsonApi', 'jsonApi', "jsonApi", 'JsonApiDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('lzf', 'lzf', "lzf", 'LZFDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('mimeMultipart', 'mimeMultipart', "mimeMultipart", 'MimeMultipartDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('ocsf', 'ocsf', "ocsf", 'OcsfDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('parquetAvro', 'parquetAvro', "parquetAvro", 'ParquetAvroDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('pgp', 'pgp', "pgp", 'PGPDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('pqc', 'pqc', "pqc", 'PQCDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('protobuf', 'protobuf', "protobuf", 'ProtobufDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('rss', 'rss', "rss", 'RssDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('smooks', 'smooks', "smooks", 'SmooksDataFormat', '', '', false, false, false, true, '', ''),
@@ -1764,7 +1843,6 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('syslog', 'syslog', "syslog", 'SyslogDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('tarFile', 'tarFile', "tarFile", 'TarFileDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('thrift', 'thrift', "thrift", 'ThriftDataFormat', '', '', false, false, false, true, '', ''),
- new PropertyMeta('tidyMarkup', 'tidyMarkup', "tidyMarkup", 'TidyMarkupDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityCsv', 'univocityCsv', "univocityCsv", 'UniVocityCsvDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityFixed', 'univocityFixed', "univocityFixed", 'UniVocityFixedDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityTsv', 'univocityTsv', "univocityTsv", 'UniVocityTsvDataFormat', '', '', false, false, false, true, '', ''),
@@ -1776,6 +1854,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('validate', 'ValidateDefinition', 'Validate', "Validates a message based on an expression", 'eip,transformation', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression to use for validation as a predicate. The expression should return either true or false. If returning false the message is invalid and an exception is thrown.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -1784,6 +1863,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('wireTap', 'WireTapDefinition', 'Wire Tap', "Routes a copy of a message (or creates a new message) to a secondary destination while continue routing the original message.", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('copy', 'Copy', "Uses a copy of the original exchange", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
@@ -1804,6 +1884,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('intercept', 'InterceptDefinition', 'Intercept', "Intercepts a message at each step in the route", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('onWhen', 'On When', "To use an expression to only trigger intercepting in specific situations", 'OnWhenDefinition', '', '', false, false, false, true, '', ''),
@@ -1815,6 +1896,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('interceptFrom', 'InterceptFromDefinition', 'Intercept From', "Intercepts incoming messages", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('uri', 'Uri', "Intercept incoming messages from the uri or uri pattern. If this option is not configured, then all incoming messages is intercepted.", 'string', '', '', false, false, false, false, '', ''),
@@ -1828,6 +1910,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('interceptSendToEndpoint', 'InterceptSendToEndpointDefinition', 'Intercept Send To Endpoint', "Intercepts messages being sent to an endpoint", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('uri', 'Uri', "Intercept sending to the uri or uri pattern.", 'string', '', '', true, false, false, false, '', ''),
@@ -1843,6 +1926,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('onCompletion', 'OnCompletionDefinition', 'On Completion', "Route to be executed when normal route processing completes", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('mode', 'Mode', "Sets the on completion mode. The default value is AfterConsumer", 'string', 'AfterConsumer, BeforeConsumer', 'AfterConsumer', false, false, false, false, 'advanced', ''),
@@ -1858,6 +1942,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('onException', 'OnExceptionDefinition', 'On Exception', "Route to be executed when an exception is thrown", 'error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('exception', 'Exception', "A set of exceptions to react upon.", 'string', '', '', true, false, true, true, '', ''),
@@ -1891,13 +1976,14 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('route', 'RouteDefinition', 'Route', "A Camel route", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('group', 'Group', "The group name for this route. Multiple routes can belong to the same group.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('nodePrefixId', 'Node Prefix Id', "Sets a prefix to use for all node ids (not route id).", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('routeConfigurationId', 'Route Configuration Id', "The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be separated by comma.", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('autoStartup', 'Auto Startup', "Whether to auto start this route", 'boolean', '', 'true', false, false, false, false, '', ''),
new PropertyMeta('startupOrder', 'Startup Order', "To configure the ordering of the routes being started", 'number', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('streamCache', 'Stream Cache', "Whether stream caching is enabled on this route.", 'boolean', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('streamCache', 'Stream Cache', "Whether stream caching is enabled on this route.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('trace', 'Trace', "Whether tracing is enabled on this route.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('messageHistory', 'Message History', "Whether message history is enabled on this route.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('logMask', 'Log Mask', "Whether security mask for Logging is enabled on this route.", 'boolean', '', 'false', false, false, false, false, '', ''),
@@ -1914,6 +2000,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('routeTemplate', 'RouteTemplateDefinition', 'Route Template', "Defines a route template (parameterized routes)", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('route', 'Route', "To define the route in the template", 'RouteDefinition', '', '', true, false, false, true, '', ''),
new PropertyMeta('beans', 'beans', "beans", 'BeanFactoryDefinition', '', '', false, false, true, true, '', ''),
@@ -1952,8 +2039,8 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('enableCORS', 'Enable CORS', "Whether to enable CORS headers in the HTTP response. The default value is false.", 'boolean', '', 'false', false, false, false, false, 'consumer,advanced', ''),
new PropertyMeta('enableNoContentResponse', 'Enable No Content Response', "Whether to return HTTP 204 with an empty body when a response contains an empty JSON object or XML root object. The default value is false.", 'boolean', '', 'false', false, false, false, false, 'consumer,advanced', ''),
new PropertyMeta('inlineRoutes', 'Inline Routes', "Inline routes in rest-dsl which are linked using direct endpoints. Each service in Rest DSL is an individual route, meaning that you would have at least two routes per service (rest-dsl, and the route linked from rest-dsl). By inlining (default) allows Camel to optimize and inline this as a single route, however this requires to use direct endpoints, which must be unique per service. If a route is not using direct endpoint then t [...]
- new PropertyMeta('jsonDataFormat', 'Json Data Format', "Name of specific json data format to use. By default jackson will be used. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('xmlDataFormat', 'Xml Data Format', "Name of specific XML data format to use. By default jaxb will be used. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance.", 'string', '', '', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('jsonDataFormat', 'Json Data Format', "Name of specific json data format to use. By default, jackson will be used. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance.", 'string', 'jackson, jsonb, fastjson, gson', 'jackson', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('xmlDataFormat', 'Xml Data Format', "Name of specific XML data format to use. By default jaxb will be used, but jacksonXml is also supported. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance.", 'string', 'jaxb, jacksonXml', 'jaxb', false, false, false, false, 'advanced', ''),
new PropertyMeta('componentProperty', 'Component Property', "Allows to configure as many additional properties for the rest component in use.", 'RestPropertyDefinition', '', '', false, false, true, true, 'advanced', ''),
new PropertyMeta('endpointProperty', 'Endpoint Property', "Allows to configure as many additional properties for the rest endpoint in use.", 'RestPropertyDefinition', '', '', false, false, true, true, 'advanced', ''),
new PropertyMeta('consumerProperty', 'Consumer Property', "Allows to configure as many additional properties for the rest consumer in use.", 'RestPropertyDefinition', '', '', false, false, true, true, 'consumer,advanced', ''),
@@ -1965,6 +2052,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('rest', 'RestDefinition', 'Rest', "Defines a rest service using the rest-dsl", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "Path of the rest service, such as /foo", 'string', '', '', false, false, false, false, '', ''),
@@ -1989,22 +2077,6 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('put', 'put', "put", 'PutDefinition', '', '', false, false, true, true, '', ''),
], [
]),
- new ElementMeta('beanFactory', 'BeanFactoryDefinition', 'Bean', "Define custom beans that can be used in your Camel routes and in general.", 'configuration', [
- new PropertyMeta('name', 'Name', "The name of the bean (bean id)", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('type', 'Type', "The class name (fully qualified) of the bean", 'string', '', '', true, false, false, false, '', ''),
- new PropertyMeta('initMethod', 'Init Method', "The name of the custom initialization method to invoke after setting bean properties. The method must have no arguments, but may throw any exception.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('destroyMethod', 'Destroy Method', "The name of the custom destroy method to invoke on bean shutdown, such as when Camel is shutting down. The method must have no arguments, but may throw any exception.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('factoryMethod', 'Factory Method', "Name of method to invoke when creating the bean via a factory bean.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('factoryBean', 'Factory Bean', "Name of factory bean (bean id) to use for creating the bean.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('builderClass', 'Builder Class', "Fully qualified class name of builder class to use for creating and configuring the bean. The builder will use the properties values to configure the bean.", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('builderMethod', 'Builder Method', "Name of method when using builder class. This method is invoked after configuring to create the actual bean. This method is often named build (used by default).", 'string', '', 'build', false, false, false, false, '', ''),
- new PropertyMeta('scriptLanguage', 'Script Language', "The script language to use when using inlined script for creating the bean, such as groovy, java, javascript etc.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('constructors', 'Constructors', "Optional constructor arguments for creating the bean. Arguments correspond to specific index of the constructor argument list, starting from zero.", 'object', '', '', false, false, false, false, '', ''),
- new PropertyMeta('properties', 'Properties', "Optional properties to set on the created bean.", 'object', '', '', false, false, false, false, '', ''),
- new PropertyMeta('script', 'Script', "The script to execute that creates the bean when using scripting languages. If the script use the prefix resource: such as resource:classpath:com/foo/myscript.groovy, resource:file:/var/myscript.groovy, then its loaded from the external resource.", 'string', '', '', false, false, false, false, 'advanced', ''),
- new PropertyMeta('scriptPropertyPlaceholders', 'scriptPropertyPlaceholders', "scriptPropertyPlaceholders", 'boolean', '', '', false, false, false, false, '', ''),
- ], [
- ]),
new ElementMeta('contextScan', 'ContextScanDefinition', 'Context Scan', "Scans for Java org.apache.camel.builder.RouteBuilder instances in the context org.apache.camel.spi.Registry .", 'configuration', [
new PropertyMeta('includeNonSingletons', 'Include Non Singletons', "Whether to include non-singleton beans (prototypes) By default only singleton beans is included in the context scan", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('excludes', 'Excludes', "Exclude finding route builder from these java package names.", 'string', '', '', false, false, true, true, '', ''),
@@ -2042,6 +2114,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('from', 'FromDefinition', 'From', "Act as a message source as input to a route", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('uri', 'Uri', "Sets the URI of the endpoint to use", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('variableReceive', 'Variable Receive', "To use a variable to store a copy of the received message body (only body, not headers). This is handy for easy access to the received message body via variables.", 'string', '', '', false, false, false, false, '', ''),
@@ -2060,6 +2133,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('inputType', 'InputTypeDefinition', 'Input Type', "Set the expected data type of the input message. If the actual message type is different at runtime, camel look for a required Transformer and apply if exists. If validate attribute is true then camel applies Validator as well. Type name consists of two parts, 'scheme' and 'name' connected with ':'. For Java type 'name' is a fully qualified class name. For example {code java:java.lang.String} , {code json:ABCOrder} . [...]
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('urn', 'Urn', "The input type URN.", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('validate', 'Validate', "Whether if validation is required for this input type.", 'boolean', '', 'false', false, false, false, false, '', ''),
@@ -2067,6 +2141,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('onFallback', 'OnFallbackDefinition', 'On Fallback', "Route to be executed when Circuit Breaker EIP executes fallback", 'eip,routing,error', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('fallbackViaNetwork', 'Fallback Via Network', "Whether the fallback goes over the network. If the fallback will go over the network it is another possible point of failure. It is important to execute the fallback command on a separate thread-pool, otherwise if the main command were to become latent and fill the thread-pool this would prevent the fallback from running if the two commands share the same pool.", 'boolean', '', 'false', false, false, false, false, 'a [...]
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
@@ -2074,8 +2149,9 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('onWhen', 'OnWhenDefinition', 'On When', "To use a predicate to determine when to trigger this.", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
- new PropertyMeta('expression', 'Expression', "expression", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
+ new PropertyMeta('expression', 'Expression', "The predicate to use", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
], [
]),
new ElementMeta('optimisticLockRetryPolicy', 'OptimisticLockRetryPolicyDefinition', 'Optimistic Lock Retry Policy', "To configure optimistic locking", 'configuration', [
@@ -2088,6 +2164,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('otherwise', 'OtherwiseDefinition', 'Otherwise', "Route to be executed when all other choices evaluate to false", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('steps', 'steps', "steps", 'CamelElement', '', '', false, false, true, true, '', ''),
@@ -2095,6 +2172,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('outputType', 'OutputTypeDefinition', 'Output Type', "Set the expected data type of the output message. If the actual message type is different at runtime, camel look for a required Transformer and apply if exists. If validate attribute is true then camel applies Validator as well. Type name consists of two parts, 'scheme' and 'name' connected with ':'. For Java type 'name' is a fully qualified class name. For example {code java:java.lang.String} , {code json:ABCOrder [...]
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('urn', 'Urn', "Set output type URN.", 'string', '', '', true, false, false, false, '', ''),
new PropertyMeta('validate', 'Validate', "Whether if validation is required for this output type.", 'boolean', '', 'false', false, false, false, false, '', ''),
@@ -2166,6 +2244,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('timeoutExecutorService', 'Timeout Executor Service', "References to a custom thread pool to use when timeout is enabled (uses ForkJoinPool#commonPool() by default)", 'string', '', '', false, false, false, false, 'advanced', ''),
new PropertyMeta('timeoutDuration', 'Timeout Duration', "Configures the thread execution timeout. Default value is 1 second.", 'number', '', '1000', false, false, false, false, '', ''),
new PropertyMeta('timeoutCancelRunningFuture', 'Timeout Cancel Running Future', "Configures whether cancel is called on the running future. Defaults to true.", 'boolean', '', 'true', false, false, false, false, 'advanced', ''),
+ new PropertyMeta('micrometerEnabled', 'Micrometer Enabled', "Whether to enable collecting statistics using Micrometer. This requires adding camel-resilience4j-micrometer JAR to the classpath.", 'boolean', '', 'false', false, false, false, false, '', ''),
new PropertyMeta('recordException', 'Record Exception', "Configure a list of exceptions that are recorded as a failure and thus increase the failure rate. Any exception matching or inheriting from one of the list counts as a failure, unless explicitly ignored via ignoreExceptions.", 'string', '', '', false, false, true, true, 'advanced', ''),
new PropertyMeta('ignoreException', 'Ignore Exception', "Configure a list of exceptions that are ignored and neither count as a failure nor success. Any exception matching or inheriting from one of the list will not count as a failure nor success, even if the exceptions is part of recordExceptions.", 'string', '', '', false, false, true, true, 'advanced', ''),
], [
@@ -2201,6 +2280,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('threadPoolProfile', 'ThreadPoolProfileDefinition', 'Thread Pool Profile', "To configure thread pools", 'configuration', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('defaultProfile', 'Default Profile', "Whether this profile is the default thread pool profile", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('poolSize', 'Pool Size', "Sets the core pool size", 'number', '', '', false, false, false, false, '', ''),
@@ -2218,6 +2298,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('when', 'WhenDefinition', 'When', "Triggers a route when the expression evaluates to true", 'eip,routing', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Disables this EIP from the route.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('expression', 'Expression', "Expression used as the predicate to evaluate whether this when should trigger and route the message or not.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
@@ -2258,6 +2339,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('flatpack', 'flatpack', "flatpack", 'FlatpackDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('fory', 'fory', "fory", 'ForyDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('grok', 'grok', "grok", 'GrokDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('groovyXml', 'groovyXml', "groovyXml", 'GroovyXmlDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('gzipDeflater', 'gzipDeflater', "gzipDeflater", 'GzipDeflaterDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('hl7', 'hl7', "hl7", 'HL7DataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('ical', 'ical', "ical", 'IcalDataFormat', '', '', false, false, false, true, '', ''),
@@ -2279,7 +2361,6 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('syslog', 'syslog', "syslog", 'SyslogDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('tarFile', 'tarFile', "tarFile", 'TarFileDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('thrift', 'thrift', "thrift", 'ThriftDataFormat', '', '', false, false, false, true, '', ''),
- new PropertyMeta('tidyMarkup', 'tidyMarkup', "tidyMarkup", 'TidyMarkupDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityCsv', 'univocityCsv', "univocityCsv", 'UniVocityCsvDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityFixed', 'univocityFixed', "univocityFixed", 'UniVocityFixedDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityTsv', 'univocityTsv', "univocityTsv", 'UniVocityTsvDataFormat', '', '', false, false, false, true, '', ''),
@@ -2454,6 +2535,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('delete', 'DeleteDefinition', 'Delete', "Rest DELETE command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2479,6 +2561,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('get', 'GetDefinition', 'Get', "Rest GET command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2504,6 +2587,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('head', 'HeadDefinition', 'Head', "Rest HEAD command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2534,6 +2618,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('openApi', 'OpenApiDefinition', 'Open Api', "To use OpenApi as contract-first with Camel Rest DSL.", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable all the REST services from the OpenAPI contract from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('specification', 'Specification', "Path to the OpenApi specification file.", 'string', '', '', true, false, false, false, '', ''),
@@ -2565,6 +2650,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('patch', 'PatchDefinition', 'Patch', "Rest PATCH command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2590,6 +2676,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('post', 'PostDefinition', 'Post', "Rest POST command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2615,6 +2702,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('put', 'PutDefinition', 'Put', "Rest PUT command", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('disabled', 'Disabled', "Whether to disable this REST service from the route during build time. Once an REST service has been disabled then it cannot be enabled later at runtime.", 'boolean', '', 'false', false, false, false, false, 'advanced', ''),
new PropertyMeta('path', 'Path', "The path mapping URIs of this REST operation such as /{id}.", 'string', '', '', false, false, false, false, '', ''),
@@ -2660,6 +2748,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('restBinding', 'RestBindingDefinition', 'Rest Binding', "To configure rest binding", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('consumes', 'Consumes', "To define the content type what the REST service consumes (accept as input), such as application/xml or application/json", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('produces', 'Produces', "To define the content type what the REST service produces (uses for output), such as application/xml or application/json", 'string', '', '', false, false, false, false, '', ''),
@@ -2690,6 +2779,7 @@ export const CamelModelMetadata: ElementMeta[] = [
]),
new ElementMeta('rests', 'RestsDefinition', 'Rests', "A series of rest services defined using the rest-dsl", 'rest', [
new PropertyMeta('id', 'Id', "Sets the id of this node", 'string', '', '', false, false, false, false, '', ''),
+ new PropertyMeta('note', 'Note', "Sets the note of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('description', 'Description', "Sets the description of this node", 'string', '', '', false, false, false, false, '', ''),
new PropertyMeta('rest', 'rest', "rest", 'RestDefinition', '', '', false, false, true, true, '', ''),
], [
@@ -2769,6 +2859,7 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('flatpack', 'flatpack', "flatpack", 'FlatpackDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('fory', 'fory', "fory", 'ForyDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('grok', 'grok', "grok", 'GrokDataFormat', '', '', false, false, false, true, '', ''),
+ new PropertyMeta('groovyXml', 'groovyXml', "groovyXml", 'GroovyXmlDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('gzipDeflater', 'gzipDeflater', "gzipDeflater", 'GzipDeflaterDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('hl7', 'hl7', "hl7", 'HL7DataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('ical', 'ical', "ical", 'IcalDataFormat', '', '', false, false, false, true, '', ''),
@@ -2790,7 +2881,6 @@ export const CamelModelMetadata: ElementMeta[] = [
new PropertyMeta('syslog', 'syslog', "syslog", 'SyslogDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('tarFile', 'tarFile', "tarFile", 'TarFileDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('thrift', 'thrift', "thrift", 'ThriftDataFormat', '', '', false, false, false, true, '', ''),
- new PropertyMeta('tidyMarkup', 'tidyMarkup', "tidyMarkup", 'TidyMarkupDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityCsv', 'univocityCsv', "univocityCsv", 'UniVocityCsvDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityFixed', 'univocityFixed', "univocityFixed", 'UniVocityFixedDataFormat', '', '', false, false, false, true, '', ''),
new PropertyMeta('univocityTsv', 'univocityTsv', "univocityTsv", 'UniVocityTsvDataFormat', '', '', false, false, false, true, '', ''),
@@ -2838,7 +2928,7 @@ export const CamelModelMetadata: ElementMeta[] = [
], [
]),
new ElementMeta('predicateValidator', 'PredicateValidatorDefinition', 'Predicate Validator', "To use a predicate to perform validation on the route level.", 'validation', [
- new PropertyMeta('expression', 'Expression', "expression", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
+ new PropertyMeta('expression', 'Expression', "The predicate to use for validation.", 'ExpressionDefinition', '', '', true, false, false, true, '', ''),
new PropertyMeta('type', 'Type', "Set the data type name. If you specify 'xml:XYZ', the validator will be picked up if message type is 'xml:XYZ'. If you specify just 'xml', the validator matches with all of 'xml' message type like 'xml:ABC' or 'xml:DEF'.", 'string', '', '', false, false, false, false, '', ''),
], [
]),
@@ -2851,79 +2941,88 @@ export const CamelModelMetadata: ElementMeta[] = [
]
export const SensitiveKeys: string[] = [
- "oauthtokenurl",
- "clientid",
- "sassignature",
- "connectionstring",
- "sslpassword",
+ "accesskey",
"accesstoken",
+ "accesstokensecret",
"accountkey",
- "proxyauthusername",
- "sslkeypassword",
- "userpassword",
+ "accountsid",
"acltoken",
- "password",
- "accesskey",
+ "api_key",
+ "api_secret",
+ "apikey",
+ "apipassword",
+ "apiuser",
+ "apiusername",
+ "authenticationtoken",
+ "authkey",
+ "authorizationtoken",
+ "authtoken",
+ "azureclientid",
+ "azureclientsecret",
+ "blobaccesskey",
+ "blobstoragesharedkeycredential",
+ "certresourcepassword",
+ "clientid",
+ "clientsecret",
+ "clientsecretcredential",
+ "connectionstring",
+ "consumerkey",
"consumersecret",
- "proxyuser",
- "oauthclientsecret",
- "truststorepassword",
- "accesstokensecret",
- "securerandom",
- "refreshtoken",
- "sessiontoken",
- "publishkey",
- "accountsid",
"emailaddress",
- "blobaccesskey",
- "publickeyid",
+ "httpproxypassword",
+ "kerberosauthticket",
+ "keypassword",
+ "keystorePassword",
+ "keystorepassword",
+ "login",
+ "oauthclientid",
+ "oauthclientsecret",
+ "oauthtoken",
+ "oauthtokenurl",
"p12filename",
- "ssltruststorepassword",
+ "passcode",
"passphrase",
- "privatekeyfile",
- "zookeeperpassword",
- "apiuser",
+ "password",
"personalaccesstoken",
- "authkey",
+ "privatekey",
+ "privatekeyfile",
"privatekeyname",
- "systemid",
- "secretkey",
- "webhookverifytoken",
"privatekeypassword",
+ "proxyauthpassword",
+ "proxyauthusername",
+ "proxypassword",
+ "proxyuser",
+ "proxyusername",
+ "publickeyid",
+ "publishkey",
+ "queueownerawsaccountid",
+ "realm",
+ "refreshtoken",
+ "sascredential",
+ "sasljaasconfig",
+ "saslpassword",
+ "sassignature",
"secret",
- "login",
+ "secretkey",
+ "securerandom",
+ "serviceinstanceid",
+ "sessiontoken",
+ "sharedaccesskey",
"sourceblobaccesskey",
- "apipassword",
- "privatekey",
+ "sslkeypassword",
"sslkeystorepassword",
- "oauthtoken",
- "sascredential",
- "verificationcode",
+ "sslpassword",
+ "ssltruststorepassword",
"subscribekey",
- "certresourcepassword",
- "clientsecretcredential",
- "keystorepassword",
- "oauthclientid",
- "apikey",
- "keystorePassword",
- "clientsecret",
- "tokencredential",
- "blobstoragesharedkeycredential",
- "kerberosauthticket",
- "proxypassword",
- "queueownerawsaccountid",
+ "systemid",
"token",
- "proxyauthpassword",
- "authorizationtoken",
- "sharedaccesskey",
- "apiusername",
- "api_key",
- "sasljaasconfig",
- "httpproxypassword",
- "realm",
+ "tokencredential",
+ "truststorepassword",
"user",
- "api_secret",
- "passcode",
- "consumerkey",
- "username"
+ "userauthenticationcredentials",
+ "username",
+ "userpassword",
+ "verificationcode",
+ "webhookverifytoken",
+ "zookeeperpassword"
]
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan-core/model/TopologyDefinition.ts b/karavan-app/src/main/webui/src/karavan-core/model/TopologyDefinition.ts
index 3b5b07f7..03f4fbe1 100644
--- a/karavan-app/src/main/webui/src/karavan-core/model/TopologyDefinition.ts
+++ b/karavan-app/src/main/webui/src/karavan-core/model/TopologyDefinition.ts
@@ -15,8 +15,8 @@
* limitations under the License.
*/
-import { CamelElement } from './IntegrationDefinition';
-import { FromDefinition, RestDefinition, RouteConfigurationDefinition, RouteDefinition } from './CamelDefinition';
+import {CamelElement} from './IntegrationDefinition';
+import {FromDefinition, RestDefinition, RouteConfigurationDefinition, RouteDefinition} from './CamelDefinition';
export class TopologyRestNode {
path: string;
(camel-karavan) 13/33: Front-end Shared Icons for 4.18.0
Posted by ma...@apache.org.
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 38c0258a01996b25a2a5b12fdba97e14e14a5d8d
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:27:49 2026 -0500
Front-end Shared Icons for 4.18.0
---
.../webui/src/karavan/shared/icons/application.svg | 1 +
.../main/webui/src/karavan/shared/icons/apps.svg | 72 ++++++++
.../webui/src/karavan/shared/icons/asyncapi.svg | 183 ---------------------
.../main/webui/src/karavan/shared/icons/groovy.svg | 72 +++++++-
.../main/webui/src/karavan/shared/icons/jib.png | Bin 0 -> 42246 bytes
.../webui/src/karavan/shared/icons/jkube-logo.svg | 38 +++++
.../main/webui/src/karavan/shared/icons/jkube.svg | 41 +++++
.../webui/src/karavan/shared/icons/json-schema.svg | 28 ----
.../main/webui/src/karavan/shared/icons/logout.svg | 53 ++++++
.../webui/src/karavan/shared/icons/settings.svg | 28 ++++
10 files changed, 303 insertions(+), 213 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/application.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/application.svg
new file mode 100644
index 00000000..a8358820
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/application.svg
@@ -0,0 +1 @@
+<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><defs><style>.cls-1{fill:none;}</style></defs><title>application</title><path d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z" transform="translate(0 0)"/><path d="M26,12v4H22V12h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V12a2,2,0,0,0-2-2Z" transform="translate(0 0)"/><path d="M26,22v4H22V22h4m0-2H22a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z" [...]
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/apps.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/apps.svg
new file mode 100644
index 00000000..c6e6f8ea
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/apps.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ id="Layer_1"
+ data-name="Layer 1"
+ width="28"
+ height="28"
+ viewBox="0 0 28 28"
+ version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+>
+ <defs
+ id="defs1">
+ <style
+ id="style1">
+ .cls-1 {
+ fill: none;
+ }
+ </style>
+ </defs>
+ <path
+ d="m 28,20 h -8 v 8 h 8 z"
+ id="path18"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="m 26,22 v 4 h -4 v -4 z"
+ id="path17"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="m 18,20 h -8 v 8 h 8 z"
+ id="path16"
+ style="fill:#f69923;fill-opacity:1" />
+ <path
+ d="m 16,22 v 4 h -4 v -4 z"
+ id="path15"
+ style="fill:#f69923;fill-opacity:1" />
+ <path
+ d="M 8,20 H 0 v 8 h 8 z"
+ id="path14"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="m 6,22 v 4 H 2 v -4 z"
+ id="path13"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ id="path12"
+ d="m 20,10 v 8 h 8 v -8 z m 2,2 h 4 v 4 h -4 z"
+ style="fill:#f69923;fill-opacity:1" />
+ <path
+ id="path10"
+ d="m 10,10 v 8 h 8 v -8 z m 2,2 h 4 v 4 h -4 z"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="M 8,10 H 0 v 8 h 8 z"
+ id="path8"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="m 6,12 v 4 H 2 v -4 z"
+ id="path7"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ id="path6"
+ d="m 20,0 v 8 h 8 V 0 Z m 2,2 h 4 v 4 h -4 z"
+ style="fill:#f69923;fill-opacity:1" />
+ <path
+ id="path4"
+ d="m 10,0 v 8 h 8 V 0 Z m 2,2 h 4 v 4 h -4 z"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ id="path2"
+ d="M 0,0 V 8 H 8 V 0 Z M 2,2 H 6 V 6 H 2 Z"
+ style="fill:#4bb9ec;fill-opacity:1" />
+</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/asyncapi.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/asyncapi.svg
deleted file mode 100644
index 4c833ddc..00000000
--- a/karavan-app/src/main/webui/src/karavan/shared/icons/asyncapi.svg
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- class="h-10 mt-0.5 w-auto"
- width="36.441799"
- height="36"
- viewBox="0 0 36.441799 36"
- fill="none"
- version="1.1"
- id="svg37"
- xmlns="http://www.w3.org/2000/svg">
- <defs
- id="defs22">
- <linearGradient
- id="gradient1"
- x1="33.0317"
- y1="3.3661001"
- x2="4.5736399"
- y2="32.176102"
- gradientUnits="userSpaceOnUse">
- <stop
- stop-color="#2DCCFD"
- id="stop1" />
- <stop
- offset="100%"
- stop-color="#AD20E2"
- id="stop2" />
- </linearGradient>
- <linearGradient
- id="gradient2"
- x1="33.0317"
- y1="32.631302"
- x2="4.5710001"
- y2="3.82126"
- gradientUnits="userSpaceOnUse">
- <stop
- stop-color="#A829E2"
- id="stop3" />
- <stop
- offset="5%"
- stop-color="#A829E2"
- stop-opacity="84%"
- id="stop4" />
- <stop
- offset="11%"
- stop-color="#A829E2"
- stop-opacity="67%"
- id="stop5" />
- <stop
- offset="18%"
- stop-color="#A829E2"
- stop-opacity="51%"
- id="stop6" />
- <stop
- offset="25%"
- stop-color="#A829E2"
- stop-opacity="38%"
- id="stop7" />
- <stop
- offset="33%"
- stop-color="#A829E2"
- stop-opacity="28%"
- id="stop8" />
- <stop
- offset="43%"
- stop-color="#A829E2"
- stop-opacity="20%"
- id="stop9" />
- <stop
- offset="54%"
- stop-color="#A829E2"
- stop-opacity="14%"
- id="stop10" />
- <stop
- offset="68%"
- stop-color="#A829E2"
- stop-opacity="11%"
- id="stop11" />
- <stop
- offset="100%"
- stop-color="#A829E2"
- stop-opacity="10%"
- id="stop12" />
- </linearGradient>
- <linearGradient
- id="gradient3"
- x1="3.4100499"
- y1="32.631302"
- x2="31.8682"
- y2="3.82129"
- gradientUnits="userSpaceOnUse">
- <stop
- stop-color="#E50E99"
- id="stop13" />
- <stop
- offset="100%"
- stop-color="#A829E2"
- stop-opacity="10%"
- id="stop14" />
- </linearGradient>
- <linearGradient
- id="gradient4"
- x1="33.0317"
- y1="3.36871"
- x2="4.5709701"
- y2="32.176102"
- gradientUnits="userSpaceOnUse">
- <stop
- stop-color="#21D4FD"
- id="stop15" />
- <stop
- offset="3%"
- stop-color="#27CDFC"
- stop-opacity="96%"
- id="stop16" />
- <stop
- offset="23%"
- stop-color="#4E9CF4"
- stop-opacity="70%"
- id="stop17" />
- <stop
- offset="43%"
- stop-color="#6E73EE"
- stop-opacity="49%"
- id="stop18" />
- <stop
- offset="61%"
- stop-color="#8753E9"
- stop-opacity="32%"
- id="stop19" />
- <stop
- offset="77%"
- stop-color="#993CE5"
- stop-opacity="20%"
- id="stop20" />
- <stop
- offset="90%"
- stop-color="#A42EE3"
- stop-opacity="13%"
- id="stop21" />
- <stop
- offset="100%"
- stop-color="#A829E2"
- stop-opacity="10%"
- id="stop22" />
- </linearGradient>
- </defs>
- <path
- d="M 27.8228,0 H 8.61905 C 3.85888,0 0,3.8121 0,8.51456 V 27.4854 C 0,32.1879 3.85888,36 8.61905,36 H 27.8228 c 4.7601,0 8.619,-3.8121 8.619,-8.5146 V 8.51456 C 36.4418,3.8121 32.5829,0 27.8228,0 Z"
- fill="url(#gradient1)"
- id="path30"
- style="fill:url(#gradient1)" />
- <path
- d="M 27.8228,0 H 8.61905 C 3.85888,0 0,3.8121 0,8.51456 V 27.4854 C 0,32.1879 3.85888,36 8.61905,36 H 27.8228 c 4.7601,0 8.619,-3.8121 8.619,-8.5146 V 8.51456 C 36.4418,3.8121 32.5829,0 27.8228,0 Z"
- fill="url(#gradient2)"
- id="path31"
- style="fill:url(#gradient2)" />
- <path
- d="M 27.8228,0 H 8.61905 C 3.85888,0 0,3.8121 0,8.51456 V 27.4854 C 0,32.1879 3.85888,36 8.61905,36 H 27.8228 c 4.7601,0 8.619,-3.8121 8.619,-8.5146 V 8.51456 C 36.4418,3.8121 32.5829,0 27.8228,0 Z"
- fill="url(#gradient3)"
- id="path32"
- style="fill:url(#gradient3)" />
- <path
- d="M 27.8228,0 H 8.61905 C 3.85888,0 0,3.8121 0,8.51456 V 27.4854 C 0,32.1879 3.85888,36 8.61905,36 H 27.8228 c 4.7601,0 8.619,-3.8121 8.619,-8.5146 V 8.51456 C 36.4418,3.8121 32.5829,0 27.8228,0 Z"
- fill="url(#gradient4)"
- id="path33"
- style="fill:url(#gradient4)" />
- <path
- d="m 11.7645,14.1988 -1.0846,1.4766 8.4709,6.0736 0.0582,0.0418 1.0846,-1.4766 -8.4709,-6.0736 z"
- fill="#ffffff"
- id="path34" />
- <path
- d="m 17.2989,14.2406 -0.0582,-0.0418 -1.0846,1.4766 8.4709,6.0736 0.0582,0.0418 1.0846,-1.4766 z"
- fill="#ffffff"
- id="path35" />
- <path
- d="m 18.2275,6.64075 c -4.5926,0 -8.32802,2.81989 -8.32802,6.28535 v 0.0705 h 1.85182 v -0.0705 c 0,-2.4593 2.9101,-4.46118 6.4815,-4.46118 3.5714,0 6.4815,2.00188 6.4815,4.46118 v 0.0705 h 1.8518 V 12.9261 C 26.5556,9.46064 22.8201,6.64075 18.2275,6.64075 Z"
- fill="#ffffff"
- id="path36" />
- <path
- d="m 24.6958,23.0714 c 0,2.4592 -2.9101,4.4611 -6.4842,4.4611 -3.574,0 -6.4815,-2.0019 -6.4815,-4.4611 V 23.0008 H 9.8783 v 0.0706 c 0,3.4654 3.7354,6.2853 8.328,6.2853 4.5926,0 8.3281,-2.8199 8.3281,-6.2853 v -0.0706 h -1.8519 z"
- fill="#ffffff"
- id="path37" />
-</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/groovy.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/groovy.svg
index 34bd134f..86dd110c 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/icons/groovy.svg
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/groovy.svg
@@ -1,2 +1,70 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
-<svg width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><title>file_type_groovy</title><path d="M7.453,22.855c0-.037.494-.849,1.1-1.805A6.891,6.891,0,0,0,9.5,19.261a1.454,1.454,0,0,0-.6.111c-.764.266-.92.2-1.491-.67-.617-.937-.639-1.034-.317-1.389.21-.232.2-.286-.147-.631a1.422,1.422,0,0,1-.377-.516,17.664,17.664,0,0,0-3.647-1.5A4.173,4.173,0,0,1,2,14.267a21.111,21.111,0,0,1,2.378-.019l2.378.048.232-.366c.981-1.547,2.463-2.945,3.122-2.945a1.333,1.333,0,0, [...]
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+
+<svg
+ width="700"
+ height="346.11191"
+ viewBox="0 0 28 13.844476"
+ version="1.1"
+ id="svg5"
+ sodipodi:docname="groovy.svg"
+ inkscape:version="1.4.2 (ebf0e940, 2025-05-08)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <defs
+ id="defs5" />
+ <sodipodi:namedview
+ id="namedview5"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="0.52"
+ inkscape:cx="657.69231"
+ inkscape:cy="451.92308"
+ inkscape:window-width="1656"
+ inkscape:window-height="1051"
+ inkscape:window-x="2632"
+ inkscape:window-y="1478"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg5" />
+ <title
+ id="title1">file_type_groovy</title>
+ <path
+ d="m 5.4529999,13.777476 c 0,-0.037 0.494,-0.849 1.1,-1.805 a 6.891,6.891 0 0 0 0.947,-1.789 1.454,1.454 0 0 0 -0.6,0.111 c -0.764,0.266 -0.92,0.2 -1.491,-0.6700002 -0.617,-0.937 -0.639,-1.034 -0.317,-1.389 0.21,-0.232 0.2,-0.286 -0.147,-0.631 a 1.422,1.422 0 0 1 -0.377,-0.516 17.664,17.664 0 0 0 -3.64699998,-1.5 A 4.173,4.173 0 0 1 0,5.1894758 a 21.111,21.111 0 0 1 2.3779999,-0.019 l 2.378,0.048 0.232,-0.366 c 0.981,-1.547 2.463,-2.945 3.122,-2.945 a 1.333,1.333 0 0 1 0.619,0.291 c [...]
+ style="fill:#333333"
+ id="path1" />
+ <path
+ d="m 12.5,5.0314758 a 0.5,0.5 0 0 1 -0.115,-0.1 0.511,0.511 0 0 0 -0.49,-0.174 0.335,0.335 0 0 1 -0.15,0.012 c -0.065,-0.013 -0.089,-0.052 -0.07,-0.12 a 9.59,9.59 0 0 1 0.548,-1.016 c 0.711,-1.235 1.666,-2.79200001 1.772,-2.88699999 0.012,-0.011 0.012,-0.011 0.024,0 0.063,0.056 0.432,0.62599999 0.937,1.44399999 0.682,1.107 1.25,2.081 1.25,2.145 0,0.039 -0.06,0.063 -0.186,0.073 a 1.193,1.193 0 0 0 -0.587,0.3 1.243,1.243 0 0 1 -0.226,0.153 0.166,0.166 0 0 1 -0.1,0.024 0.15,0.15 0 0 1 [...]
+ style="fill:#6398aa"
+ id="path2" />
+ <path
+ d="m 4.2519999,6.3924758 a 22.778,22.778 0 0 1 -2.3,-0.909 c -0.031,-0.019 -0.034,-0.022 -0.025,-0.028 a 5.357,5.357 0 0 1 1.14,-0.042 c 0.23,0.006 1.619,0.052 1.621,0.054 0.002,0.002 -0.3,0.88 -0.321,0.93 -0.01,0.025 -0.03,0.025 -0.115,-0.005 z"
+ style="fill:#6398aa"
+ id="path3" />
+ <path
+ d="M 23.177,6.6014758 A 3.659,3.659 0 0 1 23,5.7164758 c 0,-0.079 0.009,-0.111 0.044,-0.143 0.081,-0.075 0.245,-0.1 0.7,-0.114 0.228,-0.006 1.281,-0.007 2.025,0 h 0.521 l -1.255,0.47 c -1.144,0.429 -1.81,0.677 -1.834,0.683 -0.006,0 -0.012,0 -0.018,-0.014 v 0 z"
+ style="fill:#6398aa"
+ id="path4" />
+ <path
+ d="m 6.5059999,12.994476 a 8.284,8.284 0 0 1 0.527,-0.929 7.528,7.528 0 0 1 1.827,-2.4190003 4.138,4.138 0 0 0 0.9690002,-0.8859999 L 10,8.5494758 l 0.225,0.221 a 1.325,1.325 0 0 0 1.062,0.5 c 0.526,0 1.1,-0.291 1.1,-0.562 0,-0.061 0.044,-0.124 0.086,-0.124 a 1.609,1.609 0 0 1 0.226,0.069 2.089,2.089 0 0 0 0.666,0.147 1.628,1.628 0 0 0 0.609,-0.073 2.357,2.357 0 0 0 0.711,-0.378 c 0.187,-0.125 0.347,-0.227 0.354,-0.227 0.007,0 0.143,0.078 0.3,0.174 a 4.62,4.62 0 0 0 0.422,0.231 1.85 [...]
+ style="fill:#6398aa"
+ id="path5" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:title>file_type_groovy</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/jib.png b/karavan-app/src/main/webui/src/karavan/shared/icons/jib.png
new file mode 100644
index 00000000..92abdd7b
Binary files /dev/null and b/karavan-app/src/main/webui/src/karavan/shared/icons/jib.png differ
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/jkube-logo.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/jkube-logo.svg
new file mode 100644
index 00000000..e528a84b
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/jkube-logo.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
+ viewBox="0 0 291.2 88.5" style="enable-background:new 0 0 291.2 88.5;" xml:space="preserve">
+<style type="text/css">
+ .jkube-icon-outer{fill-rule:evenodd;clip-rule:evenodd;}
+ .jkube-icon-inner, .jkube-icon-outer{fill:#0A4E9B;}
+ .jkube-text{fill: #000000;}
+</style>
+ <g>
+ <path class="jkube-text" d="M100.2,23.1h21.7v28.1c0,3-0.8,5.8-2.3,8.4c-1.5,2.6-3.6,4.6-6.2,6.1c-2.6,1.5-5.5,2.2-8.5,2.2c-3.1,0-5.9-0.7-8.5-2.2
+ c-2.6-1.5-4.7-3.5-6.2-6.1c-1.5-2.6-2.3-5.4-2.3-8.4h11.2c0,1.5,0.6,2.8,1.7,3.9s2.5,1.6,4.1,1.6c1.6,0,2.9-0.5,4.1-1.6
+ c1.1-1.1,1.7-2.4,1.7-3.9v-17h-10.5V23.1z"/>
+ <path class="jkube-text" d="M163.3,23l-18.3,19.7l18,24.3H149l-11.8-16l0,0v15.7h-11.2V23h11.2v11.6L147.9,23H163.3z"/>
+ <path class="jkube-text" d="M198,35.1c-0.3,2.6-0.4,4.9-0.4,8.2v17c0,3.8,0.1,6,0.4,8.2H187v-2.4c0-0.3,0-1.1,0.1-1.5c-3.6,3.4-6.8,4.7-11.4,4.7
+ c-3.7,0-6.6-1-8.7-3.1c-2.2-2.2-3.1-4.9-3.1-9.2V43.3c0-3.2-0.2-5.9-0.4-8.2h11.4c-0.3,2.6-0.4,4.9-0.4,8.2v11.3
+ c0,2.3,0.2,3.2,0.9,4.1c0.8,1,2,1.5,3.6,1.5c3,0,6.1-2.1,8.2-5.7V43.3c0-3.1-0.1-5.4-0.4-8.2H198z"/>
+ <path class="jkube-text" d="M203.7,68.6c0.3-2.6,0.4-4.9,0.4-8.6V31.5c0-4-0.1-6-0.4-8.6h11.1c-0.3,2.6-0.4,4.6-0.4,8.6v4.6c0,0.8,0,1.3-0.1,2.1
+ c3.2-2.9,6.8-4.1,11.3-4.1c10,0,15.8,6.4,15.8,17.2c0,5.9-1.7,10.6-4.9,13.9c-2.9,2.9-6.6,4.3-11.4,4.3c-4.6,0-7.2-0.9-10.8-3.9
+ c0,0.2,0.1,0.9,0.1,1.2v1.8H203.7z M223.2,42.4c-5,0-8.6,3.8-8.6,9.2c0,5.4,3.6,9.6,8.3,9.6c4.8,0,8-3.9,8-9.7
+ C230.9,45.8,228,42.4,223.2,42.4z"/>
+ <path class="jkube-text" d="M254.6,54.9c0.5,4.4,3.1,6.8,7.5,6.8c2.2,0,4.1-0.7,5.5-2c0.8-0.8,1.2-1.4,1.6-2.8l9.6,2.7c-1.3,2.9-2.1,4.1-3.6,5.7
+ c-3.1,3.1-7.5,4.7-13,4.7c-5.4,0-9.6-1.5-12.7-4.7c-3.2-3.3-5-8-5-13.4c0-10.9,7-18.1,17.5-18.1c8.6,0,14.6,4.7,16.5,12.9
+ c0.4,1.8,0.7,4.1,0.8,7.2c0,0.2,0,0.5,0.1,1.1H254.6z M268.9,47.3c-0.8-3.5-3.1-5.4-6.9-5.4c-3.9,0-6.3,1.8-7.2,5.4H268.9z"/>
+</g>
+ <g>
+ <path class="jkube-icon-outer" d="M9.3,59.8c0.9,0.8,2.5,1.5,3.5,2.1l21.6,12.5c1,0.6,2.5,1.6,3.6,2v-6.3L14.8,56.6l0-26.8
+ c-1.6-0.4-4.2-2.7-5.6-2.9L9.3,59.8z"/>
+ <path class="jkube-icon-outer" d="M69,59.8l-0.1-33c-1.5,0.5-3.9,2.6-5.5,3l0,26.9c-0.8,0.8-4.9,2.9-6.1,3.6L45,67.3c-5.1,3-4.8,2-4.8,4.9
+ l0.1,4.2L69,59.8z"/>
+ <path class="jkube-icon-outer" d="M15.9,28c1.9-0.7,4.3-2.4,6-3.4c1.9-1.1,3.8-2.2,5.7-3.3c2.1-1.2,3.7-2.2,5.8-3.4c1.7-0.9,4.1-2.6,5.7-3.2
+ l14.3,8.2c2.4,1.4,4.7,2.7,7.2,4.1c2.1,1.2,1.6,1,3.7-0.1c1-0.6,2.7-1.4,3.4-2.1C67,24.1,39.4,8.3,39.2,8.3
+ C39,8.3,11.4,24,10.5,24.9L15.9,28z"/>
+</g>
+ <path class="jkube-icon-inner" d="M39.2,17.8L17.8,30.1v24.7l21.4,12.3l21.4-12.3V30.1L39.2,17.8z M46.6,46.8c0,1.8-0.5,3.6-1.4,5.1
+ c-0.9,1.6-2.2,2.8-3.8,3.7c-1.6,0.9-3.3,1.4-5.2,1.4c-1.9,0-3.6-0.5-5.2-1.4c-1.6-0.9-2.9-2.2-3.8-3.7c-0.9-1.6-1.4-3.3-1.4-5.1h6.8
+ c0,0.9,0.3,1.7,1,2.4s1.5,1,2.5,1c1,0,1.8-0.3,2.5-1c0.7-0.7,1-1.5,1-2.4V36.5h-6.4v-6.8h13.3V46.8z"/>
+</svg>
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/jkube.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/jkube.svg
new file mode 100644
index 00000000..fdc14d1c
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/jkube.svg
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 59.799999 68.099998"
+ xml:space="preserve"
+ width="59.799999"
+ height="68.099998"
+ xmlns="http://www.w3.org/2000/svg">
+ <defs
+ id="defs4" />
+<style
+ type="text/css"
+ id="style1">
+ .jkube-icon-outer{fill-rule:evenodd;clip-rule:evenodd;}
+ .jkube-icon-inner, .jkube-icon-outer{fill:#0A4E9B;}
+ .jkube-text{fill: #000000;}
+</style>
+ <g
+ id="g3"
+ transform="translate(-9.2,-8.3)">
+ <path
+ class="jkube-icon-outer"
+ d="m 9.3,59.8 c 0.9,0.8 2.5,1.5 3.5,2.1 l 21.6,12.5 c 1,0.6 2.5,1.6 3.6,2 V 70.1 L 14.8,56.6 V 29.8 C 13.2,29.4 10.6,27.1 9.2,26.9 Z"
+ id="path1" />
+ <path
+ class="jkube-icon-outer"
+ d="m 69,59.8 -0.1,-33 c -1.5,0.5 -3.9,2.6 -5.5,3 v 26.9 c -0.8,0.8 -4.9,2.9 -6.1,3.6 l -12.3,7 c -5.1,3 -4.8,2 -4.8,4.9 l 0.1,4.2 z"
+ id="path2" />
+ <path
+ class="jkube-icon-outer"
+ d="m 15.9,28 c 1.9,-0.7 4.3,-2.4 6,-3.4 1.9,-1.1 3.8,-2.2 5.7,-3.3 2.1,-1.2 3.7,-2.2 5.8,-3.4 1.7,-0.9 4.1,-2.6 5.7,-3.2 l 14.3,8.2 c 2.4,1.4 4.7,2.7 7.2,4.1 2.1,1.2 1.6,1 3.7,-0.1 1,-0.6 2.7,-1.4 3.4,-2.1 C 67,24.1 39.4,8.3 39.2,8.3 39,8.3 11.4,24 10.5,24.9 Z"
+ id="path3" />
+</g>
+ <path
+ class="jkube-icon-inner"
+ d="M 30,9.5 8.6,21.8 V 46.5 L 30,58.8 51.4,46.5 V 21.8 Z m 7.4,29 c 0,1.8 -0.5,3.6 -1.4,5.1 -0.9,1.6 -2.2,2.8 -3.8,3.7 -1.6,0.9 -3.3,1.4 -5.2,1.4 -1.9,0 -3.6,-0.5 -5.2,-1.4 C 20.2,46.4 18.9,45.1 18,43.6 17.1,42 16.6,40.3 16.6,38.5 h 6.8 c 0,0.9 0.3,1.7 1,2.4 0.7,0.7 1.5,1 2.5,1 1,0 1.8,-0.3 2.5,-1 0.7,-0.7 1,-1.5 1,-2.4 V 28.2 H 24 v -6.8 h 13.3 v 17.1 z"
+ id="path4" />
+</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/json-schema.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/json-schema.svg
deleted file mode 100644
index 5f970a88..00000000
--- a/karavan-app/src/main/webui/src/karavan/shared/icons/json-schema.svg
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- width="66.294701"
- height="56.746601"
- viewBox="0 0 66.294701 56.746601"
- fill="none"
- version="1.1"
- id="svg14"
- xmlns="http://www.w3.org/2000/svg">
- <defs
- id="defs14" />
- <path
- d="m 27.1872,51.3759 c -1.0836,-1.0178 -0.9262,-2.7714 0.4028,-4.4922 0.9848,-1.274 5.0998,-5.4476 8.069,-8.1861 l 1.2008,-1.1057 -1.9111,-4.0967 C 32.807,28.9006 32.818,28.8127 35.6443,28.4978 l 1.556,-0.172 1.739,2.6286 c 0.9555,1.4461 1.8781,2.6287 2.0429,2.6287 0.1647,0 1.8818,-1.3766 3.8111,-3.057 3.3499,-2.9216 3.5586,-3.0497 4.6935,-2.8959 0.6847,0.0951 1.2924,0.0366 1.4352,-0.1355 0.3368,-0.4027 1.3033,0.194 1.3033,0.8054 0,0.2527 -0.4832,0.8897 -1.069,1.4169 -2.4053,2.16 -7 [...]
- fill="#4bb9ec"
- id="path1" />
- <path
- d="M 24.1959,27.458 C 24.1813,27.4361 24.163,27.4141 24.152,27.3958 18.5359,19.0119 14.4648,17.5365 14.6112,17.445 c 2.1345,-1.3729 6.1397,-0.0256 8.6146,2.1747 0.0292,0.0256 0.0585,0.0586 0.0915,0.0879 0.5931,0.5052 0.7285,0.6882 1.4388,1.479 0.1281,0 2.8666,-4.5507 2.8849,-4.58 5.5136,-8.69503 11.2798,-12.37075 14.626,-12.36343 1.5962,0 1.8342,0.55649 1.8342,0.55649 -5.4221,2.83001 -10.0094,7.87494 -14.7468,17.16674 -1.3217,2.6616 -3.5476,6.9561 -3.7087,7.249 -0.2416,0.4393 -0.281 [...]
- fill="#4bb9ec"
- id="path2" />
- <path
- d="m 5.84307,27.9084 c 1.50104,-0.3698 2.65428,-0.8933 3.4707,-1.5743 0.81273,-0.681 1.36923,-1.4937 1.67313,-2.4383 0.3039,-0.9445 0.454,-1.9953 0.454,-3.1485 v -8.8671 c 0,-1.728 0.205,-3.1522 0.6114,-4.26883 C 12.4586,6.49475 13.1542,5.671 14.1354,5.14015 15.1166,4.60929 16.4675,4.34203 18.1809,4.34203 V 0 C 16.0099,0 14.183,0.23797 12.7039,0.710248 11.2249,1.18253 10.046,1.90742 9.15635,2.88126 8.26671,3.85511 7.62968,5.08889 7.23794,6.58261 6.84621,8.07633 6.65217,9.84097 6.652 [...]
- fill="#4bb9ec"
- id="path3" />
- <path
- d="m 60.4516,27.9084 c -1.5011,-0.3698 -2.6543,-0.8933 -3.4707,-1.5743 -0.8128,-0.681 -1.3693,-1.4937 -1.6731,-2.4383 -0.3039,-0.9445 -0.454,-1.9953 -0.454,-3.1485 v -8.8671 c 0,-1.728 -0.205,-3.1522 -0.6114,-4.26883 C 53.836,6.49475 53.1404,5.671 52.1593,5.14015 51.1781,4.60929 49.8272,4.34203 48.1138,4.34203 V 0 c 2.171,0 3.9979,0.23797 5.4769,0.710248 1.4791,0.472282 2.658,1.197172 3.5476,2.171012 0.886,0.97385 1.5267,2.20763 1.9184,3.70135 0.3918,1.49372 0.5858,3.25836 0.5858,5. [...]
- fill="#4bb9ec"
- id="path4" />
-</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/logout.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/logout.svg
new file mode 100644
index 00000000..b631979b
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/logout.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ id="icon"
+ width="32"
+ height="32"
+ viewBox="0 0 32 32"
+ version="1.1"
+ sodipodi:docname="logout.svg"
+ inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview1"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="9.1923881"
+ inkscape:cx="39.21723"
+ inkscape:cy="20.070954"
+ inkscape:window-width="2560"
+ inkscape:window-height="1382"
+ inkscape:window-x="0"
+ inkscape:window-y="30"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="icon" />
+ <defs
+ id="defs1">
+ <style
+ id="style1">.cls-1{fill:none;}</style>
+ </defs>
+ <title
+ id="title1">logout</title>
+ <path
+ d="M6,30H18a2.0023,2.0023,0,0,0,2-2V25H18v3H6V4H18V7h2V4a2.0023,2.0023,0,0,0-2-2H6A2.0023,2.0023,0,0,0,4,4V28A2.0023,2.0023,0,0,0,6,30Z"
+ id="path1"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <polygon
+ points="20.586 20.586 24.172 17 10 17 10 15 24.172 15 20.586 11.414 22 10 28 16 22 22 20.586 20.586"
+ id="polygon1"
+ style="fill:#f69923;fill-opacity:1" />
+ <rect
+ id="_Transparent_Rectangle_"
+ data-name="<Transparent Rectangle>"
+ class="cls-1"
+ width="32"
+ height="32" />
+</svg>
diff --git a/karavan-app/src/main/webui/src/karavan/shared/icons/settings.svg b/karavan-app/src/main/webui/src/karavan/shared/icons/settings.svg
new file mode 100644
index 00000000..69cf06b1
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/icons/settings.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ id="icon"
+ viewBox="0 0 27.184721 27.920734"
+ version="1.1"
+ width="27.184721"
+ height="27.920734"
+ xmlns="http://www.w3.org/2000/svg"
+>
+ <defs
+ id="defs1">
+ <style
+ id="style1">.cls-1{fill:none;}</style>
+ </defs>
+ <title
+ id="title1">settings</title>
+ <path
+ d="m 24.587162,14.720367 c 0,-0.25 0,-0.5 0,-0.76 0,-0.26 0,-0.51 0,-0.77 l 1.92,-1.68 a 2,2 0 0 0 0.38,-2.5499999 l -2.36,-4 a 2,2 0 0 0 -1.73,-1 2,2 0 0 0 -0.64,0.1 l -2.43,0.82 a 11.35,11.35 0 0 0 -1.31,-0.75 l -0.51,-2.52 a 2,2 0 0 0 -2,-1.60999995005 h -4.68 A 2,2 0 0 0 9.2271623,1.6103671 l -0.51,2.52 a 11.48,11.48 0 0 0 -1.32,0.75 l -2.38,-0.86 a 2,2 0 0 0 -0.64,-0.06 2,2 0 0 0 -1.73,1 l -2.35999998,4 a 2,2 0 0 0 0.41,2.5099999 l 1.88999998,1.73 c 0,0.25 0,0.5 0,0.76 0,0.26 0 [...]
+ id="path1"
+ style="fill:#4bb9ec;fill-opacity:1" />
+ <path
+ d="m 13.587162,19.960367 a 6,6 0 1 1 6,-6 5.94,5.94 0 0 1 -6,6 z m 0,-9.9999999 a 3.91,3.91 0 0 0 -3.9999997,3.9999999 3.91,3.91 0 0 0 3.9999997,4 3.91,3.91 0 0 0 4,-4 3.91,3.91 0 0 0 -4,-3.9999999 z"
+ id="path2"
+ style="fill:#f69923;fill-opacity:1" />
+ <metadata
+ id="metadata2">
+ </metadata>
+</svg>
(camel-karavan) 09/33: Front-end Stores for 4.18.0
Posted by ma...@apache.org.
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 fa98128d1b1b5921b6f5314a06e808a727f5d812
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:23:34 2026 -0500
Front-end Stores for 4.18.0
---
.../src/karavan/stores/ContainerStatusesStore.ts | 48 ++++++++++++
.../src/main/webui/src/karavan/stores/LogStore.ts | 58 ++++++++++++++
.../main/webui/src/karavan/stores/SettingsStore.ts | 88 ++++++++++++++++++++++
.../main/webui/src/karavan/stores/TopologyStore.ts | 63 ++++++++++++++++
4 files changed, 257 insertions(+)
diff --git a/karavan-app/src/main/webui/src/karavan/stores/ContainerStatusesStore.ts b/karavan-app/src/main/webui/src/karavan/stores/ContainerStatusesStore.ts
new file mode 100644
index 00000000..8a91f5bd
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/stores/ContainerStatusesStore.ts
@@ -0,0 +1,48 @@
+/*
+ * 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 {KaravanApi} from "@api/KaravanApi";
+import {create} from "zustand";
+import {ContainerStatus} from "@models/ProjectModels";
+import isEqual from "lodash/isEqual";
+
+type ContainerStatusesState = {
+ containers: ContainerStatus[];
+ fetchContainers: () => Promise<void>;
+ findContainers: (projectId: string) => ContainerStatus[];
+}
+
+export const useContainerStatusesStore = create<ContainerStatusesState>((set, get) => ({
+ containers: [],
+ fetchContainers: async (): Promise<void> => {
+ const currentContainers = get().containers;
+ await new Promise<ContainerStatus[]>((resolve, reject) => {
+ KaravanApi.getAllContainerStatuses((containers: ContainerStatus[]) => {
+ resolve(containers);
+ });
+ })
+ .then((containers) => {
+ if (!isEqual(currentContainers, containers)) {
+ set({containers: containers});
+ }
+ });
+ },
+ findContainers: (projectId: string) => {
+ const state = get();
+ return state.containers.filter(c => c.projectId === projectId);
+ },
+}))
+
diff --git a/karavan-app/src/main/webui/src/karavan/stores/LogStore.ts b/karavan-app/src/main/webui/src/karavan/stores/LogStore.ts
new file mode 100644
index 00000000..65b7d030
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/stores/LogStore.ts
@@ -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 {ProjectEventBus} from "@bus/ProjectEventBus";
+import {unstable_batchedUpdates} from "react-dom";
+import {createWithEqualityFn} from "zustand/traditional";
+import {shallow} from "zustand/shallow";
+
+const MAX_LOG_LINES = 1000;
+
+interface LogState {
+ podName?: string,
+ data: string[];
+ setData: (data: string[]) => void;
+}
+
+export const useLogStore = createWithEqualityFn<LogState>((set) => ({
+ podName: undefined,
+ data: [],
+ setData: (data: string[]) => {
+ set({data: data})
+ }
+}), shallow)
+
+const sub = ProjectEventBus.onLog()?.subscribe((result: ["add" | "set", string]) => {
+ if (result[0] === 'add') {
+ unstable_batchedUpdates(() => {
+ useLogStore.setState((state: LogState) => {
+ const newEntry = result[1]?.length !== 0 ? result[1] : "\n";
+
+ // Combine, then slice from the end (negative index)
+ const newData = [...state.data, newEntry];
+ const trimmedData = newData.length > MAX_LOG_LINES
+ ? newData.slice(-MAX_LOG_LINES)
+ : newData;
+
+ return { data: trimmedData };
+ })
+ })
+ } else if (result[0] === 'set') {
+ unstable_batchedUpdates(() => {
+ useLogStore.setState({data: [result[1]]});
+ })
+ }
+});
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/stores/SettingsStore.ts b/karavan-app/src/main/webui/src/karavan/stores/SettingsStore.ts
new file mode 100644
index 00000000..33af15fb
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/stores/SettingsStore.ts
@@ -0,0 +1,88 @@
+/*
+ * 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 {ProjectFile, ProjectType} from "@models/ProjectModels";
+import {create} from "zustand";
+import {KaravanApi} from "@api/KaravanApi";
+import isEqual from "lodash/isEqual";
+import concat from "lodash/concat";
+
+export const SettingsMenus = ['templates', 'kamelets', 'configuration'] as const;
+export type SettingsMenu = typeof SettingsMenus[number];
+
+type SettingsState = {
+ currentMenu: SettingsMenu;
+ setCurrentMenu: (currentMenu: SettingsMenu) => void;
+ selectedProjectId?: string;
+ setSelectedProjectId: (selectedProjectId?: string) => void;
+ selectedFileName?: string;
+ setSelectedFilename: (selectedFileName?: string) => void;
+}
+
+export const useSettingsStore = create<SettingsState>((set, get) => ({
+ currentMenu: SettingsMenus[0],
+ setCurrentMenu: (currentMenu: SettingsMenu) => {
+ set({ currentMenu: currentMenu });
+ },
+ setSelectedProjectId: (selectedProjectId: string) => {
+ set({ selectedProjectId: selectedProjectId });
+ },
+ setSelectedFilename: (selectedFileName: string) => {
+ set({ selectedFileName: selectedFileName });
+ },
+}))
+
+type TemplatesState = {
+ templateFiles: ProjectFile[];
+ saveTemplateFile: (file: ProjectFile) => Promise<void>;
+ fetchTemplateFiles: () => Promise<void>;
+}
+
+export const useTemplatesStore = create<TemplatesState>((set, get) => ({
+ templateFiles: [],
+ fetchTemplateFiles: async (): Promise<void> => {
+ await new Promise<ProjectFile[]>((resolve) => {
+ KaravanApi.getFiles(ProjectType.templates, resolve);
+ }).then(templates => {
+ const currentTemplateFiles = get().templateFiles;
+ if (!isEqual(currentTemplateFiles, templates)) {
+ set({ templateFiles: templates });
+ }
+ })
+ },
+ saveTemplateFile: async (file: ProjectFile) => {
+ const prevSettings = [...get().templateFiles];
+ const newTemplateFiles = concat(prevSettings.filter(f => f.name !== file.name), file)
+ set({ templateFiles: newTemplateFiles });
+
+ await new Promise<{ result: boolean; file: ProjectFile | any }>((resolve, reject) => {
+ KaravanApi.saveProjectFile(file, (result, file) => {
+ if (result) {
+ resolve({ result, file });
+ } else {
+ // Reject the promise if the API explicitly returns result: false (Application error)
+ reject(new Error("API returned failure result."));
+ }
+ });
+ }).catch(error => {
+ set({ templateFiles: prevSettings });
+ console.error(error);
+ });
+ }
+}))
+
+
+
diff --git a/karavan-app/src/main/webui/src/karavan/stores/TopologyStore.ts b/karavan-app/src/main/webui/src/karavan/stores/TopologyStore.ts
new file mode 100644
index 00000000..f7088137
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/stores/TopologyStore.ts
@@ -0,0 +1,63 @@
+/*
+ * 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 {createWithEqualityFn} from "zustand/traditional";
+
+interface TopologyState {
+ fileName?: string
+ setFileName: (fileName?: string) => void
+ showGroups: boolean
+ setShowGroups: (showGroups: boolean) => void
+ showBeans: boolean
+ setShowBeans: (showBeans: boolean) => void
+ showLegend: boolean
+ setShowLegend: (showLegend: boolean) => void
+ showStats: boolean
+ setShowStats: (showStats: boolean) => void
+}
+
+export const useTopologyStore = createWithEqualityFn<TopologyState>((set, get) => {
+ return {
+ setFileName: (fileName?: string) => {
+ set((state: TopologyState) => {
+ return {fileName: fileName};
+ });
+ },
+ showGroups: false,
+ setShowGroups: (showGroups: boolean) => {
+ set({showGroups: showGroups});
+ },
+ showBeans: false,
+ setShowBeans: (showBeans: boolean) => {
+ set((state: TopologyState) => {
+ return {showBeans: showBeans};
+ });
+ },
+ showLegend: false,
+ setShowLegend: (showLegend: boolean) => {
+ set((state: TopologyState) => {
+ return {showLegend: showLegend};
+ });
+ },
+ showStats: false,
+ setShowStats: (showStats: boolean) => {
+ set((state: TopologyState) => {
+ return {showStats: showStats};
+ });
+ },
+ }
+});
(camel-karavan) 33/33: 4.18.0
Posted by ma...@apache.org.
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 2b90ed4b61cdf0e08f82b8649341fbe88f0b4309
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 19:08:38 2026 -0500
4.18.0
---
.github/DISCUSSION_TEMPLATE/q-a.yml | 2 +-
.github/ISSUE_TEMPLATE/bug_report.yml | 2 +-
docs/VSCODE_HOWTO.md | 4 ++--
docs/install/karavan-helm/Chart.yaml | 2 +-
docs/install/karavan-helm/values.yaml | 4 ++--
docs/install/karavan-kubernetes/deployment.yaml | 4 ++--
karavan-app/src/main/docker/Dockerfile | 2 +-
karavan-devmode/Dockerfile | 12 ++++++------
karavan-vscode/CHANGELOG.md | 7 +++++++
karavan-vscode/README.md | 4 ++--
karavan-vscode/package.json | 4 ++--
11 files changed, 27 insertions(+), 20 deletions(-)
diff --git a/.github/DISCUSSION_TEMPLATE/q-a.yml b/.github/DISCUSSION_TEMPLATE/q-a.yml
index 8b217524..84eb9067 100644
--- a/.github/DISCUSSION_TEMPLATE/q-a.yml
+++ b/.github/DISCUSSION_TEMPLATE/q-a.yml
@@ -42,4 +42,4 @@ body:
options:
- 4.8.0
- 4.10.2
- - 4.14.5
+ - 4.18.0
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 6f0d2020..93ca14e5 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -61,7 +61,7 @@ body:
- 4.7.0
- 4.8.0
- 4.10.2
- - 4.14.5
+ - 4.18.0
default: 0
validations:
required: true
diff --git a/docs/VSCODE_HOWTO.md b/docs/VSCODE_HOWTO.md
index bd78ce6c..bc4a7a26 100644
--- a/docs/VSCODE_HOWTO.md
+++ b/docs/VSCODE_HOWTO.md
@@ -16,7 +16,7 @@
* Run using CLI
```shell
- jbang -Dcamel.jbang.version=4.14.5 camel@apache/camel run $INTEGRATION.yaml --max-messages=10 --logging-level=info
+ jbang -Dcamel.jbang.version=4.18.0 camel@apache/camel run $INTEGRATION.yaml --max-messages=10 --logging-level=info
```
## Export integration to Maven project
@@ -26,5 +26,5 @@
* Export using CLI
```shell
- jbang -Dcamel.jbang.version=4.14.5 camel@apache/camel export --directory=export
+ jbang -Dcamel.jbang.version=4.18.0 camel@apache/camel export --directory=export
```
\ No newline at end of file
diff --git a/docs/install/karavan-helm/Chart.yaml b/docs/install/karavan-helm/Chart.yaml
index fcedc954..09807220 100644
--- a/docs/install/karavan-helm/Chart.yaml
+++ b/docs/install/karavan-helm/Chart.yaml
@@ -2,4 +2,4 @@ apiVersion: v2
name: karavan
version: 0.1.0
description: Chart Helm for deploy Karavan
-appVersion: "4.14.5"
\ No newline at end of file
+appVersion: "4.18.0"
\ No newline at end of file
diff --git a/docs/install/karavan-helm/values.yaml b/docs/install/karavan-helm/values.yaml
index 28135682..1b65f753 100644
--- a/docs/install/karavan-helm/values.yaml
+++ b/docs/install/karavan-helm/values.yaml
@@ -2,14 +2,14 @@ replicaCount: 1
image:
repository: ghcr.io/apache/camel-karavan
- tag: "4.14.5"
+ tag: "4.18.0"
pullPolicy: Always
env:
KARAVAN_CONTAINER_STATUS_INTERVAL: "disabled"
KARAVAN_CONTAINER_STATISTICS_INTERVAL: "disabled"
KARAVAN_CAMEL_STATUS_INTERVAL: "3s"
- KARAVAN_DEVMODE_IMAGE: "ghcr.io/apache/camel-karavan-devmode:4.14.5"
+ KARAVAN_DEVMODE_IMAGE: "ghcr.io/apache/camel-karavan-devmode:4.18.0"
service:
type: ClusterIP
diff --git a/docs/install/karavan-kubernetes/deployment.yaml b/docs/install/karavan-kubernetes/deployment.yaml
index f37d6f5e..b2aca748 100644
--- a/docs/install/karavan-kubernetes/deployment.yaml
+++ b/docs/install/karavan-kubernetes/deployment.yaml
@@ -22,7 +22,7 @@ spec:
- name: "KARAVAN_CAMEL_STATUS_INTERVAL"
value: "3s"
- name: "KARAVAN_DEVMODE_IMAGE"
- value: "ghcr.io/apache/camel-karavan-devmode:4.14.5"
+ value: "ghcr.io/apache/camel-karavan-devmode:4.18.0"
- name: "KARAVAN_GIT_REPOSITORY"
valueFrom:
secretKeyRef:
@@ -73,7 +73,7 @@ spec:
fieldRef:
apiVersion: ""
fieldPath: "metadata.namespace"
- image: "ghcr.io/apache/camel-karavan:4.14.5"
+ image: "ghcr.io/apache/camel-karavan:4.18.0"
imagePullPolicy: "Always"
name: "karavan"
ports:
diff --git a/karavan-app/src/main/docker/Dockerfile b/karavan-app/src/main/docker/Dockerfile
index 2701f60e..296121c3 100644
--- a/karavan-app/src/main/docker/Dockerfile
+++ b/karavan-app/src/main/docker/Dockerfile
@@ -19,7 +19,7 @@ LABEL "org.opencontainers.image.title"="karavan"
LABEL "org.opencontainers.image.description"="Apache Camel Karavan"
LABEL "org.opencontainers.image.url"="https://camel.apache.org"
LABEL "org.opencontainers.image.licenses"="Apache 2.0"
-LABEL "org.opencontainers.image.version"="4.14.5"
+LABEL "org.opencontainers.image.version"="4.18.0"
LABEL "org.apache.camel.karavan/type"="internal"
USER root
diff --git a/karavan-devmode/Dockerfile b/karavan-devmode/Dockerfile
index b12e21d4..1aa7c227 100644
--- a/karavan-devmode/Dockerfile
+++ b/karavan-devmode/Dockerfile
@@ -13,21 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM maven:3.9.9-eclipse-temurin-21
+FROM maven:3.9.12-eclipse-temurin-21
LABEL "org.opencontainers.image.title"="karavan-devmode"
LABEL "org.opencontainers.image.description"="Apache Camel Karavan DevMode"
LABEL "org.opencontainers.image.url"="https://camel.apache.org"
LABEL "org.opencontainers.image.licenses"="Apache 2.0"
-LABEL "org.opencontainers.image.version"="4.14.5"
+LABEL "org.opencontainers.image.version"="4.18.0"
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
-ENV JBANG_VERSION=0.132.1
-ENV CAMEL_VERSION=4.14.5
-ENV JBANG_JAVA_OPTIONS="-Dcamel.jbang.version=4.14.5 -Dcamel.jbang.kameletsVersion=4.14.5"
+ENV JBANG_VERSION=0.137.0
+ENV CAMEL_VERSION=4.18.0
+ENV JBANG_JAVA_OPTIONS="-Dcamel.jbang.version=4.18.0 -Dcamel.jbang.kameletsVersion=4.18.0"
ENV KARAVAN="/karavan"
ENV JBANG_DIR="$KARAVAN/.jbang"
ENV MAVEN_CONFIG="$KARAVAN/.m2"
@@ -55,4 +55,4 @@ RUN curl -Ls https://sh.jbang.dev | bash -s - app setup \
EXPOSE 8080
WORKDIR $CODE_DIR
-CMD ["jbang", "-Dcamel.jbang.version=4.14.5", "-Dcamel.jbang.kameletsVersion=4.14.5", "camel@apache/camel", "run", "--source-dir=/karavan/code", "--console"]
\ No newline at end of file
+CMD ["jbang", "-Dcamel.jbang.version=4.18.0", "-Dcamel.jbang.kameletsVersion=4.18.0", "camel@apache/camel", "run", "--source-dir=/karavan/code", "--console"]
\ No newline at end of file
diff --git a/karavan-vscode/CHANGELOG.md b/karavan-vscode/CHANGELOG.md
index ec4e3de9..03928ce1 100644
--- a/karavan-vscode/CHANGELOG.md
+++ b/karavan-vscode/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## 4.18.0
+0. Camel 4.18.0
+1. Kamelets 4.18.0
+3. Jkube 1.19.0
+4. JBang v0.137.1
+4. Quarkus 3.27.2
+
## 4.14.2
0. Camel 4.14.2
1. Kamelets 4.14.2
diff --git a/karavan-vscode/README.md b/karavan-vscode/README.md
index 3d6a92d6..8c7406de 100644
--- a/karavan-vscode/README.md
+++ b/karavan-vscode/README.md
@@ -72,7 +72,7 @@ Build-in catalogues:
* Run using CLI
```shell
- jbang -Dcamel.jbang.version=4.14.5 camel@apache/camel run $INTEGRATION.yaml --max-messages=10 --logging-level=info
+ jbang -Dcamel.jbang.version=4.18.0 camel@apache/camel run $INTEGRATION.yaml --max-messages=10 --logging-level=info
```
## Export integration to Maven project
@@ -82,7 +82,7 @@ Build-in catalogues:
* Export using CLI
```shell
- jbang -Dcamel.jbang.version=4.14.5 camel@apache/camel export --directory=export
+ jbang -Dcamel.jbang.version=4.18.0 camel@apache/camel export --directory=export
```
# Issues
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index a1bead14..d76898d4 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -63,7 +63,7 @@
"properties": {
"camel.version": {
"type": "string",
- "default": "4.14.5",
+ "default": "4.18.0",
"description": "Camel version",
"scope": "machine",
"order": 10
@@ -281,7 +281,7 @@
"camel.karavan.project-name=$NAME",
"camel.karavan.target=$TARGET",
"camel.jbang.gav=$GAV",
- "camel.jbang.version=4.14.5",
+ "camel.jbang.version=4.18.0",
"camel.jbang.runtime=camel-main",
"camel.jbang.dependencies=camel-console,camel-platform-http-main",
"camel.jbang.exportDir=.export",
(camel-karavan) 32/33: 4.18.0
Posted by ma...@apache.org.
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 13f72216f1a619455133df1f3daf1c7cf22eadbe
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 19:04:28 2026 -0500
4.18.0
---
.github/workflows/app.yml | 2 +-
.github/workflows/docker-devmode.yml | 2 +-
.github/workflows/vscode.yml | 2 +-
docs/install/karavan-docker/docker-compose.yaml | 2 +-
docs/install/karavan-kubernetes/kustomization.yaml | 2 +-
karavan-app/pom.xml | 2 +-
karavan-app/src/main/resources/application.properties | 2 +-
karavan-core/package-lock.json | 4 ++--
karavan-core/package.json | 2 +-
karavan-vscode/package-lock.json | 4 ++--
karavan-vscode/package.json | 2 +-
11 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/app.yml b/.github/workflows/app.yml
index d2c7fccd..2a1b8230 100644
--- a/.github/workflows/app.yml
+++ b/.github/workflows/app.yml
@@ -10,7 +10,7 @@ on:
env:
REGISTRY: ghcr.io
- TAG: 4.14.5
+ TAG: 4.18.0
jobs:
build:
diff --git a/.github/workflows/docker-devmode.yml b/.github/workflows/docker-devmode.yml
index 63f2e7a5..6ee2f402 100644
--- a/.github/workflows/docker-devmode.yml
+++ b/.github/workflows/docker-devmode.yml
@@ -9,7 +9,7 @@ on:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-devmode
- TAG: 4.14.5
+ TAG: 4.18.0
jobs:
docker:
diff --git a/.github/workflows/vscode.yml b/.github/workflows/vscode.yml
index 6de03895..428829dd 100644
--- a/.github/workflows/vscode.yml
+++ b/.github/workflows/vscode.yml
@@ -9,7 +9,7 @@ on:
branches: [ main ]
env:
- TAG: 4.14.5
+ TAG: 4.18.0
jobs:
build:
diff --git a/docs/install/karavan-docker/docker-compose.yaml b/docs/install/karavan-docker/docker-compose.yaml
index 7d60fb0f..2eb70fe1 100644
--- a/docs/install/karavan-docker/docker-compose.yaml
+++ b/docs/install/karavan-docker/docker-compose.yaml
@@ -4,7 +4,7 @@ services:
karavan:
container_name: karavan
- image: ghcr.io/apache/camel-karavan:4.14.5
+ image: ghcr.io/apache/camel-karavan:4.18.0
ports:
- "8080:8080"
environment:
diff --git a/docs/install/karavan-kubernetes/kustomization.yaml b/docs/install/karavan-kubernetes/kustomization.yaml
index d72c59b9..3566b9e5 100644
--- a/docs/install/karavan-kubernetes/kustomization.yaml
+++ b/docs/install/karavan-kubernetes/kustomization.yaml
@@ -4,7 +4,7 @@ commonLabels:
app: "karavan"
app.kubernetes.io/part-of: "karavan"
app.kubernetes.io/name: "karavan"
- app.kubernetes.io/version: "4.14.5"
+ app.kubernetes.io/version: "4.18.0"
namespace: "karavan"
resources:
- secret.yaml
diff --git a/karavan-app/pom.xml b/karavan-app/pom.xml
index de95ab7a..191e34b8 100644
--- a/karavan-app/pom.xml
+++ b/karavan-app/pom.xml
@@ -21,7 +21,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.camel.karavan</groupId>
<artifactId>karavan</artifactId>
- <version>4.14.5</version>
+ <version>4.18.0</version>
<properties>
<compiler-plugin.version>3.14.0</compiler-plugin.version>
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index a1eff6fa..149736aa 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -25,7 +25,7 @@ karavan.container.status.interval=3s
karavan.container.statistics.interval=10s
# karavan.container.statistics.interval should be off in kubernetes
-karavan.devmode.image=ghcr.io/apache/camel-karavan-devmode:${${karavan.version}:latest}
+karavan.devmode.image=ghcr.io/apache/camel-karavan-devmode:4.18.0
karavan.devmode.service.account=karavan
karavan.builder.service.account=karavan
karavan.secret.name=karavan
diff --git a/karavan-core/package-lock.json b/karavan-core/package-lock.json
index 4a7c40ad..b8a67daa 100644
--- a/karavan-core/package-lock.json
+++ b/karavan-core/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "karavan-core",
- "version": "4.14.2",
+ "version": "4.18.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "karavan-core",
- "version": "4.14.2",
+ "version": "4.18.0",
"license": "Apache-2.0",
"dependencies": {
"@types/js-yaml": "^4.0.9",
diff --git a/karavan-core/package.json b/karavan-core/package.json
index ba8ddfcb..61fc1bc9 100644
--- a/karavan-core/package.json
+++ b/karavan-core/package.json
@@ -1,7 +1,7 @@
{
"name": "karavan-core",
"publisher": "camel-karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"description": "Apache Camel Karavan Core",
"scripts": {
"build": "tsc && tsc-alias",
diff --git a/karavan-vscode/package-lock.json b/karavan-vscode/package-lock.json
index 350ee996..71c0eaa7 100644
--- a/karavan-vscode/package-lock.json
+++ b/karavan-vscode/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"license": "Apache-2.0",
"dependencies": {
"@carbon/icons-react": "11.70.0",
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 6c46a5b5..a1bead14 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -4,7 +4,7 @@
"displayName": "Karavan",
"icon": "icons/karavan.png",
"description": "Integration Toolkit for Apache Camel",
- "version": "4.14.5",
+ "version": "4.18.0",
"license": "Apache-2.0",
"preview": false,
"bugs": {
(camel-karavan) 07/33: Front-end Utils for 4.18.0
Posted by ma...@apache.org.
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 cb81ad8ae0315dc3f0cab18312b2e5e4993d22e0
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:20:27 2026 -0500
Front-end Utils for 4.18.0
---
.../src/main/webui/src/karavan/util/CodeUtils.ts | 4 +-
.../src/main/webui/src/karavan/util/StringUtils.ts | 62 ++++++++++++++++++++++
2 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts b/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
index a2fecc8c..94cb2d90 100644
--- a/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
+++ b/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
@@ -19,10 +19,10 @@ import {APPLICATION_PROPERTIES, ProjectFile} from "@models/ProjectModels";
import {BeanFactoryDefinition} from "@karavan-core/model/CamelDefinition";
import {Integration, IntegrationFile, KameletTypes, MetadataLabels} from "@karavan-core/model/IntegrationDefinition";
import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {KameletApi} from "@karavan-core/api/KameletApi";
import {CamelUtil} from "@karavan-core/api/CamelUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {ApplicationProperty} from "@karavan-core/model/MainConfigurationModel";
import {MainConfigurationApi} from "@karavan-core/api/MainConfigurationApi";
diff --git a/karavan-app/src/main/webui/src/karavan/util/StringUtils.ts b/karavan-app/src/main/webui/src/karavan/util/StringUtils.ts
index 370d0d45..c6d521ec 100644
--- a/karavan-app/src/main/webui/src/karavan/util/StringUtils.ts
+++ b/karavan-app/src/main/webui/src/karavan/util/StringUtils.ts
@@ -276,4 +276,66 @@ export function extractTitleFromMarkdown(markdown: string): string | null {
// If no title found
return null;
+}
+
+export function convertAnyToString(value: any): string {
+ if (value === null) return "null";
+ if (value === undefined) return "undefined";
+
+ // If it's already a string, check if it might be JSON
+ if (typeof value === "string") {
+ const trimmed = value.trim();
+
+ // Try parsing directly (normal JSON string)
+ try {
+ const parsed = JSON.parse(trimmed);
+ return JSON.stringify(parsed, null, 2);
+ } catch {
+ // Try parsing escaped JSON string
+ try {
+ const unescaped = trimmed.replace(/\\"/g, '"');
+ const parsed = JSON.parse(unescaped);
+ return JSON.stringify(parsed, null, 2);
+ } catch {
+ // Not JSON, return as-is
+ return value;
+ }
+ }
+ }
+
+ // Handle objects and arrays
+ if (typeof value === "object") {
+ try {
+ return JSON.stringify(value, null, 2);
+ } catch {
+ // Circular reference or unserializable object
+ return Object.prototype.toString.call(value);
+ }
+ }
+
+ // Fallback for primitives (number, boolean, symbol, bigint, function)
+ try {
+ return String(value);
+ } catch {
+ return "[Unstringifiable value]";
+ }
+}
+
+const placeholderRegexp = /\{\{\s*([^}:]+?)\s*\}\}/g;
+export function replacePlaceholders(code: string, placeholders: Record<string, string>){
+ return code.replace(placeholderRegexp, (match, rawKey) => {
+ const key = rawKey.trim();
+ return key in placeholders ? placeholders[key] : match;
+ });
+}
+
+export function findPlaceholders(code: string): string[] {
+ const regex = placeholderRegexp;
+ const results: string[] = [];
+ let match: RegExpExecArray | null;
+
+ while ((match = regex.exec(code)) !== null) {
+ results.push(match[1].trim());
+ }
+ return [...new Set(results)];
}
\ No newline at end of file
(camel-karavan) 28/33: Backend for 4.18.0
Posted by ma...@apache.org.
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 1991a4fc385999b06b3d71e65596f68ee00588cd
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:54:02 2026 -0500
Backend for 4.18.0
---
.../camel/karavan/api/GitCommitResource.java | 65 +++++
.../org/apache/camel/karavan/cache/CacheEvent.java | 8 +
.../org/apache/camel/karavan/cache/CacheUtils.java | 25 ++
.../camel/karavan/cache/ProjectFolderCommited.java | 59 ++++
.../apache/camel/karavan/cache/SystemCommit.java | 100 +++++++
.../apache/camel/karavan/loader/CacheLoader.java | 61 ++++
.../org/apache/camel/karavan/loader/GitLoader.java | 118 ++++++++
.../apache/camel/karavan/loader/StartupLoader.java | 99 +++++++
.../apache/camel/karavan/model/CommitResult.java | 9 +
.../camel/karavan/model/PathCommitDetails.java | 3 +
.../karavan/persistence/AccessCacheEntity.java | 28 ++
.../karavan/persistence/PersistenceService.java | 108 +++++++
.../karavan/persistence/ProjectCacheEntity.java | 29 ++
.../karavan/persistence/SessionCacheEntity.java | 33 +++
.../karavan/scheduler/ActivityCleanupService.java | 35 +++
.../karavan/scheduler/SessionCleanupService.java | 23 ++
.../camel/karavan/service/GitHistoryService.java | 310 +++++++++++++++++++++
.../camel/karavan/service/LogStreamingService.java | 165 +++++++++++
18 files changed, 1278 insertions(+)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/GitCommitResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/GitCommitResource.java
new file mode 100644
index 00000000..fe172e4c
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/GitCommitResource.java
@@ -0,0 +1,65 @@
+package org.apache.camel.karavan.api;
+
+import io.quarkus.security.Authenticated;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.karavan.cache.KaravanCache;
+import org.apache.camel.karavan.cache.ProjectFolderCommit;
+import org.apache.camel.karavan.cache.SystemCommit;
+import org.apache.camel.karavan.service.GitHistoryService;
+import org.jboss.logging.Logger;
+
+import java.util.List;
+
+@Path("/ui/git")
+public class GitCommitResource {
+
+ private static final Logger LOGGER = Logger.getLogger(GitCommitResource.class.getName());
+
+ @Inject
+ GitHistoryService gitHistoryService;
+
+ @Inject
+ KaravanCache karavanCache;
+
+ @GET
+ @Authenticated
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/commits/{projectId}")
+ public List<ProjectFolderCommit> getProjectCommits(@PathParam("projectId") String projectId) {
+ try {
+ return karavanCache.getProjectLastCommits(projectId);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ return List.of();
+ }
+ }
+
+ @POST
+ @Authenticated
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/commits/{projectId}")
+ public Response loadProjectCommits(@PathParam("projectId") String projectId) {
+ try {
+ gitHistoryService.importProjectCommits(projectId);
+ return Response.accepted().build();
+ } catch (Exception e) {
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ }
+
+ @GET
+ @Authenticated
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/system")
+ public List<SystemCommit> getSystemCommits() {
+ try {
+ return karavanCache.getSystemLastCommits();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ return List.of();
+ }
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheEvent.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheEvent.java
new file mode 100644
index 00000000..c83710b5
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheEvent.java
@@ -0,0 +1,8 @@
+package org.apache.camel.karavan.cache;
+
+public record CacheEvent(String key, Operation operation, Object data) {
+ public enum Operation {
+ SAVE,
+ DELETE
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheUtils.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheUtils.java
new file mode 100644
index 00000000..8ab2c999
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/CacheUtils.java
@@ -0,0 +1,25 @@
+package org.apache.camel.karavan.cache;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class CacheUtils {
+
+ public static <T> List<T> query(Map<?, T> cache, Predicate<T> predicate, Function<T, T> copier) {
+ return cache.values().stream()
+ .filter(predicate)
+ .map(copier)
+ .collect(Collectors.toList());
+ }
+
+ public static <T> T queryFirst(Map<?, T> cache, Predicate<T> predicate, Function<T, T> copier) {
+ return cache.values().stream()
+ .filter(predicate)
+ .map(copier)
+ .findFirst()
+ .orElse(null);
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommited.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommited.java
new file mode 100644
index 00000000..0490d3f9
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/ProjectFolderCommited.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.camel.karavan.cache;
+
+public class ProjectFolderCommited {
+
+ String projectId;
+ String lastCommit;
+ Long lastCommitTimestamp = 0L;
+
+ public ProjectFolderCommited(String projectId, String lastCommit, Long lastCommitTimestamp) {
+ this.projectId = projectId;
+ this.lastCommit = lastCommit;
+ this.lastCommitTimestamp = lastCommitTimestamp;
+ }
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public void setProjectId(String projectId) {
+ this.projectId = projectId;
+ }
+
+ public String getLastCommit() {
+ return lastCommit;
+ }
+
+ public void setLastCommit(String lastCommit) {
+ this.lastCommit = lastCommit;
+ }
+
+ public Long getLastCommitTimestamp() {
+ return lastCommitTimestamp;
+ }
+
+ public void setLastCommitTimestamp(Long lastCommitTimestamp) {
+ this.lastCommitTimestamp = lastCommitTimestamp;
+ }
+
+ public ProjectFolderCommited copy() {
+ return new ProjectFolderCommited(projectId, lastCommit, lastCommitTimestamp);
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/SystemCommit.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/SystemCommit.java
new file mode 100644
index 00000000..04c9bdf6
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/SystemCommit.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package org.apache.camel.karavan.cache;
+
+import java.util.List;
+
+public class SystemCommit {
+ private String id;
+ private String authorName;
+ private String authorEmail;
+ private Long commitTime;
+ private String message;
+ private List<String> projectIds;
+
+ public SystemCommit() {
+ }
+
+ public SystemCommit(String id, String authorName, String authorEmail, Long commitTime, String message, List<String> projectIds) {
+ this.id = id;
+ this.authorName = authorName;
+ this.authorEmail = authorEmail;
+ this.commitTime = commitTime;
+ this.message = message;
+ this.projectIds = projectIds;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAuthorName() {
+ return authorName;
+ }
+
+ public void setAuthorName(String authorName) {
+ this.authorName = authorName;
+ }
+
+ public String getAuthorEmail() {
+ return authorEmail;
+ }
+
+ public void setAuthorEmail(String authorEmail) {
+ this.authorEmail = authorEmail;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Long getCommitTime() {
+ return commitTime;
+ }
+
+ public void setCommitTime(Long commitTime) {
+ this.commitTime = commitTime;
+ }
+
+ public List<String> getProjectIds() {
+ return projectIds;
+ }
+
+ public void setProjectIds(List<String> projectIds) {
+ this.projectIds = projectIds;
+ }
+
+ @Override
+ public String toString() {
+ return "SystemCommit{" +
+ "id='" + id + '\'' +
+ ", authorName='" + authorName + '\'' +
+ ", authorEmail='" + authorEmail + '\'' +
+ ", message='" + message + '\'' +
+ ", commitTime='" + commitTime + '\'' +
+ '}';
+ }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/loader/CacheLoader.java b/karavan-app/src/main/java/org/apache/camel/karavan/loader/CacheLoader.java
new file mode 100644
index 00000000..da896d4b
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/loader/CacheLoader.java
@@ -0,0 +1,61 @@
+package org.apache.camel.karavan.loader;
+
+import io.vertx.core.json.JsonObject;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.cache.*;
+import org.apache.camel.karavan.persistence.AccessCacheEntity;
+import org.apache.camel.karavan.persistence.PersistenceService;
+import org.apache.camel.karavan.persistence.ProjectCacheEntity;
+import org.jboss.logging.Logger;
+
+@ApplicationScoped
+public class CacheLoader {
+
+ private static final Logger LOGGER = Logger.getLogger(CacheLoader.class);
+
+ @Inject
+ KaravanCache karavanCache;
+ @Inject
+ PersistenceService persistenceService;
+
+ public void load() {
+ LOGGER.info("Starting Karavan Cache Hydration...");
+
+ var allEntities = persistenceService.getAll(ProjectCacheEntity.class);
+
+ allEntities.stream()
+ .filter(entity -> ProjectFolder.class.getSimpleName().equals(entity.type))
+ .forEach(entity -> {
+ JsonObject json = new JsonObject(entity.data);
+ var project = json.mapTo(ProjectFolder.class);
+ karavanCache.saveProject(project, false);
+ });
+
+ allEntities.stream()
+ .filter(entity -> ProjectFile.class.getSimpleName().equals(entity.type))
+ .forEach(entity -> {
+ JsonObject json = new JsonObject(entity.data);
+ var file = json.mapTo(ProjectFile.class);
+ karavanCache.saveProjectFile(file, null, false);
+ });
+
+ persistenceService.getAll(AccessCacheEntity.class).forEach(entity -> {
+ JsonObject json = new JsonObject(entity.data);
+ if (AccessUser.class.getSimpleName().equals(entity.type)) {
+ karavanCache.saveUser(json.mapTo(AccessUser.class), false);
+ } else if (AccessRole.class.getSimpleName().equals(entity.type)) {
+ karavanCache.saveRole(json.mapTo(AccessRole.class), false);
+ } else if (AccessPassword.class.getSimpleName().equals(entity.type)) {
+ karavanCache.savePassword(json.mapTo(AccessPassword.class), false);
+ }
+ });
+
+ persistenceService.getActiveSessions().forEach(entity -> {
+ JsonObject json = new JsonObject(entity.data);
+ karavanCache.saveAccessSession(json.mapTo(AccessSession.class), false);
+ });
+
+ LOGGER.info("Karavan Cache Hydration complete.");
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/loader/GitLoader.java b/karavan-app/src/main/java/org/apache/camel/karavan/loader/GitLoader.java
new file mode 100644
index 00000000..0f334cfb
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/loader/GitLoader.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+package org.apache.camel.karavan.loader;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.KaravanConstants;
+import org.apache.camel.karavan.cache.KaravanCache;
+import org.apache.camel.karavan.cache.ProjectFile;
+import org.apache.camel.karavan.cache.ProjectFolder;
+import org.apache.camel.karavan.service.CodeService;
+import org.apache.camel.karavan.service.GitHistoryService;
+import org.apache.camel.karavan.service.GitService;
+import org.apache.camel.karavan.service.ProjectService;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jboss.logging.Logger;
+
+import java.time.Instant;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import static org.apache.camel.karavan.KaravanConstants.DEV;
+
+@ApplicationScoped
+public class GitLoader {
+
+ private static final Logger LOGGER = Logger.getLogger(GitLoader.class.getName());
+
+ @ConfigProperty(name = "karavan.environment", defaultValue = KaravanConstants.DEV)
+ String environment;
+
+ @Inject
+ ProjectService projectService;
+
+ @Inject
+ KaravanCache karavanCache;
+
+ @Inject
+ GitService gitService;
+
+ @Inject
+ GitHistoryService gitHistoryService;
+
+ @Inject
+ CodeService codeService;
+
+ public void load() throws Exception {
+ boolean git = gitService.checkGit();
+ LOGGER.info("Starting Project service: git is " + (git ? "ready" : "not ready"));
+ if (gitService.checkGit()) {
+ projectService.importProjects(false);
+ if (Objects.equals(environment, DEV)) {
+ addKameletsProject();
+ addBuildInProject(ProjectFolder.Type.templates.name());
+ addBuildInProject(ProjectFolder.Type.configuration.name());
+ addBuildInProject(ProjectFolder.Type.documentation.name());
+ addBuildInProject(ProjectFolder.Type.contracts.name());
+ }
+ gitHistoryService.importCommits();
+ } else {
+ LOGGER.info("Projects are not ready");
+ throw new Exception("Projects are not ready");
+ }
+ }
+
+ void addKameletsProject() {
+ try {
+ ProjectFolder kamelets = karavanCache.getProject(ProjectFolder.Type.kamelets.name());
+ if (kamelets == null) {
+ LOGGER.info("Add custom kamelets project");
+ kamelets = new ProjectFolder(ProjectFolder.Type.kamelets.name(), "Custom Kamelets", Instant.now().getEpochSecond() * 1000L, ProjectFolder.Type.kamelets);
+ karavanCache.saveProject(kamelets, false);
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error during custom kamelets project creation", e);
+ }
+ }
+
+ public void addBuildInProject(String projectId) {
+ try {
+ ProjectFolder projectFolder = karavanCache.getProject(projectId);
+ if (projectFolder == null) {
+ var title = Pattern.compile("^.").matcher(projectId).replaceFirst(m -> m.group().toUpperCase());
+ projectFolder = new ProjectFolder(projectId, title, Instant.now().getEpochSecond() * 1000L, ProjectFolder.Type.valueOf(projectId));
+ karavanCache.saveProject(projectFolder, false);
+
+ codeService.getBuildInProjectFiles(projectId).forEach((name, value) -> {
+ ProjectFile file = new ProjectFile(name, value, projectId, Instant.now().getEpochSecond() * 1000L);
+ karavanCache.saveProjectFile(file, null, false);
+ });
+ } else {
+ codeService.getBuildInProjectFiles(projectId).forEach((name, value) -> {
+ ProjectFile f = karavanCache.getProjectFile(projectId, name);
+ if (f == null) {
+ ProjectFile file = new ProjectFile(name, value, projectId, Instant.now().getEpochSecond() * 1000L);
+ karavanCache.saveProjectFile(file, null, false);
+ }
+ });
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error during creation of project " + projectId, e);
+ }
+ }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/loader/StartupLoader.java b/karavan-app/src/main/java/org/apache/camel/karavan/loader/StartupLoader.java
new file mode 100644
index 00000000..8f823dfc
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/loader/StartupLoader.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+package org.apache.camel.karavan.loader;
+
+import io.quarkus.runtime.Quarkus;
+import io.quarkus.runtime.StartupEvent;
+import io.vertx.mutiny.core.eventbus.EventBus;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
+import jakarta.enterprise.inject.Default;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.KaravanConstants;
+import org.apache.camel.karavan.docker.DockerService;
+import org.apache.camel.karavan.service.AuthService;
+import org.apache.camel.karavan.service.ConfigService;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+import org.eclipse.microprofile.health.Readiness;
+import org.jboss.logging.Logger;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.apache.camel.karavan.KaravanEvents.NOTIFICATION_PROJECTS_STARTED;
+
+@Default
+@Readiness
+@ApplicationScoped
+public class StartupLoader implements HealthCheck {
+
+ private static final Logger LOGGER = Logger.getLogger(StartupLoader.class.getName());
+
+ @ConfigProperty(name = "karavan.environment", defaultValue = KaravanConstants.DEV)
+ String environment;
+
+ @Inject
+ DockerService dockerService;
+
+ @Inject
+ EventBus eventBus;
+
+ @Inject
+ AuthService authService;
+
+ @Inject
+ CacheLoader cacheLoader;
+
+ @Inject
+ GitLoader gitLoader;
+
+ private final AtomicBoolean ready = new AtomicBoolean(false);
+
+ @Override
+ public HealthCheckResponse call() {
+ if (ready.get()) {
+ return HealthCheckResponse.named("Projects").up().build();
+ } else {
+ return HealthCheckResponse.named("Projects").down().build();
+ }
+ }
+
+ void onStart(@Observes StartupEvent ev) throws Exception {
+ LOGGER.info("Starting " + ConfigService.getAppName() + " in " + environment + " env in " + (ConfigService.inKubernetes() ? "Kubernetes" : "Docker"));
+ if (!ConfigService.inKubernetes() && !dockerService.checkDocker()){
+ Quarkus.asyncExit();
+ } else {
+ createCaches();
+ }
+ }
+
+ void createCaches() {
+ try {
+ LOGGER.info("Loading projects ...");
+ cacheLoader.load();
+ gitLoader.load();
+ LOGGER.info("Projects loaded");
+ eventBus.publish(NOTIFICATION_PROJECTS_STARTED, null);
+ LOGGER.info("Creating defaults...");
+ authService.loadDefaults();
+ ready.set(true);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
+ }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/CommitResult.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/CommitResult.java
new file mode 100644
index 00000000..6f4e8a09
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/CommitResult.java
@@ -0,0 +1,9 @@
+package org.apache.camel.karavan.model;
+
+import org.apache.camel.karavan.cache.ProjectFolder;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+
+import java.util.List;
+
+public record CommitResult (ProjectFolder projectFolder, List<RemoteRefUpdate.Status> statuses, List<String> messages, String commitId, Long commitTime) {}
+
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/PathCommitDetails.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/PathCommitDetails.java
new file mode 100644
index 00000000..e28b33c2
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/PathCommitDetails.java
@@ -0,0 +1,3 @@
+package org.apache.camel.karavan.model;
+
+public record PathCommitDetails(String projectId, String fileName, String commitId, Long commitTime, String content, boolean isFolder) { }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/persistence/AccessCacheEntity.java b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/AccessCacheEntity.java
new file mode 100644
index 00000000..fb024732
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/AccessCacheEntity.java
@@ -0,0 +1,28 @@
+package org.apache.camel.karavan.persistence;
+
+import jakarta.persistence.*;
+import org.hibernate.annotations.UpdateTimestamp;
+
+import java.time.Instant;
+
+@Entity
+@Table(name = AccessCacheEntity.TABLE_NAME, indexes = {
+ @Index(name = "idx_access_type", columnList = "type"),
+ @Index(name = "idx_access_last_update", columnList = "last_update")
+})
+public class AccessCacheEntity {
+
+ public static final String TABLE_NAME = "access_state";
+
+ @Id
+ public String key; // The GroupedKey
+
+ public String type; // "UserFile", "RoleFolder", etc.
+
+ @Column(columnDefinition = "jsonb")
+ public String data; // The actual object serialized to JSON
+
+ @UpdateTimestamp
+ @Column(name = "last_update")
+ public Instant lastUpdate;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/persistence/PersistenceService.java b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/PersistenceService.java
new file mode 100644
index 00000000..4525d96d
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/PersistenceService.java
@@ -0,0 +1,108 @@
+package org.apache.camel.karavan.persistence;
+
+import io.quarkus.vertx.ConsumeEvent;
+import io.vertx.core.json.JsonObject;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.Query;
+import jakarta.transaction.Transactional;
+import org.apache.camel.karavan.cache.AccessSession;
+import org.apache.camel.karavan.cache.CacheEvent;
+import org.jboss.logging.Logger;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.Objects;
+
+import static org.apache.camel.karavan.KaravanEvents.*;
+
+@ApplicationScoped
+public class PersistenceService {
+
+ private static final Logger LOGGER = Logger.getLogger(PersistenceService.class.getName());
+
+ @Inject
+ EntityManager entityManager;
+
+ private static final String SAVE_SQL =
+ "INSERT INTO %s (key, type, data, last_update) " +
+ "VALUES (:key, :type, CAST(:data AS jsonb), :now) " +
+ "ON CONFLICT (key) DO UPDATE SET " +
+ "type = EXCLUDED.type, " +
+ "data = EXCLUDED.data, " +
+ "last_update = EXCLUDED.last_update";
+
+ private static final String SAVE_SESSION_SQL =
+ "INSERT INTO session_state (key, type, data, expiry, last_update) " + // Added expiry
+ "VALUES (:key, :type, CAST(:data AS jsonb), :expiry, :now) " +
+ "ON CONFLICT (key) DO UPDATE SET " +
+ "type = EXCLUDED.type, data = EXCLUDED.data, " +
+ "expiry = EXCLUDED.expiry, last_update = EXCLUDED.last_update";
+
+ private static final String DELETE_SQL = "DELETE FROM %s WHERE key = :key";
+
+ @ConsumeEvent(value = PERSIST_PROJECT, blocking = true, ordered = true)
+ @Transactional
+ public void handleProjectUpdate(CacheEvent event) {
+ execute(ProjectCacheEntity.TABLE_NAME, event);
+ }
+
+ @ConsumeEvent(value = PERSIST_ACCESS, blocking = true, ordered = true)
+ @Transactional
+ public void handleAccessUpdate(CacheEvent event) {
+ execute(AccessCacheEntity.TABLE_NAME, event);
+ }
+
+ @ConsumeEvent(value = PERSIST_SESSION, blocking = true, ordered = true)
+ @Transactional
+ public void handleSessionUpdate(CacheEvent event) {
+ execute(SessionCacheEntity.TABLE_NAME, event);
+ }
+
+ private void execute(String tableName, CacheEvent event) {
+ try {
+ Query query;
+ if (event.operation().equals(CacheEvent.Operation.SAVE)) {
+ String json = Objects.requireNonNull(JsonObject.mapFrom(event.data())).encode();
+ String entityName = event.data().getClass().getSimpleName();
+
+ String sql = tableName.equals(SessionCacheEntity.TABLE_NAME) ? SAVE_SESSION_SQL : String.format(SAVE_SQL, tableName);
+
+ query = entityManager.createNativeQuery(String.format(sql, tableName))
+ .setParameter("key", event.key())
+ .setParameter("type", entityName)
+ .setParameter("data", json)
+ .setParameter("now", Instant.now());
+
+ if (event.data() instanceof AccessSession s) {
+ query.setParameter("expiry", s.getExpiredAt());
+ }
+ } else {
+ query = entityManager.createNativeQuery(String.format(DELETE_SQL, tableName))
+ .setParameter("key", event.key());
+ }
+ query.executeUpdate();
+ } catch (Exception e) {
+ LOGGER.errorf(e, "Failed to persist event %s in %s with key %s", event.operation(), tableName, event.key());
+ }
+ }
+
+ /**
+ * Fetches all records from a specific cache table as Entity objects.
+ */
+ public <T> List<T> getAll(Class<T> entityClass) {
+ String jpql = "SELECT e FROM " + entityClass.getSimpleName() + " e";
+ return entityManager.createQuery(jpql, entityClass).getResultList();
+ }
+
+ /**
+ * Fetches only active sessions.
+ */
+ public List<SessionCacheEntity> getActiveSessions() {
+ String jpql = "SELECT e FROM SessionCacheEntity e WHERE e.expiry > :now";
+ return entityManager.createQuery(jpql, SessionCacheEntity.class)
+ .setParameter("now", Instant.now())
+ .getResultList();
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/persistence/ProjectCacheEntity.java b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/ProjectCacheEntity.java
new file mode 100644
index 00000000..30b1d394
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/ProjectCacheEntity.java
@@ -0,0 +1,29 @@
+package org.apache.camel.karavan.persistence;
+
+import jakarta.persistence.*;
+import org.hibernate.annotations.UpdateTimestamp;
+
+import java.time.Instant;
+
+import static org.apache.camel.karavan.persistence.ProjectCacheEntity.TABLE_NAME;
+
+@Entity
+@Table(name = TABLE_NAME, indexes = {
+ @Index(name = "idx_project_type", columnList = "type"),
+ @Index(name = "idx_project_last_update", columnList = "last_update")
+})
+public class ProjectCacheEntity {
+
+ public static final String TABLE_NAME = "project_state";
+
+ @Id
+ public String key;
+ public String type;
+
+ @Column(columnDefinition = "jsonb")
+ public String data;
+
+ @UpdateTimestamp
+ @Column(name = "last_update")
+ public Instant lastUpdate;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/persistence/SessionCacheEntity.java b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/SessionCacheEntity.java
new file mode 100644
index 00000000..adfd3ea8
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/persistence/SessionCacheEntity.java
@@ -0,0 +1,33 @@
+package org.apache.camel.karavan.persistence;
+
+import jakarta.persistence.*;
+import org.hibernate.annotations.UpdateTimestamp;
+
+import java.time.Instant;
+
+import static org.apache.camel.karavan.persistence.SessionCacheEntity.TABLE_NAME;
+
+@Entity
+@Table(name = TABLE_NAME, indexes = {
+ @Index(name = "idx_session_type", columnList = "type"),
+ @Index(name = "idx_session_expiry", columnList = "expiry") // Add index for cleanup
+})
+public class SessionCacheEntity {
+
+ public static final String TABLE_NAME = "session_state";
+
+ @Id
+ public String key;
+
+ public String type;
+
+ @Column(columnDefinition = "jsonb")
+ public String data;
+
+ @Column(name = "expiry")
+ public Instant expiry; // The exact time this session expires
+
+ @UpdateTimestamp
+ @Column(name = "last_update")
+ public Instant lastUpdate;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/ActivityCleanupService.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/ActivityCleanupService.java
new file mode 100644
index 00000000..4ff1315b
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/ActivityCleanupService.java
@@ -0,0 +1,35 @@
+package org.apache.camel.karavan.scheduler;
+
+import io.quarkus.scheduler.Scheduled;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.cache.KaravanCache;
+
+import java.time.Instant;
+
+@ApplicationScoped
+public class ActivityCleanupService {
+
+ private static final long THRESHOLD = 120000;
+
+ @Inject
+ KaravanCache karavanCache;
+
+ @Scheduled(every = "2m") // Run every 2 minutes
+ void deleteUsersActivities() {
+
+ karavanCache.getCopyUsersWorking().entrySet().stream()
+ .filter(e -> {
+ var lastTimestamp = Instant.ofEpochMilli(e.getValue().getTimeStamp()).plusMillis(THRESHOLD);
+ return Instant.now().isAfter(lastTimestamp);
+ })
+ .forEach(e -> karavanCache.deleteUserWorking(e.getKey()));
+
+ karavanCache.getCopyUsersHeartBeat().entrySet().stream()
+ .filter(e -> {
+ var lastTimestamp = Instant.ofEpochMilli(e.getValue().getTimeStamp()).plusMillis(THRESHOLD);
+ return Instant.now().isAfter(lastTimestamp);
+ })
+ .forEach(e -> karavanCache.deleteUserHeartBeat(e.getKey()));
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/SessionCleanupService.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/SessionCleanupService.java
new file mode 100644
index 00000000..04013d33
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/SessionCleanupService.java
@@ -0,0 +1,23 @@
+package org.apache.camel.karavan.scheduler;
+
+import io.quarkus.scheduler.Scheduled;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.cache.KaravanCache;
+
+import java.time.Instant;
+
+@ApplicationScoped
+public class SessionCleanupService {
+
+ @Inject
+ KaravanCache karavanCache;
+
+ @Scheduled(every = "10m") // Run every 10 minutes
+ void deleteExpiredSessions() {
+
+ karavanCache.getAccessSessions().stream()
+ .filter(s -> Instant.now().isAfter(s.expiredAt))
+ .forEach(session -> karavanCache.deleteAccessSession(session.sessionId));
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/GitHistoryService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitHistoryService.java
new file mode 100644
index 00000000..66efd66a
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitHistoryService.java
@@ -0,0 +1,310 @@
+package org.apache.camel.karavan.service;
+
+import io.vertx.core.Vertx;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import org.apache.camel.karavan.cache.KaravanCache;
+import org.apache.camel.karavan.cache.ProjectFileCommitDiff;
+import org.apache.camel.karavan.cache.ProjectFolderCommit;
+import org.apache.camel.karavan.cache.SystemCommit;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.diff.RawTextComparator;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.EmptyTreeIterator;
+import org.eclipse.jgit.util.io.DisabledOutputStream;
+import org.eclipse.microprofile.context.ManagedExecutor;
+import org.jboss.logging.Logger;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.StreamSupport;
+
+@Singleton
+public class GitHistoryService {
+
+ private static final Logger LOGGER = Logger.getLogger(GitHistoryService.class.getName());
+
+ @Inject
+ ManagedExecutor managedExecutor;
+
+ @Inject
+ Vertx vertx;
+
+ @Inject
+ GitService gitService;
+
+ @Inject
+ KaravanCache karavanCache;
+
+ public void importProjectCommits(String projectId) {
+ LOGGER.info("Import commits for " + projectId);
+ managedExecutor.runAsync(() -> {
+ var commits = getProjectCommits(projectId, 10);
+ karavanCache.saveProjectLastCommits(projectId, commits);
+ });
+ }
+
+ public void importCommits() {
+ LOGGER.info("Import commits for system");
+ managedExecutor.runAsync(() -> {
+ var commits = getCommits( 100);
+ karavanCache.saveSystemCommits(commits);
+ });
+ }
+
+ public List<SystemCommit> getCommits(int maxCount) {
+ List<SystemCommit> result = new ArrayList<>();
+ try {
+ Git pollGit = gitService.getGit(true, vertx.fileSystem().createTempDirectoryBlocking("commits"));
+ if (pollGit == null) return result;
+
+ // Grab the repository reference to pass to our helper
+ Repository repository = pollGit.getRepository();
+
+ Iterable<RevCommit> commits = pollGit.log()
+ .setMaxCount(maxCount)
+ .all()
+ .call();
+
+ StreamSupport.stream(commits.spliterator(), false)
+ .sorted(Comparator.comparingInt(RevCommit::getCommitTime).reversed())
+ .forEach(commit -> {
+ try {
+ // Get the folders modified in this specific commit
+ List<String> modifiedFolders = getChangedFoldersInCommit(repository, commit);
+
+ SystemCommit systemCommit = new SystemCommit(
+ commit.getId().getName(),
+ commit.getAuthorIdent().getName(),
+ commit.getAuthorIdent().getEmailAddress(),
+ commit.getCommitTime() * 1000L,
+ commit.getShortMessage(),
+ modifiedFolders // <-- Injected here
+ );
+ result.add(systemCommit);
+ } catch (Exception e) {
+ LOGGER.error("Error building diffs for commit " + commit.getId().getName(), e);
+ }
+ });
+
+ } catch (Exception e) {
+ LOGGER.error("Error", e);
+ }
+
+ return result;
+ }
+
+ private List<String> getChangedFoldersInCommit(Repository repository, RevCommit commit) throws IOException {
+ Set<String> changedFolders = new HashSet<>();
+
+ // DisabledOutputStream ensures we don't print the actual file diffs to the console
+ try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE);
+ RevWalk revWalk = new RevWalk(repository)) {
+
+ diffFormatter.setRepository(repository);
+ diffFormatter.setDetectRenames(true);
+
+ AbstractTreeIterator parentTreeParser;
+
+ if (commit.getParentCount() > 0) {
+ // For standard/merge commits, compare against the first parent
+ RevCommit parent = revWalk.parseCommit(commit.getParent(0).getId());
+ parentTreeParser = new CanonicalTreeParser(null, repository.newObjectReader(), parent.getTree().getId());
+ } else {
+ // For the initial root commit, compare against an empty tree
+ parentTreeParser = new EmptyTreeIterator();
+ }
+
+ AbstractTreeIterator commitTreeParser = new CanonicalTreeParser(null, repository.newObjectReader(), commit.getTree().getId());
+
+ // Calculate the differences
+ List<DiffEntry> diffs = diffFormatter.scan(parentTreeParser, commitTreeParser);
+
+ for (DiffEntry diff : diffs) {
+ // If the file was deleted, getNewPath() returns /dev/null, so we must use getOldPath()
+ String path = (diff.getChangeType() == DiffEntry.ChangeType.DELETE)
+ ? diff.getOldPath()
+ : diff.getNewPath();
+
+ // Extract the folder path from the file path
+ int lastSlash = path.lastIndexOf('/');
+
+ // If lastSlash is -1, the file is in the root directory.
+ // You can change "/" to "" depending on your preference.
+ String folder = (lastSlash == -1) ? "/" : path.substring(0, lastSlash);
+
+ changedFolders.add(folder); // Set automatically deduplicates
+ }
+ }
+
+ return new ArrayList<>(changedFolders);
+ }
+
+ public List<ProjectFolderCommit> getProjectCommits(String projectId, int maxCount) {
+ List<ProjectFolderCommit> result = new ArrayList<>();
+ try {
+ Git pollGit = gitService.getGit(true, vertx.fileSystem().createTempDirectoryBlocking("commits"));
+ if (pollGit == null) return result;
+
+ Repository repo = pollGit.getRepository();
+
+ Iterable<RevCommit> commits = pollGit.log()
+ .setMaxCount(maxCount)
+ .all()
+ .addPath(projectId)
+ .call();
+ StreamSupport.stream(commits.spliterator(), false)
+ .sorted(Comparator.comparingInt(RevCommit::getCommitTime).reversed())
+ .forEach(commit -> {
+ try {
+ List<ProjectFileCommitDiff> diffs = buildDiffsWithBeforeAfter(repo, commit, projectId);
+
+ ProjectFolderCommit projectCommit = new ProjectFolderCommit(
+ commit.getId().getName(),
+ projectId,
+ commit.getAuthorIdent().getName(),
+ commit.getAuthorIdent().getEmailAddress(),
+ commit.getCommitTime() * 1000L,
+ commit.getShortMessage(),
+ diffs
+ );
+
+ result.add(projectCommit);
+ } catch (Exception e) {
+ LOGGER.error("Error building diffs for commit " + commit.getId().getName(), e);
+ }
+ });
+
+ } catch (Exception e) {
+ LOGGER.error("Error", e);
+ }
+
+ return result;
+ }
+
+ private List<ProjectFileCommitDiff> buildDiffsWithBeforeAfter(Repository repo, RevCommit commit, String projectId) throws Exception {
+ List<ProjectFileCommitDiff> out = new ArrayList<>();
+
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ revWalk.parseHeaders(commit);
+
+ RevCommit parent = commit.getParentCount() > 0 ? revWalk.parseCommit(commit.getParent(0).getId()) : null;
+
+ AbstractTreeIterator oldTreeIter = (parent == null)
+ ? new EmptyTreeIterator()
+ : treeIterator(repo, parent);
+
+ AbstractTreeIterator newTreeIter = treeIterator(repo, commit);
+
+ // 1) Collect DiffEntry list
+ List<DiffEntry> entries;
+ try (DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE)) {
+ df.setRepository(repo);
+ df.setDiffComparator(RawTextComparator.DEFAULT);
+ df.setDetectRenames(true);
+
+ entries = df.scan(oldTreeIter, newTreeIter);
+ }
+
+ // 2) For each entry, produce: diff text + before/after
+ for (DiffEntry entry : entries) {
+ // Optional: keep only diffs under the project path
+ if (!isUnderProjectPath(entry, projectId)) continue;
+
+ String patchText = formatUnifiedDiff(repo, entry);
+
+ String before = readBlobAsText(repo, entry.getOldId().toObjectId());
+ String after = readBlobAsText(repo, entry.getNewId().toObjectId());
+
+ // For added/deleted files, one side will be /dev/null and ObjectId may be zero
+ if (isZeroId(entry.getOldId().toObjectId())) before = null;
+ if (isZeroId(entry.getNewId().toObjectId())) after = null;
+
+ ProjectFileCommitDiff d = new ProjectFileCommitDiff();
+ d.setChangeType(entry.getChangeType().name());
+ d.setOldPath(entry.getOldPath());
+ d.setNewPath(entry.getNewPath());
+ d.setDiff(patchText);
+ d.setBefore(before);
+ d.setAfter(after);
+
+ out.add(d);
+ }
+ }
+
+ return out;
+ }
+
+ private AbstractTreeIterator treeIterator(Repository repo, RevCommit commit) throws Exception {
+ try (RevWalk revWalk = new RevWalk(repo)) {
+ RevCommit parsed = revWalk.parseCommit(commit.getId());
+ ObjectId treeId = parsed.getTree().getId();
+
+ CanonicalTreeParser parser = new CanonicalTreeParser();
+ try (var reader = repo.newObjectReader()) {
+ parser.reset(reader, treeId);
+ }
+ return parser;
+ }
+ }
+
+ private String formatUnifiedDiff(Repository repo, DiffEntry entry) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ try (DiffFormatter df = new DiffFormatter(baos)) {
+ df.setRepository(repo);
+ df.setDiffComparator(RawTextComparator.DEFAULT);
+ df.setDetectRenames(true);
+ df.format(entry);
+ }
+
+ return baos.toString(StandardCharsets.UTF_8);
+ }
+
+ private String readBlobAsText(Repository repo, ObjectId id) throws Exception {
+ if (id == null || isZeroId(id)) return null;
+
+ try {
+ ObjectLoader loader = repo.open(id, Constants.OBJ_BLOB);
+
+ // If you expect huge files, consider a size cap
+ byte[] bytes = loader.getBytes();
+
+ // If you need binary detection, add it here (e.g., scan for 0x00)
+ return new String(bytes, StandardCharsets.UTF_8);
+ } catch (MissingObjectException e) {
+ // Blob not available (should be rare unless repo state is odd)
+ return null;
+ }
+ }
+
+ private boolean isZeroId(ObjectId id) {
+ return id == null || ObjectId.zeroId().equals(id);
+ }
+
+ private boolean isUnderProjectPath(DiffEntry entry, String projectId) {
+ // projectId is used as a path prefix in addPath(projectId)
+ // but diff scan can still contain unrelated entries in some setups; this is a safe filter.
+ String p = projectId.endsWith("/") ? projectId : projectId + "/";
+ String oldPath = entry.getOldPath() == null ? "" : entry.getOldPath();
+ String newPath = entry.getNewPath() == null ? "" : entry.getNewPath();
+
+ // DiffEntry uses DiffEntry.DEV_NULL for added/deleted sides
+ if (DiffEntry.DEV_NULL.equals(oldPath)) oldPath = "";
+ if (DiffEntry.DEV_NULL.equals(newPath)) newPath = "";
+
+ return oldPath.startsWith(p) || newPath.startsWith(p) || oldPath.equals(projectId) || newPath.equals(projectId);
+ }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/LogStreamingService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/LogStreamingService.java
new file mode 100644
index 00000000..21b71b44
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/LogStreamingService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+package org.apache.camel.karavan.service;
+
+import com.github.dockerjava.api.DockerClient;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.dsl.LogWatch;
+import io.smallrye.mutiny.tuples.Tuple2;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.sse.Sse;
+import jakarta.ws.rs.sse.SseEventSink;
+import org.apache.camel.karavan.docker.DockerLogCallback;
+import org.apache.camel.karavan.docker.DockerService;
+import org.apache.camel.karavan.kubernetes.KubernetesService;
+import org.jboss.logging.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+
+@ApplicationScoped
+public class LogStreamingService {
+
+ private static final Logger LOGGER = Logger.getLogger(LogStreamingService.class.getName());
+ public static final String SERVICE_NAME = "LOG_WATCH";
+
+ private final ConcurrentHashMap<String, Tuple2<LogWatch, KubernetesClient>> logWatches = new ConcurrentHashMap<>();
+
+ @Inject
+ KubernetesService kubernetesService;
+
+ @Inject
+ DockerService dockerService;
+
+ public void streamLog(String type, String name, String username, SseEventSink eventSink, Sse sse) {
+ String oldName = Thread.currentThread().getName();
+ Thread.currentThread().setName("log-watcher-" + name + "-" + username);
+ try {
+ if (ConfigService.inKubernetes()) {
+ streamKubernetesLogs(name, username, eventSink, sse);
+ } else {
+ streamDockerLogs(name, eventSink, sse);
+ }
+ } finally {
+ Thread.currentThread().setName(oldName);
+ }
+ }
+
+ private void streamDockerLogs(String name, SseEventSink eventSink, Sse sse) {
+ LOGGER.info("LogWatch for " + name + " starting (Docker)");
+ final DockerLogCallback[] callbackHolder = new DockerLogCallback[1];
+
+ callbackHolder[0] = new DockerLogCallback(line -> {
+ try {
+ if (eventSink.isClosed()) throw new IOException("Sink closed");
+ // FIX: Strip trailing newline to match Kubernetes behavior
+ String cleanLine = line.endsWith("\n")
+ ? line.substring(0, line.length() - 1)
+ : line;
+
+ eventSink.send(sse.newEvent(cleanLine))
+ .toCompletableFuture()
+ .join();
+ } catch (CompletionException | IOException e) {
+ LOGGER.info("Browser disconnected from " + name + ". Stopping Docker stream.");
+ try {
+ if (callbackHolder[0] != null) callbackHolder[0].close();
+ } catch (IOException ex) { /* ignore */ }
+ } catch (Exception e) {
+ LOGGER.error("Error sending log event: " + e.getMessage());
+ }
+ });
+
+ try {
+ DockerClient client = dockerService.getDockerClient();
+ client.logContainerCmd(name)
+ .withStdOut(true).withStdErr(true).withTimestamps(false)
+ .withFollowStream(true).withTail(100)
+ .exec(callbackHolder[0]);
+
+ callbackHolder[0].awaitCompletion();
+ } catch (InterruptedException e) {
+ LOGGER.info("LogWatch interrupted for " + name);
+ } catch (Exception e) {
+ LOGGER.error("Docker Log Error for " + name + ": " + e.getMessage());
+ } finally {
+ cleanupDockerResources(callbackHolder[0], eventSink, name);
+ }
+ }
+
+ private void streamKubernetesLogs(String name, String username, SseEventSink eventSink, Sse sse) {
+ Tuple2<LogWatch, KubernetesClient> request = null;
+ try {
+ request = kubernetesService.getContainerLogWatch(name);
+ manageK8sSession(username, name, request); // Renamed for clarity
+
+ LogWatch logWatch = request.getItem1();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput()))) {
+ String line;
+ while (!eventSink.isClosed() && (line = reader.readLine()) != null) {
+ try {
+ eventSink.send(sse.newEvent(line))
+ .toCompletableFuture()
+ .join();
+ } catch (Exception e) {
+ LOGGER.debug("Client disconnected during K8s log stream");
+ break; // Stop reading immediately
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.error("Kubernetes Log Error for " + name + ": " + e.getMessage());
+ } finally {
+ cleanupK8sResources(request, eventSink, name);
+ }
+ }
+
+ private void cleanupDockerResources(DockerLogCallback callback, SseEventSink sink, String name) {
+ try {
+ if (callback != null) callback.close();
+ } catch (Exception e) { LOGGER.warn("Error closing callback", e); }
+ if (!sink.isClosed()) sink.close();
+ LOGGER.info("LogWatch for " + name + " ended");
+ }
+
+ private void cleanupK8sResources(Tuple2<LogWatch, KubernetesClient> request, SseEventSink sink, String name) {
+ if (request != null) {
+ try {
+ if (request.getItem1() != null) request.getItem1().close();
+ if (request.getItem2() != null) request.getItem2().close();
+ } catch (Exception e) { LOGGER.warn("Error closing K8s resources", e); }
+ }
+ if (!sink.isClosed()) sink.close();
+ LOGGER.info("LogWatch for " + name + " ended");
+ }
+
+ private void manageK8sSession(String username, String containerName, Tuple2<LogWatch, KubernetesClient> logWatch) {
+ String key = SERVICE_NAME + ":" + username + ":" + containerName;
+ if (logWatches.containsKey(key)) {
+ var old = logWatches.remove(key);
+ try {
+ if (old.getItem1() != null) old.getItem1().close();
+ if (old.getItem2() != null) old.getItem2().close();
+ } catch (Exception e) { /* ignore */ }
+ }
+ logWatches.put(key, logWatch);
+ }
+}
\ No newline at end of file
(camel-karavan) 30/33: Fron-end fixes for 4.18.0
Posted by ma...@apache.org.
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 f57f88aa8cc26845ca8942a6e3671c0bb1de8e55
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 19:01:01 2026 -0500
Fron-end fixes for 4.18.0
---
.../project/designer/editor/CodeEditor.tsx | 69 -------------
.../project/designer/kamelet/KameletDesigner.tsx | 3 -
.../project/designer/rest/RestMethodSelector.tsx | 2 -
.../project/designer/selector/DslFastCard.tsx | 8 +-
.../features/project/developer/DeveloperEditor.tsx | 7 +-
.../developer/MonacoEditorWrapperStateless.tsx | 113 ---------------------
.../project/project-topology/TopologyApi.tsx | 68 -------------
.../karavan/features/projects/SettingsToolbar.tsx | 3 +-
.../webui/src/karavan/services/ProjectService.ts | 1 -
.../webui/src/karavan/shared/ui/PlatformLogos.tsx | 13 ---
.../src/karavan/shared/ui/SideBarFormWrapper.tsx | 84 ---------------
.../src/main/webui/src/karavan/util/CodeUtils.ts | 105 -------------------
12 files changed, 3 insertions(+), 473 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx
deleted file mode 100644
index 3be551c9..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/project/designer/editor/CodeEditor.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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, {useEffect, useState} from 'react';
-import '@shared/monaco-setup';
-import Editor from "@monaco-editor/react";
-import {shallow} from "zustand/shallow";
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
-import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
-import {CamelUtil} from "@karavan-core/api/CamelUtil";
-
-export function CodeEditor () {
-
- const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow);
- const [setNotification, badge] = useDesignerStore((s) => [s.setNotification, s.notificationBadge], shallow)
- const [code, setCode] = useState<string>('');
-
- useEffect(() => {
- try {
- const clone = CamelUtil.cloneIntegration(integration);
- const c = CamelDefinitionYaml.integrationToYaml(clone);
- setCode(c);
- } catch (e: any) {
- const message: string = e?.message ? e.message : e.reason;
- setNotification(true, ['Error in YAML, Integration can not be saved!', message]);
- }
- return () => {
- setNotification(false, ['', '']);
- }
- }, []);
-
- function onChange(value: string | undefined) {
- if (value) {
- try {
- const i = CamelDefinitionYaml.yamlToIntegration(integration.metadata.name, value);
- setIntegration(i, false);
- setNotification(false, ['', '']);
- } catch (e: any) {
- const message: string = e?.message ? e.message : e.reason;
- setNotification(true, ['Error in YAML, Integration can not be saved!' ,message]);
- }
- }
- }
-
- return (
- <Editor
- height="100vh"
- defaultLanguage={'yaml'}
- theme={'light'}
- value={code}
- className={'code-editor'}
- defaultValue={code}
- onChange={(value, ev) => onChange(value)}
- />
- )
-}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx
index 728d4689..f045f8b4 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/kamelet/KameletDesigner.tsx
@@ -15,9 +15,6 @@
* limitations under the License.
*/
import React from 'react';
-import {
- PageSection,
-} from '@patternfly/react-core';
import '@features/project/designer/karavan.css';
import './kamelet.css';
import {KameletAnnotationsPanel} from "./KameletAnnotationsPanel";
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/rest/RestMethodSelector.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/rest/RestMethodSelector.tsx
index 1702925f..a4e525ea 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/designer/rest/RestMethodSelector.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/rest/RestMethodSelector.tsx
@@ -18,8 +18,6 @@ import React from 'react';
import {Badge, Card, CardBody, CardFooter, CardHeader, Content, Gallery} from '@patternfly/react-core';
import {CamelUi} from "../utils/CamelUi";
import {DslMetaModel} from "../utils/DslMetaModel";
-import {useDesignerStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
interface Props {
onMethodSelect: (method: DslMetaModel) => void
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/designer/selector/DslFastCard.tsx b/karavan-app/src/main/webui/src/karavan/features/project/designer/selector/DslFastCard.tsx
index be3d1ae8..2ecd0161 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/designer/selector/DslFastCard.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/designer/selector/DslFastCard.tsx
@@ -15,13 +15,7 @@
* limitations under the License.
*/
import React from 'react';
-import {
- Button,
- Card,
- CardBody,
- CardHeader,
- Content,
-} from '@patternfly/react-core';
+import {Button, Content,} from '@patternfly/react-core';
import './DslSelector.css';
import {CamelUi} from "../utils/CamelUi";
import {DslMetaModel} from "../utils/DslMetaModel";
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/developer/DeveloperEditor.tsx b/karavan-app/src/main/webui/src/karavan/features/project/developer/DeveloperEditor.tsx
index 28edfdbc..93e847e3 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/developer/DeveloperEditor.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/developer/DeveloperEditor.tsx
@@ -4,13 +4,10 @@ import {MarkdownEditor} from "@features/project/developer/MarkdownEditor";
import './DeveloperManager.css'
import {EditorErrorBoundaryWrapper} from "@features/project/developer/EditorErrorBoundaryWrapper";
import {EditorType} from "@features/project/developer/EditorConfig";
-import {useFilesStore, useFileStore} from "@stores/ProjectStore";
+import {useFileStore} from "@stores/ProjectStore";
import {shallow} from "zustand/shallow";
import {useDesignerStore} from "@features/project/designer/DesignerStore";
import {ProjectService} from "@services/ProjectService";
-import type * as monaco from "monaco-editor";
-import {useNavigate} from "react-router-dom";
-import {ROUTES} from "@app/navigation/Routes";
export interface DeveloperEditorProps {
editorType: EditorType;
@@ -21,9 +18,7 @@ export function DeveloperEditor(props: DeveloperEditorProps): JSX.Element {
const {editorType} = props
const [setDesignerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch], shallow)
const [file, setFile] = useFileStore((s) => [s.file, s.setFile], shallow)
- const [files] = useFilesStore((s) => [s.files], shallow);
const [code, setCode] = useState<string>("");
- const navigate = useNavigate();
useEffect(() => {
setDesignerSwitch(false);
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/developer/MonacoEditorWrapperStateless.tsx b/karavan-app/src/main/webui/src/karavan/features/project/developer/MonacoEditorWrapperStateless.tsx
deleted file mode 100644
index 6bd874ee..00000000
--- a/karavan-app/src/main/webui/src/karavan/features/project/developer/MonacoEditorWrapperStateless.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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, {useEffect, useRef, useState} from "react";
-import '@shared/monaco-setup';
-import type * as monaco from "monaco-editor";
-import Editor, {OnMount} from "@monaco-editor/react";
-import {useTheme} from "@app/theme/ThemeContext";
-import {useDebounceValue} from "usehooks-ts";
-import {defaultEditorOptions} from "@features/project/developer/EditorConfig";
-
-const MIN_HEIGHT = 100; // px
-const MAX_HEIGHT = 400; // px
-
-export interface MonacoEditorProps {
- language: string;
- onChange?: (value: string | undefined) => void;
- onDidBlurEditorText?: () => void;
- editorOptions?: monaco.editor.IStandaloneEditorConstructionOptions;
- height?: string;
- width?: string;
- initialCode: string;
- completionProvider?: monaco.languages.CompletionItemProvider;
-}
-
-export const MonacoEditorWrapperStateless: React.FC<MonacoEditorProps> = ({
- language,
- onChange,
- editorOptions,
- height,
- width = "100%",
- completionProvider, initialCode,onDidBlurEditorText
- }) => {
- const {isDark} = useTheme();
- const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
- const providerRefCompletionItem = useRef<monaco.IDisposable | null>(null);
- const [autoHeight, setAutoHeight] = useState(MIN_HEIGHT);
- const [code, setCode] = useState<string | undefined>(initialCode);
- const [debouncedCode] = useDebounceValue(code, 300);
-
- useEffect(() => {
- return () => disposeRefs();
- }, [])
-
- useEffect(() => {
- onChange?.(debouncedCode);
- }, [debouncedCode]);
-
- useEffect(() => {
- return () => disposeRefs();
- }, [])
-
- function disposeRefs() {
- providerRefCompletionItem.current?.dispose();
- }
-
- const handleEditorWillMount = (monacoInstance: typeof monaco) => {
- if (completionProvider) {
- disposeRefs();
- monacoInstance.languages.registerCompletionItemProvider(language, completionProvider);
- }
- };
-
- const handleEditorDidMount: OnMount = (editor, monacoInstance) => {
- editorRef.current = editor;
- resizeEditor();
-
- editor.onDidContentSizeChange(() => {
- resizeEditor();
- });
-
- editor.onDidBlurEditorText(() => {
- onDidBlurEditorText?.()
- });
- };
-
- const resizeEditor = () => {
- if (!editorRef.current) return;
-
- const contentHeight = editorRef.current.getContentHeight();
- const newHeight = Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, contentHeight));
-
- setAutoHeight(newHeight);
- editorRef.current.layout({width: editorRef.current.getLayoutInfo().width, height: newHeight});
- };
-
- return (
- <Editor className={'monaco-editor-wrapper-stateless'}
- defaultLanguage={language}
- value={code}
- onChange={(value, ev) => setCode(value)}
- options={editorOptions || defaultEditorOptions}
- height={height ?? autoHeight}
- width={width}
- theme={isDark ? 'vs-dark' : 'light'}
- beforeMount={handleEditorWillMount}
- onMount={handleEditorDidMount}
- />
- );
-};
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx
index cfb80842..f5d87cba 100644
--- a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx
@@ -361,74 +361,6 @@ export function getOpenApiNodes(topenapis: TopologyOpenApiNode[], showStats?: bo
});
}
-export function getAsyncApiNodes(tasyncapis: TopologyAsyncApiNode[]): NodeModel[] {
- const result: NodeModel[] = [];
- tasyncapis.forEach(tasyncapi => {
- // const node = {
- // id: tasyncapi.fileName,
- // type: 'node',
- // label: tasyncapi.title,
- // width: NODE_DIAMETER_ROUTE,
- // height: NODE_DIAMETER_ROUTE,
- // shape: NodeShape.circle,
- // status: NodeStatus.default,
- // data: {
- // isAlternate: false,
- // badge: 'AsyncAPI',
- // icon: 'asyncapi',
- // type: 'asyncapi',
- // // step: tin.rest,
- // fileName: tasyncapi.fileName,
- // secondaryLabel: tasyncapi.title,
- // }
- // } as NodeModel;
- // result.push(node);
-
- tasyncapi.operations.forEach(operation => {
- const operationNode = {
- id: `asyncapi-operation-${operation.operationId}`,
- type: 'node',
- label: operation.operationId,
- width: NODE_DIAMETER_ROUTE,
- height: NODE_DIAMETER_ROUTE,
- shape: NodeShape.rect,
- status: NodeStatus.default,
- data: {
- isAlternate: false,
- badge: 'AsyncAPI',
- type: operation.action,
- icon: operation.action,
- // step: tin.rest,
- fileName: tasyncapi.fileName,
- secondaryLabel: tasyncapi.title,
- }
- } as NodeModel;
- result.push(operationNode);
- })
- });
- return result;
-}
-
-export function getAsyncApiEdges(tasyncapis: TopologyAsyncApiNode[]): EdgeModel[] {
- const result: EdgeModel[] = [];
- tasyncapis.forEach(tasyncapi => {
- tasyncapi.operations.forEach(operation => {
- const edge: EdgeModel = {
- id: `${operation.action}-${operation.operationId}`,
- type: 'edge',
- source: operation.action === 'send' ? `asyncapi-operation-${operation.operationId}` : tasyncapi.fileName,
- target: operation.action === 'send' ? tasyncapi.fileName: `asyncapi-operation-${operation.operationId}`,
- edgeStyle: EdgeStyle.dashed,
- animationSpeed: EdgeAnimationSpeed.medium,
- data: {
- label: `${operation.action}`
- }
- }
- // result.push(edge);
- })
- });
- return result;
-}
export function getOpenApiEdges(topenapis: TopologyOpenApiNode[], tins: TopologyIncomingNode[], trcs: TopologyRestNode[]): EdgeModel[] {
const result: EdgeModel[] = [];
diff --git a/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx
index 560c958d..b1c226c0 100644
--- a/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/projects/SettingsToolbar.tsx
@@ -1,10 +1,9 @@
import React, {useState} from 'react';
-import {Button, Flex, FlexItem, Modal, ModalBody, ModalFooter, ModalHeader,} from '@patternfly/react-core';
+import {Button, Flex, Modal, ModalBody, ModalFooter, ModalHeader,} from '@patternfly/react-core';
import {useAppConfigStore, useFileStore, useProjectStore} from "@stores/ProjectStore";
import {shallow} from "zustand/shallow";
import {ProjectType} from "@models/ProjectModels";
import {KaravanApi} from "@api/KaravanApi";
-import {CatalogIcon} from '@patternfly/react-icons';
import {EditorToolbar} from "@features/project/developer/EditorToolbar";
export function SettingsToolbar() {
diff --git a/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts b/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
index 6bbfe1f9..1bcebdf3 100644
--- a/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
+++ b/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
@@ -26,7 +26,6 @@ import {EventBus} from "@features/project/designer/utils/EventBus";
import {KameletApi} from "@karavan-core/api/KameletApi";
import {getCurrentUser} from "@api/auth/AuthApi";
import {AxiosResponse} from "axios";
-import {KARAVAN_DOT_EXTENSION} from "@karavan-core/contants";
import {useLogStore} from "@stores/LogStore";
import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
index 46cd3c01..213123ce 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
@@ -61,19 +61,6 @@ export function PlatformVersionWithName() {
</div>)
}
-export function PlatformNameForToolbar() {
- return (<div style={{
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'center',
- gap: '3px',
- }}>
- {PlatformName()}
- </div>)
-}
-
export const PlatformName = (height: number | string = 20, width: number | string = 292.797) => (
<Content component={'h1'}>KARAVAN</Content>
)
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx
deleted file mode 100644
index 257610a3..00000000
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import {Button, Form} from "@patternfly/react-core";
-import {UseFormReturn} from "react-hook-form";
-
-interface AsyncFormWrapperProps {
- children: React.ReactNode;
- formContext: UseFormReturn<any>; // Accepts any form context
- selectedId: string | null;
- onSave?: (data: any) => void;
- onCancel?: () => void;
- onDelete?: () => void;
- showDelete?: boolean;
- isSubmitDisabled?: boolean;
- footer?: React.ReactNode;
-}
-
-export function SideBarFormWrapper({
- children,
- formContext,
- selectedId,
- onSave,
- onCancel,
- onDelete,
- showDelete = false,
- isSubmitDisabled = false,
- footer
- }: AsyncFormWrapperProps) {
-
- const {formState: {errors}, handleSubmit, getValues} = formContext;
-
- function onKeyDown(event: React.KeyboardEvent<HTMLFormElement>): void {
- event.stopPropagation();
- if (event.key === 'Enter') {
- event.preventDefault();
- handleSubmit(onSave)();
- }
- }
-
- // Common Footer Logic
- function getFooter() {
- const isDisabled = Object.getOwnPropertyNames(errors).length > 0 || isSubmitDisabled;
- return (
- <div style={{display: "flex", flexDirection: "row", gap: 8, justifyContent: "space-between", marginTop: 16}}>
- <div style={{flexGrow: 1}}>
- {showDelete &&
- <Button
- key="delete"
- variant={"danger"}
- isDanger
- isDisabled={isDisabled}
- onClick={onDelete}
- >
- Delete
- </Button>
- }
- </div>
- <Button
- key="confirm"
- variant={"primary"}
- isDisabled={isDisabled}
- onClick={handleSubmit(onSave)}
- >
- Save
- </Button>
- <Button
- key="cancel"
- variant="link" // Standardized to "link" or "secondary" as you prefer
- onClick={onCancel}
- >
- Cancel
- </Button>
- </div>
- )
- }
-
- return (
- <Form isHorizontal={true} autoComplete="off" noValidate onKeyDown={onKeyDown}>
- <div style={{display: "flex", flexDirection: "column", gap: 16}}>
- {children}
- </div>
- {footer || getFooter()}
- </Form>
- );
-}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts b/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
index 94cb2d90..648fbf9a 100644
--- a/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
+++ b/karavan-app/src/main/webui/src/karavan/util/CodeUtils.ts
@@ -23,8 +23,6 @@ import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {KameletApi} from "@karavan-core/api/KameletApi";
import {CamelUtil} from "@karavan-core/api/CamelUtil";
import {EventBus} from "@features/project/designer/utils/EventBus";
-import {ApplicationProperty} from "@karavan-core/model/MainConfigurationModel";
-import {MainConfigurationApi} from "@karavan-core/api/MainConfigurationApi";
export class CodeUtils {
@@ -100,107 +98,4 @@ export class CodeUtils {
return '';
}
}
-
- static getApplicationPropertiesCurrentValues(code: string): ApplicationProperty[] {
- if (!code) return []; // Add a guard for null or undefined code
- return code.split(/\r?\n/)
- .filter((p: string) => p.trim() !== '' && p.indexOf('#') !== 0) // Skip empty/whitespace lines and comments
- .map((p: string) => {
- const i = p.indexOf("=");
- // Handle lines that might not contain '='
- if (i === -1) {
- return {name: p.trim(), value: ''};
- }
- const key = p.substring(0, i).trim();
- const value = p.substring(i + 1).trim();
- return {name: key, value: value};
- });
- }
-
-
- /**
- * Replaces all deprecated property keys in a given .properties string with their new names.
- *
- * @param code The input string containing properties in .ini format.
- * @returns A new string with deprecated keys replaced.
- */
- static getReplaceAllPropertiesNames(code: string): string {
- // 1. Split the input text into an array of lines.
- const lines = code.split('\n');
-
- // 2. Process each line to check for and replace keys.
- const updatedLines = lines.map(line => {
- const trimmedLine = line.trim();
-
- // 3. Ignore comments (starting with # or !) and empty lines.
- if (trimmedLine.startsWith('#') || trimmedLine.startsWith('!') || trimmedLine === '') {
- return line;
- }
-
- // 4. Find the first separator (= or :) to isolate the key.
- const separatorIndex = trimmedLine.search(/[=:]/);
-
- // If no separator is found or the line starts with it, it's not a valid key-value pair.
- if (separatorIndex <= 0) {
- return line;
- }
-
- // Extract the key, trimming any whitespace around it.
- const key = trimmedLine.substring(0, separatorIndex).trim();
-
- // 5. Use the API to check if the key is deprecated.
- const change = MainConfigurationApi.findChangeByPropertyName(key);
-
- // 6. If a new name is found, replace the old key in the original line.
- // This replacement preserves leading whitespace and the value part of the string.
- if (change && change.replaced) {
- return line.replace(key, change.replaced);
- }
-
- // 7. If no change is needed, return the original line.
- return line;
- });
-
- // 8. Join the updated lines back into a single string.
- return updatedLines.join('\n');
- }
-
- static sortApplicationProperties(input: string): string {
- // Define priority order for prefixes
- const priorities = [
- 'camel.karavan.',
- 'camel.jbang.',
- 'camel.context',
- 'camel.',
- 'jib.',
- 'jkube.'
- ];
-
- // Function to determine the priority of each line
- const getPriority = (line: string): number => {
- for (let i = 0; i < priorities.length; i++) {
- if (line.startsWith(priorities[i])) {
- return i; // Return the index as priority
- }
- }
- return priorities.length; // Return a default priority for lines not matching any prefix
- };
-
- // Split input string into lines, sort them by priority and return the sorted result
- return input
- .split('\n')
- .sort((a, b) => {
- const priorityA = getPriority(a);
- const priorityB = getPriority(b);
-
- // If priorities are equal, use lexicographical order
- if (priorityA === priorityB) {
- return a.localeCompare(b);
- }
-
- // Otherwise, sort by priority
- return priorityA - priorityB;
- })
- .join('\n');
- }
}
\ No newline at end of file
(camel-karavan) 14/33: Front-end Services for 4.18.0
Posted by ma...@apache.org.
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 01ac80a60f17250c4565003a617a42ebf177ac01
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:30:00 2026 -0500
Front-end Services for 4.18.0
---
.../webui/src/karavan/services/AccessService.ts | 20 ++++++-
.../src/karavan/services/NotificationService.ts | 7 ++-
.../webui/src/karavan/services/ProjectService.ts | 70 +++++-----------------
.../webui/src/karavan/services/SystemService.ts | 16 +++++
4 files changed, 53 insertions(+), 60 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/services/AccessService.ts b/karavan-app/src/main/webui/src/karavan/services/AccessService.ts
index 151ddf71..39b52b19 100644
--- a/karavan-app/src/main/webui/src/karavan/services/AccessService.ts
+++ b/karavan-app/src/main/webui/src/karavan/services/AccessService.ts
@@ -1,5 +1,21 @@
-import {AccessApi} from "../api/AccessApi";
-import {useAccessStore} from "../stores/AccessStore";
+/*
+ * 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 {AccessApi} from "@api/AccessApi";
+import {useAccessStore} from "@stores/AccessStore";
export class AccessService {
diff --git a/karavan-app/src/main/webui/src/karavan/services/NotificationService.ts b/karavan-app/src/main/webui/src/karavan/services/NotificationService.ts
index 05a14f0a..231d000c 100644
--- a/karavan-app/src/main/webui/src/karavan/services/NotificationService.ts
+++ b/karavan-app/src/main/webui/src/karavan/services/NotificationService.ts
@@ -19,7 +19,7 @@ import {Subject} from "rxjs";
import {unstable_batchedUpdates} from "react-dom";
import {useProjectStore} from "@stores/ProjectStore";
import {ProjectService} from "@services/ProjectService";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
export class KaravanEvent {
id: string = '';
@@ -46,8 +46,11 @@ const sub = NotificationEventBus.onEvent()?.subscribe((event: KaravanEvent) => {
EventBus.sendAlert('Success', 'Configuration shared for ' + filename);
} else if (event.event === 'commit' && event.className === "ProjectFolder") {
const projectId = event.data?.projectId;
+ const statuses = event.data?.statuses;
const messages = event.data?.messages;
- EventBus.sendAlert('Commited', messages);
+ const variant = statuses?.filter((s: any) => s !== "OK")?.length > 0 ? 'danger' : 'success';
+ const title = variant === 'success' ? 'Commited' : 'Error';
+ EventBus.sendAlert(title, messages, variant);
if (useProjectStore.getState().project?.projectId === projectId) {
unstable_batchedUpdates(() => {
useProjectStore.setState({isPushing: false});
diff --git a/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts b/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
index ac43d9ba..6bbfe1f9 100644
--- a/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
+++ b/karavan-app/src/main/webui/src/karavan/services/ProjectService.ts
@@ -16,18 +16,19 @@
*/
import {KaravanApi} from '@api/KaravanApi';
-import {CamelStatus, ContainerImage, ContainerStatus, DeploymentStatus, Project, ProjectFile, ProjectType, ServiceStatus} from '../models/ProjectModels';
+import {CamelStatus, ContainerImage, ContainerStatus, DeploymentStatus, Project, ProjectFile, ProjectType, ServiceStatus} from '@models/ProjectModels';
import {TemplateApi} from '@karavan-core/api/TemplateApi';
-import {InfrastructureAPI} from '@features/integration/designer/utils/InfrastructureAPI';
+import {InfrastructureAPI} from '@features/project/designer/utils/InfrastructureAPI';
import {unstable_batchedUpdates} from 'react-dom'
-import {useDevModeStore, useFilesStore, useFileStore, useLogStore, useProjectsStore, useProjectStore, useStatusesStore} from '../stores/ProjectStore';
+import {useDevModeStore, useFilesStore, useFileStore, useProjectsStore, useProjectStore, useStatusesStore} from '@stores/ProjectStore';
import {ProjectEventBus} from '@bus/ProjectEventBus';
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {KameletApi} from "@karavan-core/api/KameletApi";
-import {ComponentApi} from '@karavan-core/api/ComponentApi';
import {getCurrentUser} from "@api/auth/AuthApi";
import {AxiosResponse} from "axios";
-import {ASYNCAPI_FILE_NAME_JSON, JSON_SCHEMA_EXTENSION, OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
+import {KARAVAN_DOT_EXTENSION} from "@karavan-core/contants";
+import {useLogStore} from "@stores/LogStore";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
export class ProjectService {
@@ -201,14 +202,14 @@ export class ProjectService {
public static refreshAllContainerStatuses() {
KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
- useStatusesStore.setState({containers: statuses});
+ useContainerStatusesStore.setState({containers: statuses});
});
}
public static refreshContainerStatus(projectId: string, env: string) {
KaravanApi.getContainerStatus(projectId, env, (res) => {
if (res.status === 200) {
- const oldContainers = [...useStatusesStore.getState().containers];
+ const oldContainers = [...useContainerStatusesStore.getState().containers];
const newContainers = res.data;
const newMap = new Map<string, ContainerStatus>(
newContainers.map(container => [container.containerName, container])
@@ -217,7 +218,7 @@ export class ProjectService {
.filter(container => newMap.has(container.containerName)) // Filter out old containers not in new
.map(container => newMap.get(container.containerName)!) // Replace with new containers
.concat(newContainers.filter(container => !oldContainers.some(old => old.containerName === container.containerName)));
- useStatusesStore.setState({containers: containers});
+ useContainerStatusesStore.setState({containers: containers});
}
})
}
@@ -309,13 +310,6 @@ export class ProjectService {
});
}
- public static getAllStatuses() {
- ProjectService.refreshAllDeploymentStatuses();
- ProjectService.refreshAllContainerStatuses();
- ProjectService.refreshAllServicesStatuses();
- ProjectService.refreshAllCamelContextStatuses();
- }
-
public static refreshProjectFiles(projectId: string) {
KaravanApi.getFiles(projectId, (files: ProjectFile[]) => {
const kameletsYamls = files.filter(f => f.name.endsWith('.kamelet.yaml') && f.code?.length > 0).map(f => f.code).join("\n---\n")
@@ -325,6 +319,8 @@ export class ProjectService {
useFilesStore.setState({files: files});
});
+ useFilesStore.getState().fetchCommitedFiles(projectId);
+
KaravanApi.getFilesDiff(projectId, (diff: any) => {
useFilesStore.setState({diff: diff});
});
@@ -333,7 +329,7 @@ export class ProjectService {
public static refreshProjectData(projectId: string) {
KaravanApi.getProject(projectId, (project: Project) => {
// ProjectEventBus.selectProject(project);
- KaravanApi.getTemplatesFiles((files: ProjectFile[]) => {
+ KaravanApi.getFiles(ProjectType.templates, (files: ProjectFile[]) => {
files.filter(f => f.name.endsWith('java'))
.forEach(f => {
const name = f.name.replace(".java", '');
@@ -347,44 +343,6 @@ export class ProjectService {
KaravanApi.getSecrets((any: []) => InfrastructureAPI.setSecrets(any));
KaravanApi.getServices((any: []) => InfrastructureAPI.setServices(any));
KaravanApi.getImages(projectId, (images: []) => useProjectStore.setState({images: images}));
- }
-
- public static reloadBlockedTemplates() {
- KaravanApi.getTemplatesFiles((files: ProjectFile[]) => {
- files.filter(f => f.name.endsWith('blocklist.txt')).forEach(file => {
- if (file.name === 'components-blocklist.txt') {
- ComponentApi.saveBlockedComponentNames(file.code.split(/\r?\n/));
- } else if (file.name === "kamelets-blocklist.txt") {
- KameletApi.saveBlockedKameletNames(file.code.split(/\r?\n/));
- }
- });
- });
- }
-
- public static refreshSharedData(after?: (schemaFiles: ProjectFile[], projectAsyncFiles: ProjectFile[], projectOpenFiles: ProjectFile[], sharedFile?: ProjectFile) => void) {
- const projectAsyncFilesPromise = new Promise<ProjectFile[]>((resolve) => {
- KaravanApi.getFilesByName(ASYNCAPI_FILE_NAME_JSON, files => {
- resolve(files);
- });
- });
-
- const projectOpenFilesPromise = new Promise<ProjectFile[]>((resolve) => {
- KaravanApi.getFilesByName(OPENAPI_FILE_NAME_JSON, files => {
- resolve(files);
- });
- });
-
- const sharedFilesPromise = new Promise<ProjectFile[]>((resolve) => {
- KaravanApi.getFiles(ProjectType.shared, (files: ProjectFile[]) => {
- resolve(files);
- });
- });
-
- Promise.all([projectAsyncFilesPromise, projectOpenFilesPromise, sharedFilesPromise])
- .then(([projectAsyncFiles, projectOpenFiles, sharedFiles]) => {
- const sharedAsyncApiFile = sharedFiles.find(f => f.name === ASYNCAPI_FILE_NAME_JSON);
- const schemaFiles = sharedFiles.filter(f => f.name.endsWith(JSON_SCHEMA_EXTENSION));
- after?.(schemaFiles, projectAsyncFiles, projectOpenFiles, sharedAsyncApiFile);
- });
+ useFilesStore.getState().fetchCommitedFiles(projectId);
}
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/services/SystemService.ts b/karavan-app/src/main/webui/src/karavan/services/SystemService.ts
index 5e97ee9c..76e27114 100644
--- a/karavan-app/src/main/webui/src/karavan/services/SystemService.ts
+++ b/karavan-app/src/main/webui/src/karavan/services/SystemService.ts
@@ -1,3 +1,19 @@
+/*
+ * 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 {useSystemStore} from "@stores/SystemStore";
import {SystemApi} from "@api/SystemApi";
import {KubernetesConfigMap, KubernetesSecret} from "@models/SystemModels";
(camel-karavan) 21/33: Front-end Login for 4.18.0
Posted by ma...@apache.org.
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 838e0091dd4798341a7e6ff0914d221b023be23f
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:47:08 2026 -0500
Front-end Login for 4.18.0
---
.../main/webui/src/karavan/app/login/LoginPage.css | 24 ----------------------
1 file changed, 24 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
index f7d78315..3b1c25ee 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
+++ b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
@@ -330,28 +330,4 @@
width: 32px;
height: 32px;
}
- .openapi-logo {
- height: 36px;
- }
- .asyncapi-logo {
- height: 32px;
- }
- .json-schema-logo {
- height: 28px;
- }
- .groovy-logo {
- height: 32px;
- }
- .jib-logo {
- height: 32px;
- }
- .infinispan-logo {
- height: 30px;
- }
- .jkube-logo {
- height: 32px;
- }
- .patternfly-logo {
- height: 28px;
- }
}
(camel-karavan) 26/33: Front-end Project for 4.18.0
Posted by ma...@apache.org.
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 d6b33a42eb7b05b17e318e7b508a722cb558f75d
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:52:20 2026 -0500
Front-end Project for 4.18.0
---
.../karavan/features/project/ContainerLogTab.tsx | 81 +++
.../karavan/features/project/DesignerToggle.tsx | 56 ++
.../features/project/FileSearchToolbarItem.tsx | 53 ++
.../features/project/ImageDownloadToolbar.tsx | 61 ++
.../src/karavan/features/project/Project.types.ts | 19 +
.../project/ProjectContainerContextToolbar.tsx | 67 ++
.../project/ProjectContainersContextProvider.tsx | 82 +++
.../karavan/features/project/ProjectContext.tsx | 29 +
.../src/karavan/features/project/ProjectPage.css | 304 +++++++++
.../src/karavan/features/project/ProjectPage.tsx | 107 +++
.../features/project/ProjectPageNavigation.tsx | 179 +++++
.../src/karavan/features/project/ProjectPanel.tsx | 86 +++
.../src/karavan/features/project/ProjectTitle.tsx | 69 ++
.../karavan/features/project/RenameFileModal.tsx | 110 ++++
.../webui/src/karavan/features/project/devmode.css | 56 ++
.../features/project/project-build/BuildTab.tsx | 32 +
.../project-containers/ContainerButtons.tsx | 149 +++++
.../ContainerEnvironmentPanel.tsx | 116 ++++
.../project/project-containers/ContainersTab.tsx | 25 +
.../project/project-containers/ContainersTable.tsx | 54 ++
.../project-containers/ContainersTableRow.tsx | 73 +++
.../project-containers/ContainersToolbar.tsx | 34 +
.../project-containers/DeploymentButtons.tsx | 164 +++++
.../project/project-containers/DeploymentPanel.tsx | 54 ++
.../project/project-containers/ImagesPanel.tsx | 293 +++++++++
.../project/project-pod/PodEventsLogTable.tsx | 61 ++
.../features/project/project-pod/PodTab.tsx | 16 +
.../project-topology/CustomComponentFactory.tsx | 87 +++
.../project/project-topology/CustomEdge.tsx | 40 ++
.../project/project-topology/CustomGroup.tsx | 35 +
.../project/project-topology/CustomNode.tsx | 178 +++++
.../project/project-topology/GetCustomMenu.tsx | 67 ++
.../project/project-topology/TopologyApi.tsx | 722 +++++++++++++++++++++
.../project/project-topology/TopologyBeans.css | 52 ++
.../project/project-topology/TopologyBeans.tsx | 77 +++
.../project/project-topology/TopologyElkLayout.ts | 222 +++++++
.../project/project-topology/TopologyLegend.css | 68 ++
.../project/project-topology/TopologyLegend.tsx | 38 ++
.../project/project-topology/TopologyTab.tsx | 191 ++++++
.../project/project-topology/TopologyToolbar.tsx | 102 +++
.../features/project/project-topology/topology.css | 202 ++++++
.../project/project-topology/useTopologyHook.tsx | 128 ++++
.../karavan/features/project/readme/ReadmeTab.tsx | 31 +
.../features/project/toolbar/BuildToolbar.tsx | 185 ++++++
.../features/project/toolbar/DevModeToolbar.css | 60 ++
.../features/project/toolbar/DevModeToolbar.tsx | 164 +++++
.../features/project/toolbar/ProjectToolbar.tsx | 48 ++
.../karavan/features/project/useProjectHook.tsx | 173 +++++
48 files changed, 5300 insertions(+)
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ContainerLogTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ContainerLogTab.tsx
new file mode 100644
index 00000000..a2e76368
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ContainerLogTab.tsx
@@ -0,0 +1,81 @@
+import React, {useEffect, useRef, useState} from 'react';
+import {useSelectedContainerStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {LogWatchApi} from "@api/LogWatchApi";
+import {LogViewer, LogViewerSearch} from '@patternfly/react-log-viewer';
+import {Button, Checkbox, Tooltip, TooltipPosition} from "@patternfly/react-core";
+import {ProjectEventBus} from "@bus/ProjectEventBus";
+import {TrashAltIcon} from "@patternfly/react-icons";
+import {ProjectContainerContextToolbar} from "@features/project/ProjectContainerContextToolbar";
+import {useLogStore} from "@stores/LogStore";
+
+export function ContainerLogTab() {
+
+ const [selectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName]);
+ const logViewerRef = useRef(null);
+ const [data, setData] = useLogStore((state) => [state.data, state.setData], shallow);
+
+ const [isTextWrapped, setIsTextWrapped] = useState(true);
+ const [autoScroll, setAutoScroll] = useState(true);
+ const showLogger = selectedContainerName !== undefined && selectedContainerName !== null;
+ const [controller, setController] = React.useState(new AbortController());
+
+ useEffect(() => {
+ setData([]);
+ controller.abort()
+ const c = new AbortController();
+ setController(c);
+ if (selectedContainerName) {
+ const f = LogWatchApi.fetchData('container', selectedContainerName, c).then(_ => {
+ });
+ }
+ return () => {
+ c.abort();
+ };
+ }, [selectedContainerName]);
+
+ function getToolbar() {
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '8px', paddingRight: '16px'}}>
+ <LogViewerSearch placeholder={'search'} minSearchChars={4} style={{width: "400px"}}/>
+ <Tooltip content={"Clean log"} position={TooltipPosition.bottom}>
+ <Button variant="plain" onClick={() => ProjectEventBus.sendLog('set', '')} icon={<TrashAltIcon/>}/>
+ </Tooltip>
+ <Checkbox label="Wrap text" aria-label="wrap text checkbox" isChecked={isTextWrapped}
+ id="wrap-text-checkbox"
+ onChange={(_, checked) => setIsTextWrapped(checked)}/>
+ <Checkbox label="Autoscroll" aria-label="autoscroll checkbox" isChecked={autoScroll}
+ id="autoscroll-checkbox"
+ onChange={(_, checked) => setAutoScroll(checked)}/>
+ </div>
+ );
+ }
+
+
+ const FooterButton = () => {
+ const handleClick = () => {
+ logViewerRef.current.scrollToBottom();
+ };
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent:'center', alignItems: 'center', gap: '8px'}}>
+ <Button variant={'link'} onClick={handleClick}>Jump to the bottom</Button>
+ </div>
+ );
+ };
+
+ const currentLine = data.length > 0 ? data.length - 1 : 0;
+ return (
+ <LogViewer
+ ref={logViewerRef}
+ isTextWrapped={isTextWrapped}
+ hasLineNumbers={false}
+ loadingContent={"Loading..."}
+ height={"100vh"}
+ data={showLogger && data.length > 0 ? data : []}
+ scrollToRow={autoScroll ? currentLine : undefined}
+ theme={'dark'}
+ toolbar={<ProjectContainerContextToolbar additionalTools={getToolbar()}/>}
+ footer={<FooterButton />}
+ />
+ );
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/DesignerToggle.tsx b/karavan-app/src/main/webui/src/karavan/features/project/DesignerToggle.tsx
new file mode 100644
index 00000000..9eaf8be3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/DesignerToggle.tsx
@@ -0,0 +1,56 @@
+/*
+ * 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 {ToggleGroup, ToggleGroupItem,} from '@patternfly/react-core';
+import {useFileStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {useDesignerStore} from "@features/project/designer/DesignerStore";
+import {getProjectFileTypeByName} from "@models/ProjectModels";
+import {CodeIcon} from "@patternfly/react-icons/dist/esm/icons";
+import {DeploymentPattern} from "@carbon/icons-react";
+
+export function DesignerToggle() {
+
+ const [file] = useFileStore((s) => [s.file], shallow);
+ const [setDesignerSwitch, designerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch, s.designerSwitch], shallow)
+
+ const fileType = getProjectFileTypeByName(file?.name || "");
+ const showDesignerSwitch = fileType.filter(ft => ['INTEGRATION', 'KAMELET', 'OPENAPI' , 'ASYNCAPI'].includes(ft.name)).length > 0;
+
+ return (
+ <ToggleGroup aria-label="DesignerToggle" className={"designer-toggle"}>
+ <ToggleGroupItem
+ icon={<DeploymentPattern className='carbon'/>}
+ aria-label="designer"
+ text='Designer'
+ buttonId="toggle-group-icons-1"
+ isSelected={designerSwitch}
+ isDisabled={!showDesignerSwitch}
+ onChange={(_, __) => setDesignerSwitch(true)}
+ />
+ <ToggleGroupItem
+ icon={<CodeIcon/>}
+ text='Code'
+ aria-label="code"
+ buttonId="toggle-group-icons-2"
+ isSelected={!designerSwitch}
+ onChange={(_, __) => setDesignerSwitch(false)}
+ />
+ </ToggleGroup>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/FileSearchToolbarItem.tsx b/karavan-app/src/main/webui/src/karavan/features/project/FileSearchToolbarItem.tsx
new file mode 100644
index 00000000..4feeaea9
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/FileSearchToolbarItem.tsx
@@ -0,0 +1,53 @@
+import React, {useEffect} from 'react';
+import {Button, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities} from '@patternfly/react-core';
+import {shallow} from "zustand/shallow";
+import {useSearchStore} from "@stores/SearchStore";
+import {SearchApi} from "@api/SearchApi";
+import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
+import {useDebounceValue} from "usehooks-ts";
+
+export function FileSearchToolbarItem(props: {disabled: boolean}) {
+
+ const [search, setSearch, setSearchResults] = useSearchStore((s) => [s.search, s.setSearch, s.setSearchResults], shallow)
+ const [debouncedSearch] = useDebounceValue(search, 300);
+
+ useEffect(() => {
+ if (search !== undefined && search !== '') {
+ SearchApi.searchAll(search, response => {
+ if (response) {
+ setSearchResults(response);
+ }
+ })
+ } else {
+ setSearchResults([])
+ }
+ }, [debouncedSearch]);
+
+ function searchInput() {
+ return (
+ <TextInputGroup style={{ width: "300px" }} isDisabled={props.disabled}>
+ <TextInputGroupMain
+ id="search-input"
+ value={search}
+ placeholder='Search'
+ type="text"
+ autoComplete={"off"}
+ autoFocus={true}
+ onChange={(_event, value) => {
+ setSearch(value);
+ }}
+ aria-label="text input example"
+ />
+ <TextInputGroupUtilities>
+ <Button variant="plain" onClick={_ => {
+ setSearch('');
+ }}>
+ <TimesIcon aria-hidden={true}/>
+ </Button>
+ </TextInputGroupUtilities>
+ </TextInputGroup>
+ )
+ }
+
+ return (searchInput())
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ImageDownloadToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ImageDownloadToolbar.tsx
new file mode 100644
index 00000000..8cfcf79a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ImageDownloadToolbar.tsx
@@ -0,0 +1,61 @@
+/*
+ * 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, {useEffect} from 'react';
+import {FlexItem, Toolbar, ToolbarContent,} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {useFileStore, useProjectStore} from "../../stores/ProjectStore";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {shallow} from "zustand/shallow";
+
+export function ImageDownloadToolbar() {
+
+ const [project] = useProjectStore((s) => [s.project], shallow)
+ const [file] = useFileStore((state) => [state.file], shallow)
+
+ useEffect(() => {
+ }, [file]);
+
+ function isYaml(): boolean {
+ return file !== undefined && file.name.endsWith("yaml");
+ }
+
+ function isIntegration(): boolean {
+ return isYaml() && file?.code !== undefined && CamelDefinitionYaml.yamlIsIntegration(file.code) !== 'none';
+ }
+
+ function downloadImage() {
+ EventBus.sendCommand("downloadImage");
+ }
+
+ return (
+ <Toolbar id="toolbar-group-types">
+ <ToolbarContent>
+ {isIntegration() &&
+ <FlexItem>
+ {/*<Tooltip content="Download image" position={"bottom-end"}>*/}
+ {/* <Button size="sm" variant="control" icon={<DownloadImageIcon/>}*/}
+ {/* onClick={e => downloadImage()}/>*/}
+ {/*</Tooltip>*/}
+ </FlexItem>
+ }
+ </ToolbarContent>
+ </Toolbar>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/Project.types.ts b/karavan-app/src/main/webui/src/karavan/features/project/Project.types.ts
new file mode 100644
index 00000000..0910166d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/Project.types.ts
@@ -0,0 +1,19 @@
+import {DslMetaModel} from "@features/project/designer/utils/DslMetaModel";
+import {Project} from "@models/ProjectModels";
+
+export type ProjectFunctions = {
+ createNewRouteFile: (dsl: DslMetaModel, parentId: string, position?: number | undefined, fileName?: string) => void;
+ createOpenApiRestFile: () => void;
+ createNewBean: () => void;
+ createNewKamelet: () => void;
+ createRouteConfiguration: () => void;
+ createOpenApi: () => void;
+ createAsyncApi: () => void;
+ createNewRestFile: () => void;
+ refreshData: () => void;
+ refreshSharedData: () => void;
+ project: Project
+};
+
+// 2. Define the hook FUNCTION'S signature
+export type UseProjectHook = () => ProjectFunctions;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainerContextToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainerContextToolbar.tsx
new file mode 100644
index 00000000..edd31f6c
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainerContextToolbar.tsx
@@ -0,0 +1,67 @@
+import React, {ReactElement} from 'react';
+import {ProjectTitle} from "@features/project/ProjectTitle";
+import {ProjectContainersContext} from "@features/project/ProjectContainersContextProvider";
+import {ToggleGroup, ToggleGroupItem} from "@patternfly/react-core";
+import {useProjectStore, useSelectedContainerStore} from "@stores/ProjectStore";
+import {BuildIcon, CogIcon, RunningIcon} from "@patternfly/react-icons";
+import {ContainerStatus} from "@models/ProjectModels";
+
+interface Props {
+ additionalTools?: ReactElement;
+ hideContainersToggle?: boolean;
+}
+
+export function ProjectContainerContextToolbar(props: Props): ReactElement {
+
+ const {additionalTools, hideContainersToggle} = props;
+ const context = React.useContext(ProjectContainersContext);
+ // if (!context) throw new Error("ProjectContainersContext not found!");
+ // const {containerStatuses} = context ? context : undefined;
+ const [selectedContainerName, setSelectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName, s.setSelectedContainerName]);
+ const [tabIndex] = useProjectStore((s) => [s.tabIndex]);
+
+ function getIcon(status: ContainerStatus) {
+ if (status.type === "devmode") {
+ const className = status.state === "running" ? 'project-container-devmode' : ''
+ return <CogIcon className={className}/>
+ } else if (status.type === "packaged") {
+ const className = status.state === "running" ? 'project-container-package' : ''
+ return <RunningIcon className={className}/>
+ } else if (status.type === "build") {
+ const className = status.state === "running" ? 'project-container-build' : ''
+ return <BuildIcon className={className}/>
+ }
+ }
+
+ function getContainers() {
+ if (tabIndex !== 'build') {
+ return context?.containerStatuses?.filter( cs => cs.type !== 'build') ?? [];
+ } else {
+ return context?.containerStatuses?.filter( cs => cs.type === 'build') ?? [];
+ }
+ }
+
+ return (
+ <div className="topology-toolbar">
+ <div className="group-switch">
+ <ProjectTitle/>
+ </div>
+ {additionalTools}
+ {context && !hideContainersToggle && <div>
+ <ToggleGroup aria-label="Default with single selectable">
+ {getContainers().map(status => (
+ <ToggleGroupItem
+ key={status.containerName}
+ icon={getIcon(status)}
+ text={status.containerName}
+ buttonId={status.containerName}
+ isSelected={selectedContainerName === status.containerName}
+ onChange={_ => setSelectedContainerName(status.containerName)}
+ />
+ ))}
+ </ToggleGroup>
+ </div>
+ }
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainersContextProvider.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainersContextProvider.tsx
new file mode 100644
index 00000000..10370606
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContainersContextProvider.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import {useAppConfigStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ContainerStatus} from "@models/ProjectModels";
+import {Label, Tooltip} from "@patternfly/react-core";
+import {CogIcon, PackageIcon} from "@patternfly/react-icons";
+import DevIcon from "@patternfly/react-icons/dist/esm/icons/dev-icon";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+type ProjectContainersContextType = {
+ containerStatuses: ContainerStatus[]
+ packagedContainerStatuses: ContainerStatus[]
+ devModeContainerStatus?: ContainerStatus
+ devModeIsRunning: boolean;
+ packagedIsRunning: boolean;
+ buildIsRunning: boolean;
+ origin: string;
+ camelContext: any,
+ containersStatusIcons: React.ReactElement<any>,
+};
+
+export const ProjectContainersContext = React.createContext<ProjectContainersContextType | undefined>(undefined);
+
+type ProjectContainersContextEnvelopeProps = {
+ children: React.ReactNode
+};
+
+export function ProjectContainersContextProvider({children}: ProjectContainersContextEnvelopeProps) {
+
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const [project, camelStatuses] = useProjectStore((s) => [s.project, s.camelStatuses], shallow);
+ const {containers} = useContainerStatusesStore();
+
+ const containerStatuses = containers.filter(c => c.projectId === project?.projectId) || [];
+ const packagedContainerStatuses = containerStatuses.filter(c => c.type === 'packaged') || [];
+ const isProjectContainer = packagedContainerStatuses.length > 0;
+ const packagedIsRunning = isProjectContainer && (packagedContainerStatuses.filter(c => c.state === 'running').length === packagedContainerStatuses.length);
+
+ const devModeContainerStatus = containerStatuses.filter(c => c.type === 'devmode').at(0);
+ const devModeIsRunning = devModeContainerStatus?.state === 'running';
+
+ const buildContainerStatus = containerStatuses.filter(c => c.type === 'build').at(0);
+ const buildIsRunning = buildContainerStatus?.state === 'running';
+
+ const isKubernetes = config.infrastructure === 'kubernetes'
+
+ const runningContainer = devModeIsRunning ? devModeContainerStatus : packagedContainerStatuses.find(c => c.state === 'running');
+
+ const origin = 'http://' + (isKubernetes
+ ? runningContainer?.podId + ':8080'
+ : runningContainer?.containerName + ':8080'
+ );
+
+ const camelStatus = camelStatuses.filter(s => s.projectId === project.projectId).at(0);
+ const contextValue = camelStatus?.statuses?.filter(x => x.name === 'context').at(0);
+ const camelContext = contextValue ? JSON.parse(contextValue?.status || '') : {};
+
+ const isRunning = packagedIsRunning || devModeIsRunning;
+ const className = isRunning ? 'rotated-run' : ''
+ const tooltip = devModeIsRunning ? 'Running dev mode' : 'Running packaged'
+ const containersStatusIcons = (
+ <div style={{flex: 2, display: 'flex', flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center'}}>
+ {isRunning &&
+ <Tooltip content={tooltip} position='left'>
+ <Label variant='outline'>
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', gap: '3px'}}>
+ <CogIcon className={`${className} rotated-run-forward`}/>
+ {devModeIsRunning && <DevIcon className={className} width={32} height={32}/>}
+ {packagedIsRunning && <PackageIcon className={className} width={32} height={32}/>}
+ </div>
+ </Label>
+ </Tooltip>
+ }
+ </div>
+ )
+
+ return (
+ <ProjectContainersContext.Provider value={{containerStatuses, packagedContainerStatuses, devModeContainerStatus, devModeIsRunning, packagedIsRunning, origin, buildIsRunning, camelContext, containersStatusIcons}}>
+ {children}
+ </ProjectContainersContext.Provider>
+ );
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectContext.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContext.tsx
new file mode 100644
index 00000000..830f672d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectContext.tsx
@@ -0,0 +1,29 @@
+import React, {createContext, useContext} from 'react';
+import {ProjectFunctions, UseProjectHook} from './Project.types';
+
+const ProjectContext = createContext<ProjectFunctions | null>(null);
+
+export const useProjectFunctions = () => {
+ const context = useContext(ProjectContext);
+ if (context === null) {
+ throw new Error('UseProjectHook must be used within a ProjectProvider');
+ }
+ return context;
+};
+
+interface ProjectProviderProps {
+ children: React.ReactNode;
+ useProjectHook: UseProjectHook;
+}
+
+export const ProjectProvider: React.FC<ProjectProviderProps> = ({
+ children,
+ useProjectHook,
+ }) => {
+ const api = useProjectHook();
+ return (
+ <ProjectContext.Provider value={api}>
+ {children}
+ </ProjectContext.Provider>
+ );
+};
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.css b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.css
new file mode 100644
index 00000000..73fdc068
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.css
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+.karavan .project-page {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .project-page .scrollable-out {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.karavan .project-page .scrollable-in {
+ overflow: auto;
+ flex-shrink: unset;
+ flex-grow: 1;
+ margin-bottom: 100px;
+}
+
+.karavan .project-title {
+ flex: 1;
+ .pf-v6-l-flex.pf-m-column > * {
+ margin-bottom: 0;
+ }
+ .pf-v6-c-clipboard-copy {
+ width: fit-content;
+ .pf-v6-c-button {
+ padding: 0;
+ }
+ }
+}
+
+.karavan .project-page .tools-section {
+ border-bottom: 1px solid #eee;
+}
+
+.karavan .project-page .project-tabs {
+ background-color: white;
+}
+
+.karavan .project-page .description-align-center .pf-v6-c-description-list__group {
+ min-height: 30px;
+ align-items: center;
+}
+
+.karavan .project-page .pf-v6-c-tabs__link,
+.karavan .project-page .pf-m-link {
+ font-size: 14px;
+}
+
+.karavan .project-page .project-button {
+ width: 100px;
+}
+
+.karavan .project-page .badge-env-up {
+ background-color: rgb(56, 129, 47);
+ color: white;
+}
+
+.karavan .project-page .env-chart {
+ font-size: 18px;
+}
+
+.karavan .project-page .replicas-ready {
+ background-color: rgb(56, 129, 47);
+ color: white;
+}
+
+.karavan .project-page .health-up {
+ background-color: rgb(56, 129, 47);
+ color: white;
+}
+
+.karavan .project-page .project-properties .delete-cell {
+ padding: 0;
+ margin: 0;
+ min-width: 0;
+}
+.karavan .project-page .project-properties .delete-button {
+ padding: 0 0 0 0;
+ margin: 0 16px 0 0;
+}
+
+.karavan .project-page .pf-v6-c-label__icon {
+ height: 16px;
+}
+
+.karavan .project-page .pf-v6-c-label__icon svg {
+ height: 16px;
+}
+
+.karavan .project-page .badge {
+ font-size: 14px;
+ font-weight: 400;
+ padding: 4px 8px 4px 8px;
+ min-width: 70px;
+}
+
+.karavan .project-files-toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 16px 8px 16px;
+ position: relative;
+}
+
+.karavan .project-files-toolbar::before {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ content: "";
+ border-bottom: var(--pf-t--global--border--color--default) solid var(--pf-t--global--border--width--box--default);
+ border-radius: inherit;
+}
+
+.karavan .project-page .runtime-tab {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px;
+ gap: 16px;
+
+ .runtime-element {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ }
+}
+
+.karavan .project-page-navigation {
+ gap: 16px;
+ .pf-v6-c-nav__link {
+ align-items: center;
+ .pf-v6-c-nav__link-icon {
+ display: flex;
+ align-items: center;
+ /*width: 20px;*/
+ /*height: 20px;*/
+ }
+ }
+
+ .jvm-svg-steam-on {
+ height: 20px;
+ width: 20px;
+ filter: brightness(1.3) contrast(1.3) saturate(2) drop-shadow(0 0 6px #4cc3ff);
+ .steam {
+ fill: #FF8C26;
+ transform-origin: center;
+ animation: steam-movement 4s infinite, /* Combined scale and translate */ steam-opacity 4s infinite; /* Opacity */
+ }
+ }
+
+ .jvm-svg-steam-off {
+ height: 20px;
+ width: 20px;
+ filter: brightness(2) saturate(0);
+ animation: none !important;
+ }
+ .k8s {
+ height: 20px;
+ width: 20px;
+ }
+
+ .camel-paused {
+ filter: saturate(0);
+ }
+
+ .rotated-run {
+ width: 16px;
+ height: 16px;
+ color: var(--pf-t--color--green--40);
+ /*animation: icon-flashing 1.5s linear infinite;*/
+ }
+ .rotated-run-forward {
+ animation: rotate-icon-forward 1.5s linear infinite
+ }
+
+ .rotated-run-backward {
+ animation: rotate-icon-backward 1.5s linear infinite,
+ icon-flashing 1.5s linear infinite
+ }
+
+ .containers-run {
+ color: var(--pf-t--global--color--status--success--100);
+ animation: icon-flashing 1.5s linear infinite,
+ scale-icon 1.5s linear infinite;
+ }
+}
+
+@keyframes icon-flashing {
+ 0% {
+ color: var(--pf-t--color--green--20);
+ border-color: var(--pf-t--global--color--status--success--100);
+ }
+ 50% {
+ color: var(--pf-t--color--green--40);
+ border-color: var(--pf-t--global--color--status--success--200);
+ }
+ 100% {
+ color: var(--pf-t--color--green--60);
+ border-color: var(--pf-t--global--icon--color--status--success--default);
+ }
+}
+
+@keyframes scale-icon {
+ from {
+ transform: scale(1);
+ }
+ to {
+ transform: scale(1.1);
+ }
+}
+
+@keyframes rotate-icon-forward {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+@keyframes rotate-icon-backward {
+ from {
+ transform: rotate(360deg);
+ }
+ to {
+ transform: rotate(0deg);
+ }
+}
+
+@keyframes logline {
+ 0% { opacity: 0; transform: translateX(-2px); }
+ 20% { opacity: 1; transform: translateX(0); }
+ 80% { opacity: 1; }
+ 100% { opacity: 0; }
+}
+
+@keyframes steam-movement {
+ 0% {
+ transform: translate(0, 0) scale(1, 1);
+ }
+ 25% {
+ transform: translate(0.5px, -1.5px) scale(1.1, 1.3);
+ }
+ 50% {
+ transform: translate(-0.3px, -2.2px) scale(0.95, 1.1);
+ }
+ 75% {
+ transform: translate(0.1px, -3px) scale(1.25, 1.15);
+ }
+ 100% {
+ transform: translate(0, 0) scale(1, 1);
+ }
+}
+
+@keyframes steam-opacity {
+ 0% { opacity: 0.7; }
+ 25% { opacity: 1; }
+ 50% { opacity: 0.85; }
+ 75% { opacity: 1; }
+ 100% { opacity: 0.7; }
+}
+
+.popover-file-validation {
+ max-width: 33%;
+ .pf-v6-c-popover__content {
+ padding-right: 0;
+
+ .pf-v6-c-popover__body {
+ max-height: 50vh;
+ overflow-y: auto;
+
+ .pf-v6-c-alert {
+ border-width: 1px;
+ padding: 6px;
+ }
+ }
+
+ .pf-v6-c-popover__body > div {
+ height: 100%; /* Make the inner div fill the body's space */
+ display: flex; /* Keep original display properties for inner layout */
+ flex-direction: column;
+ }
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.tsx
new file mode 100644
index 00000000..3ccb9294
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPage.tsx
@@ -0,0 +1,107 @@
+/*
+ * 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, {JSX, useEffect, useState} from 'react';
+import './ProjectPage.css';
+import {shallow} from "zustand/shallow";
+import {useNavigate, useParams} from "react-router-dom";
+import {useFilesStore, useFileStore, useProjectsStore, useProjectStore} from '@stores/ProjectStore';
+import {BUILD_IN_PROJECTS, Project} from '@models/ProjectModels';
+import {RightPanel} from "@shared/ui/RightPanel";
+import {ROUTES} from "@app/navigation/Routes";
+import {useProjectFunctions} from './ProjectContext';
+import {ProjectPageNavigation} from "@features/project/ProjectPageNavigation";
+import {ProjectContainersContextProvider} from "@features/project/ProjectContainersContextProvider";
+import {Content} from "@patternfly/react-core";
+import {ProjectToolbar} from "@features/project/toolbar/ProjectToolbar";
+import {ProjectPanel} from "@features/project/ProjectPanel";
+import {useDataPolling} from "@shared/polling/useDataPolling";
+
+interface ProjectPageProps {
+ developerManager: JSX.Element;
+}
+
+function ProjectPage(props: ProjectPageProps): JSX.Element {
+
+ const {developerManager} = props;
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [projects] = useProjectsStore((state) => [state.projects], shallow)
+ const [project, setProject, tabIndex, setTabIndex, refreshTrace] =
+ useProjectStore((s) => [s.project, s.setProject, s.tabIndex, s.setTabIndex, s.refreshTrace], shallow);
+ const [file, operation, setFile] = useFileStore((s) => [s.file, s.operation, s.setFile], shallow);
+ const showFilePanel = file !== undefined && operation === 'select';
+ const [urlFileName, setUrlFileName] = useState<string>();
+ const {refreshData} = useProjectFunctions();
+
+ useDataPolling('ProjectPage', refreshData, 3000, [tabIndex, refreshTrace, project]);
+
+ let {projectId, fileName} = useParams();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ setUrlFileName(fileName)
+ window.history.replaceState({}, "", `${ROUTES.PROJECTS}/${projectId}`);
+ const p = projects.filter(project => project.projectId === projectId).at(0);
+ if (p) {
+ setProject(p, "select");
+ if (!BUILD_IN_PROJECTS.includes(p.projectId)) {
+ setTabIndex('topology');
+ }
+ } else {
+ navigate('/');
+ }
+ return () => {
+ setProject(new Project(), "none");
+ setTabIndex('topology');
+ }
+ }, []);
+
+ useEffect(() => {
+ if (urlFileName !== undefined) {
+ const file = files
+ .filter(f => f.projectId === projectId && f.name === urlFileName)?.at(0);
+ if (file) {
+ setFile('select', file);
+ setTabIndex('topology');
+ setUrlFileName(undefined);
+ }
+ }
+ }, [files]);
+
+ function title() {
+ return (<Content component="h2">Integration</Content>)
+ }
+
+ return (
+ <RightPanel
+ title={title()}
+ toolsStart={
+ <ProjectContainersContextProvider>
+ <ProjectPageNavigation/>
+ </ProjectContainersContextProvider>
+ }
+ tools={<ProjectToolbar/>}
+ mainPanel={
+ <div className="right-panel-card">
+ {showFilePanel && developerManager}
+ {!showFilePanel && <ProjectPanel/>}
+ </div>
+ }
+ />
+ )
+}
+
+export default ProjectPage
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectPageNavigation.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPageNavigation.tsx
new file mode 100644
index 00000000..731b0985
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPageNavigation.tsx
@@ -0,0 +1,179 @@
+/*
+ * 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, {JSX, useEffect, useState} from 'react';
+import {capitalize, Nav, NavItem, NavList,} from '@patternfly/react-core';
+import '@features/project/ProjectPage.css';
+import {
+ ProjectMenu,
+ ProjectMenus,
+ ProjectRuntimeMenu,
+ ProjectRuntimeMenus,
+ useAppConfigStore,
+ useFilesStore,
+ useFileStore,
+ useProjectStore,
+ useSelectedContainerStore
+} from '@stores/ProjectStore';
+import {BUILD_IN_PROJECTS} from '@models/ProjectModels';
+import {ProjectContainersContext} from "@features/project/ProjectContainersContextProvider";
+import {SvgIcon} from "@shared/icons/SvgIcon";
+import BuildIcon from "@patternfly/react-icons/dist/esm/icons/build-icon";
+import {shallow} from "zustand/shallow";
+import {useIntegrationStore} from "@features/project/designer/DesignerStore";
+import {KubernetesIcon} from "@features/project/designer/icons/ComponentIcons";
+
+export function ProjectPageNavigation(): JSX.Element {
+
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const isKubernetes = config.infrastructure === 'kubernetes'
+ const context = React.useContext(ProjectContainersContext);
+ if (!context) throw new Error("ProjectContainersContext not found!");
+
+ const [selectedContainerName, setSelectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName, s.setSelectedContainerName]);
+
+ const {devModeIsRunning, packagedIsRunning, buildIsRunning, containerStatuses, devModeContainerStatus, camelContext, containersStatusIcons} = context;
+ const hasContainers = containerStatuses?.length > 0;
+ const devContainer = containerStatuses.filter(c => c.type === 'devmode')?.at(0)
+ const hasDevmodeContainers = devContainer !== undefined;
+ const buildContainer = containerStatuses.filter(c => c.type === 'build')?.at(0)
+ const hasBuildContainers = buildContainer !== undefined;
+
+ const [files] = useFilesStore((s) => [s.files]);
+ const [project, tabIndex, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex]);
+ const [setFile, file] = useFileStore((s) => [s.setFile, s.file]);
+ const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+
+ const [buildContainerId, setBuildContainerId] = useState<string>('');
+ const [hasDevMode, setHasDevMode] = useState<boolean>(false);
+
+ useEffect(() => {
+ selectName();
+ }, [tabIndex, hasDevmodeContainers, hasBuildContainers, buildContainer?.containerId, buildContainerId])
+
+ function selectName() {
+ const selectedContainers = containerStatuses.filter(c => c.containerName === selectedContainerName) || [];
+ const names = containerStatuses
+ ?.filter(cs => {
+ if (tabIndex === "build") {
+ return cs.type === 'build'
+ } else {
+ return ['devmode', 'packaged'].includes(cs.type)
+ }
+ })
+ ?.map(cs => cs.containerName);
+ const name = names?.at(0);
+ if (tabIndex === "build" && buildContainer?.containerId && buildContainerId !== buildContainer?.containerId) {
+ setSelectedContainerName(undefined);
+ setBuildContainerId(buildContainer?.containerId);
+ } else if (tabIndex === "build" && buildContainerId === buildContainer?.containerId && selectedContainerName === undefined) {
+ setSelectedContainerName(buildContainer.containerName);
+ } else if (!hasDevmodeContainers && hasDevMode) {
+ setHasDevMode(false);
+ setTabIndex(0);
+ setSelectedContainerName(undefined);
+ } else if (hasDevmodeContainers && !hasDevMode) {
+ setHasDevMode(true);
+ setTabIndex('log');
+ setSelectedContainerName(devModeContainerStatus?.containerName);
+ } else if (selectedContainers.length === 0 && selectedContainerName !== undefined) {
+ setSelectedContainerName(undefined);
+ } else if (selectedContainerName === undefined || !names?.includes(selectedContainerName) && name) {
+ setSelectedContainerName(name);
+ } else if (!names?.includes(selectedContainerName)) {
+ setSelectedContainerName(undefined);
+ }
+ }
+
+ function isBuildIn(): boolean {
+ return BUILD_IN_PROJECTS.includes(project?.projectId);
+ }
+
+ function hasReadme(): boolean {
+ return files.map(f => f.name).findIndex(f => f.toLowerCase() === 'readme.md') !== -1;
+ }
+
+ const onNavSelect = (_: any, selectedItem: {
+ groupId: number | string;
+ itemId: number | string;
+ to: string;
+ }
+ ) => {
+ setTabIndex(selectedItem.itemId as ProjectMenu);
+ setFile('none', undefined);
+ };
+
+ function getProjectMenu(): ProjectMenu[] {
+ let menu: ProjectMenu[] = []
+ if (isBuildIn()) {
+ menu.push('source');
+ } else {
+ menu.push(...ProjectMenus);
+ }
+ if (!hasReadme()) {
+ menu = menu.filter(m => m !== 'readme')
+ }
+ return menu;
+ }
+
+ function getProjectRuntimeMenusMenu(): ProjectRuntimeMenu[] {
+ const menus = isKubernetes ? ProjectRuntimeMenus : ProjectRuntimeMenus.filter(m => m !== 'pod');
+ let menu: (ProjectRuntimeMenu)[] = []
+ if ((devModeIsRunning || packagedIsRunning || devModeContainerStatus) && tabIndex !== "build") {
+ menu.push(...menus);
+ }
+ return menu;
+ }
+
+ function getIcon(item: ProjectRuntimeMenu | ProjectMenu) {
+ const isRunning = packagedIsRunning || devModeIsRunning;
+ if (item === 'log') {
+ const className = isRunning ? 'log-on' : 'log-off'
+ return <SvgIcon icon='log' className={className}/>
+ } else if (item === 'build' && hasBuildContainers) {
+ const className = buildIsRunning ? 'containers-run' : ''
+ return <BuildIcon className={className}/>
+ } else if (item === 'pod') {
+ return KubernetesIcon("k8s")
+ }
+ }
+
+ const projectRuntimeMenus = getProjectRuntimeMenusMenu();
+ return (
+ <Nav onSelect={onNavSelect} aria-label="Nav1" variant="horizontal" className="project-page-navigation">
+ <NavList>
+ {getProjectMenu().map((item, i) =>
+ <NavItem icon={getIcon(item)} key={item} preventDefault itemId={item} isActive={tabIndex === item} to="#">
+ {capitalize(item)}
+ </NavItem>
+ )}
+ </NavList>
+ {containersStatusIcons}
+ {projectRuntimeMenus.length > 0 &&
+ <NavList>
+ {getProjectRuntimeMenusMenu().map((item, i) => {
+ return (
+ <NavItem icon={getIcon(item)} key={item} preventDefault itemId={item} isActive={tabIndex === item} to="#">
+ {capitalize(item)}
+ </NavItem>
+ )
+ }
+ )}
+ </NavList>
+ }
+ </Nav>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPanel.tsx
new file mode 100644
index 00000000..df2e0954
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectPanel.tsx
@@ -0,0 +1,86 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {shallow} from "zustand/shallow";
+import {useFilesStore, useProjectStore} from '@stores/ProjectStore';
+import {useSelectorStore} from '@features/project/designer/DesignerStore';
+import {ProjectService} from '@services/ProjectService';
+import {BUILD_IN_PROJECTS, ProjectType} from '@models/ProjectModels';
+import {TopologyTab} from '@features/project/project-topology/TopologyTab';
+import {CreateProjectModal} from '@features/project/files/CreateProjectModal';
+import {DslSelector} from '@features/project/designer/selector/DslSelector';
+import {BeanWizard} from '@features/project/beans/BeanWizard';
+import {BuildTab} from '@features/project/project-build/BuildTab';
+import {ReadmeTab} from "@features/project/readme/ReadmeTab";
+import {SourcesTab} from '@features/project/files/SourcesTab';
+import {useProjectFunctions} from "@features/project/ProjectContext";
+import {ContainerLogTab} from "@features/project/ContainerLogTab";
+import {ProjectContainersContextProvider} from "@features/project/ProjectContainersContextProvider";
+import {ContainersTab} from "@features/project/project-containers/ContainersTab";
+import {PodTab} from "@features/project/project-pod/PodTab";
+
+export function ProjectPanel() {
+
+ const [project, tab, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex], shallow);
+ const [setFiles, setSelectedFileNames] = useFilesStore((s) => [s.setFiles, s.setSelectedFileNames], shallow);
+ const [showSelector] = useSelectorStore((s) => [s.showSelector], shallow)
+ const [asyncApiJson] = useState<string>('');
+
+ const {createNewRouteFile, refreshSharedData} = useProjectFunctions();
+
+ useEffect(() => {
+ onRefresh();
+ }, [project]);
+
+ function onRefresh() {
+ if (project?.projectId) {
+ setFiles([]);
+ setSelectedFileNames([]);
+ ProjectService.refreshProjectData(project.projectId);
+ setTabIndex(project.type !== ProjectType.integration ? 'source' : tab);
+ refreshSharedData();
+ }
+ }
+
+ function isBuildIn(): boolean {
+ return BUILD_IN_PROJECTS.includes(project.projectId);
+ }
+
+ const buildIn = isBuildIn();
+ const isTopology = tab === 'topology';
+
+ return isTopology
+ ? (<>
+ <TopologyTab asyncApiJson={asyncApiJson}/>
+ <CreateProjectModal/>
+ {showSelector && <DslSelector onDslSelect={createNewRouteFile} showFileNameInput={true}/>}
+ <BeanWizard/>
+ </>
+ )
+ : (
+ <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
+ {tab === 'source' && <SourcesTab/>}
+ {!buildIn && tab === "build" && <BuildTab/>}
+ {/*{!buildIn && tab === "build" && config.infrastructure !== 'kubernetes' && <ImagesPanel/>}*/}
+ {!buildIn && tab === 'readme' && <ReadmeTab/>}
+ {!buildIn && tab === 'pod' && <ProjectContainersContextProvider><PodTab/></ProjectContainersContextProvider>}
+ {!buildIn && tab === 'log' && <ProjectContainersContextProvider><ContainerLogTab/></ProjectContainersContextProvider>}
+ {!buildIn && tab === 'containers' && <ProjectContainersContextProvider><ContainersTab/></ProjectContainersContextProvider>}
+ </div>
+ )
+}
+
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/ProjectTitle.tsx b/karavan-app/src/main/webui/src/karavan/features/project/ProjectTitle.tsx
new file mode 100644
index 00000000..0d8ad297
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/ProjectTitle.tsx
@@ -0,0 +1,69 @@
+/*
+ * 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 {ClipboardCopy, Content, Flex, FlexItem,} from '@patternfly/react-core';
+import {useFileStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+
+export function ProjectTitle() {
+
+ const [project, tabIndex, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex], shallow);
+ const [file, setFile, operation] = useFileStore((s) => [s.file, s.setFile, s.operation], shallow);
+
+ const isFile = file !== undefined && operation !== 'delete';
+ const isLog = file !== undefined && file.name.endsWith("log");
+ const filename = file ? file.name.substring(0, file.name.lastIndexOf('.')) : "";
+
+ function getProjectTitle() {
+ return (
+ <Flex direction={{default: "column"}} gap={{default: 'gapNone'}}>
+ <FlexItem>
+ <Content component="h3">{project?.name}</Content>
+ </FlexItem>
+ <FlexItem>
+ <ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact">
+ {project?.projectId}
+ </ClipboardCopy>
+ </FlexItem>
+ </Flex>
+ )
+ }
+
+ function getFileTitle() {
+ return (isFile ?
+ <Flex direction={{default: "column"}} gap={{default: 'gapNone'}}>
+ <FlexItem>
+ <Content component="h3">{project?.name}</Content>
+ </FlexItem>
+ <FlexItem>
+ <ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact">
+ {isLog ? filename : file.name}
+ </ClipboardCopy>
+ </FlexItem>
+ </Flex>
+ : <></>
+ )
+ }
+
+ return (
+ <div className="dsl-title project-title">
+ {isFile && getFileTitle()}
+ {!isFile && getProjectTitle()}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/RenameFileModal.tsx b/karavan-app/src/main/webui/src/karavan/features/project/RenameFileModal.tsx
new file mode 100644
index 00000000..8aec9807
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/RenameFileModal.tsx
@@ -0,0 +1,110 @@
+/*
+ * 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, {useEffect} from 'react';
+import {Button, Form, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant} from '@patternfly/react-core';
+import {useFileStore, useProjectStore} from "@stores/ProjectStore";
+import {RESERVED_WORDS} from "@models/ProjectModels";
+import {shallow} from "zustand/shallow";
+import {SubmitHandler, useForm} from "react-hook-form";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {isValidFileName} from "@util/StringUtils";
+import {useFormUtil} from "@util/useFormUtil";
+import {KaravanApi} from "@api/KaravanApi";
+
+type FormValues = {
+ newName: string;
+};
+
+interface RenameFileModalProps {
+ show: boolean,
+ onRename: () => void
+ onClose: () => void
+}
+
+export function RenameFileModal({show, onClose, onRename}: RenameFileModalProps) {
+
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const [file] = useFileStore((s) => [s.file], shallow);
+ const formContext = useForm<FormValues>({
+ mode: "onChange",
+ defaultValues: { newName: file?.name },
+ });
+ const {getTextField} = useFormUtil(formContext);
+ const {
+ register,
+ handleSubmit,
+ formState: { errors, isSubmitting },
+ reset,
+ } = formContext;
+
+ useEffect(() => {
+ reset({ newName: file?.name || "" });
+ }, [file, reset]);
+
+ function closeModal() {
+ onClose();
+ }
+
+ const onSubmit: SubmitHandler<FormValues> = (data) => {
+ if (file) {
+ KaravanApi.renameProjectFile(project.projectId, file?.name, data.newName, (result: boolean, err?: Error | undefined) => {
+ if (result) {
+ onRename();
+ } else {
+ EventBus.sendAlert("Error", err?.message ?? "Error copying file!", "warning");
+ }
+ })
+ }
+ }
+
+ function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>): void {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ event.stopPropagation();
+ handleSubmit(onSubmit)();
+ }
+ }
+
+ return (
+ <Modal
+ variant={ModalVariant.small}
+ isOpen={show}
+ onClose={closeModal}
+ onKeyDown={onKeyDown}
+ >
+ <ModalHeader title='Rename file'/>
+ <ModalBody>
+ <Form autoComplete="off" isHorizontal className="create-file-form">
+ {getTextField('newName', 'Name', {
+ regex: v => isValidFileName(v) || 'Not a valid filename',
+ length: v => v.length > 5 || 'File name should be longer that 5 characters',
+ name: v => !(RESERVED_WORDS.concat(file?.name ?? '')).includes(v) || "Reserved word",
+ })}
+ </Form>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary" onClick={handleSubmit(onSubmit)}
+ isDisabled={Object.getOwnPropertyNames(errors).length > 0}
+ >
+ Save
+ </Button>
+ <Button key="cancel" variant="secondary" onClick={closeModal}>Cancel</Button>
+ </ModalFooter>
+ </Modal>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/devmode.css b/karavan-app/src/main/webui/src/karavan/features/project/devmode.css
new file mode 100644
index 00000000..c863d05a
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/devmode.css
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+
+.karavan .refresher {
+ width: 34px;
+ height: 34px;
+}
+
+.karavan .refresher .spinner {
+ position: absolute;
+ width: 34px;
+ height: 34px;
+}
+
+.karavan .refresher .button {
+ position: absolute;
+ width: 34px;
+ height: 34px;
+ padding: 0;
+ font-size: 16px;
+}
+
+.karavan .refresher .button .pf-v6-c-button__icon {
+ margin: 0;
+}
+
+.karavan .main-toolbar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+}
+
+.karavan .main-toolbar .main-run-button .pf-v6-svg {
+ margin-right: 5px;
+}
+
+.karavan .main-toolbar .main-run-dropdown-toggle .pf-v6-c-menu-toggle__button:last-child {
+ padding-left: 0;
+ padding-right: 0;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-build/BuildTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-build/BuildTab.tsx
new file mode 100644
index 00000000..f885ee79
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-build/BuildTab.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 '@features/project/designer/karavan.css';
+import {ContainerLogTab} from "@features/project/ContainerLogTab";
+import {ProjectContainersContextProvider} from "@features/project/ProjectContainersContextProvider";
+
+export function BuildTab () {
+
+ return (
+ <div style={{display: 'flex', flexDirection: 'column', height: "100%", gap: '16px'}}>
+ <ProjectContainersContextProvider>
+ <ContainerLogTab/>
+ </ProjectContainersContextProvider>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerButtons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerButtons.tsx
new file mode 100644
index 00000000..e01e33fc
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerButtons.tsx
@@ -0,0 +1,149 @@
+/*
+ * 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, {useState} from 'react';
+import {Button, Modal, ModalBody, ModalFooter, ModalHeader, Spinner, Switch, Tooltip, TooltipPosition} from '@patternfly/react-core';
+import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon";
+import StopIcon from "@patternfly/react-icons/dist/esm/icons/stop-icon";
+import DeployIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
+import {useDevModeStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import RunIcon from "@patternfly/react-icons/dist/esm/icons/play-icon";
+import {KaravanApi} from "@api/KaravanApi";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+export function ContainerButtons() {
+
+ const [status] = useDevModeStore((state) => [state.status], shallow)
+ const [project] = useProjectStore((state) => [state.project], shallow)
+ const {containers} = useContainerStatusesStore();
+
+ const [pullImage, setPullImage] = useState<boolean>(false);
+ const [showConfirmation, setShowConfirmation] = useState<boolean>(false);
+ const [actionType, setActionType] = useState<'deploy' | 'run' | 'stop' | 'delete'>('run');
+
+ const containerStatus = containers.filter(c => c.containerName === project.projectId).at(0);
+ const commands = containerStatus?.commands || ['deploy'];
+ const isRunning = containerStatus?.state === 'running';
+ const inTransit = containerStatus?.inTransit;
+ const isLoading = status === 'wip';
+
+ function act() {
+ KaravanApi.manageContainer(project.projectId, 'packaged', project.projectId, actionType, pullImage ? 'always' : 'never', res => {
+ const response = res?.response;
+ if (response?.status === 500) {
+ EventBus.sendAlert('Error', response.data !== undefined && response.data.length > 0 ? response.data : response.statusText, 'warning')
+ }
+ });
+ }
+
+ function getConfirmationModal() {
+ return (
+ <Modal
+ variant='small'
+ isOpen={showConfirmation}
+ onClose={() => setShowConfirmation(false)}
+ onEscapePress={e => setShowConfirmation(false)}>
+ <ModalHeader title='Confirmation'/>
+ <ModalBody>
+ <div>{"Confirm " + actionType + " container?"}</div>
+ {actionType === 'deploy' && <div>
+ <Switch
+ label="Pull image"
+ isChecked={pullImage}
+ onChange={(_, checked) => setPullImage(checked)}
+ isReversed
+ />
+ </div>}
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary" onClick={e => {
+ if (actionType && project.projectId) {
+ act();
+ setShowConfirmation(false);
+ }
+ }}>Confirm
+ </Button>
+ <Button key="cancel" variant="link"
+ onClick={e => setShowConfirmation(false)}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ return (
+ <div style={{flex: '2', display: 'flex', flexDirection: 'row', justifyContent: 'end', alignItems: 'center', gap: '6px'}}>
+ <div>
+ {(inTransit || isLoading) && <Spinner size="lg" aria-label="spinner"/>}
+ </div>
+ <div>
+ <Tooltip content="Deploy container" position={TooltipPosition.bottom}>
+ <Button className="dev-action-button"
+ isDisabled={(!(commands.length === 0) && !commands.includes('deploy')) || inTransit}
+ variant={"primary"}
+ icon={<DeployIcon/>}
+ onClick={() => {
+ setActionType('deploy');
+ setShowConfirmation(true);
+ }}>Deploy</Button>
+ </Tooltip>
+ </div>
+ <div>
+ <Tooltip content="Run container" position={TooltipPosition.bottom}>
+ <Button className="dev-action-button"
+ isDisabled={(!(commands.length === 0) && !commands.includes('run')) || inTransit}
+ variant={"primary"}
+ icon={<RunIcon/>}
+ onClick={() => {
+ setActionType('run');
+ setShowConfirmation(true);
+ }}>
+ Run
+ </Button>
+ </Tooltip>
+ </div>
+ <div>
+ <Tooltip content="Stop container" position={TooltipPosition.bottom}>
+ <Button className="dev-action-button"
+ isDisabled={!commands.includes('stop') || inTransit}
+ variant={"control"}
+ icon={<StopIcon/>}
+ onClick={() => {
+ setActionType('stop');
+ setShowConfirmation(true);
+ }}>
+ Stop
+ </Button>
+ </Tooltip>
+ </div>
+ <div>
+ <Tooltip content="Delete container" position={TooltipPosition.bottom}>
+ <Button className="dev-action-button"
+ isDisabled={!commands.includes('delete') || inTransit}
+ variant={"control"}
+ icon={<DeleteIcon/>}
+ onClick={() => {
+ setActionType('delete');
+ setShowConfirmation(true);
+ }}>
+ Delete
+ </Button>
+ </Tooltip>
+ </div>
+ {showConfirmation && getConfirmationModal()}
+ </div>);
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerEnvironmentPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerEnvironmentPanel.tsx
new file mode 100644
index 00000000..4c24f929
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainerEnvironmentPanel.tsx
@@ -0,0 +1,116 @@
+/*
+ * 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, {useState} from 'react';
+import {Button, ClipboardCopy, Flex, FlexItem, Label} from '@patternfly/react-core';
+
+import '@features/project/designer/karavan.css';
+import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import {useAppConfigStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ContainerStatus} from "@models/ProjectModels";
+import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon";
+import ImageIcon from "@patternfly/react-icons/dist/esm/icons/cube-icon";
+import {KaravanApi} from "@api/KaravanApi";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ContainerButton} from "@shared/ui/ContainerButton";
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+interface Props {
+ env: string,
+}
+
+export function ContainerEnvironmentPanel(props: Props) {
+
+ const {config} = useAppConfigStore();
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const {containers} = useContainerStatusesStore();
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+ const [deleteEntityName, setDeleteEntityName] = useState<string>();
+
+ function deleteEntity() {
+ if (deleteEntityName) {
+ KaravanApi.stopBuild('dev', deleteEntityName, (res: any) => {
+ if (res.status === 200) {
+ EventBus.sendAlert("Container deleted", "Container deleted: " + deleteEntityName, 'info');
+ }
+ });
+ }
+ }
+
+ function getStatusBadge(cs: ContainerStatus) {
+ return isKubernetes ? cs.phase : cs.state
+ }
+
+ const env = props.env;
+ const conts = containers
+ .filter(c => c.env === env)
+ .filter(d => d.projectId === project?.projectId && d.type === 'packaged');
+
+ const isKubernetes = config.infrastructure === 'kubernetes';
+ const noContainersText = isKubernetes ? 'No pods' : 'No containers';
+
+ return (
+ <Flex justifyContent={{default: "justifyContentSpaceBetween"}}
+ alignItems={{default: "alignItemsFlexStart"}}>
+ <FlexItem>
+ {conts.length === 0 && <Label icon={<DownIcon/>} color={"grey"}>{noContainersText}</Label>}
+ <Flex direction={{default: 'column'}}>
+ {conts.map((cs: ContainerStatus, index) => {
+ const ready = cs.state === 'running';
+ return (
+ <div style={{display: 'flex', gap: '8px'}} key={index}>
+ <ContainerButton container={cs}/>
+ <Label icon={<ImageIcon/>} color={ready ? "green" : "grey"} variant='outline'>
+ Image:
+ <ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact" style={{backgroundColor: 'transparent'}}>
+ {cs.image}
+ </ClipboardCopy>
+ </Label>
+ {isKubernetes && <Button
+ isDanger
+ icon={<DeleteIcon/>}
+ className="karavan-labeled-button"
+ variant="link" onClick={e => {
+ setShowDeleteConfirmation(true);
+ setDeleteEntityName(cs.containerName);
+ }}></Button>}
+ </div>
+ )
+ }
+ )}
+ </Flex>
+ </FlexItem>
+ {showDeleteConfirmation &&
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message={"Delete container " + deleteEntityName + "?"}
+ btnConfirm='Delete'
+ btnConfirmVariant='danger'
+ onConfirm={() => {
+ if (deleteEntityName) {
+ deleteEntity();
+ setShowDeleteConfirmation(false);
+ }
+ }}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ }
+ </Flex>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTab.tsx
new file mode 100644
index 00000000..30d359b1
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTab.tsx
@@ -0,0 +1,25 @@
+import React, {ReactElement} from 'react';
+import {Content, Divider} from "@patternfly/react-core";
+import {useAppConfigStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ProjectContainerContextToolbar} from "@features/project/ProjectContainerContextToolbar";
+import {ContainersTable} from "@features/project/project-containers/ContainersTable";
+import {ContainersToolbar} from "@features/project/project-containers/ContainersToolbar";
+import {ImagesPanel} from "@features/project/project-containers/ImagesPanel";
+
+export function ContainersTab(): ReactElement {
+
+ const [config] = useAppConfigStore((state) => [state.config], shallow)
+ const isKubernetes = (config.infrastructure === 'kubernetes')
+
+ return (
+ <div className="project-page">
+ <ProjectContainerContextToolbar additionalTools={<ContainersToolbar/>} hideContainersToggle={true}/>
+ <Content component='h6' style={{padding: '16px'}}>Containers</Content>
+ <Divider/>
+ <ContainersTable/>
+ <Divider/>
+ {!isKubernetes && <ImagesPanel/>}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTable.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTable.tsx
new file mode 100644
index 00000000..dd0b3d8f
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTable.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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 {InnerScrollContainer, OuterScrollContainer, Table, Tbody, Th, Thead, Tr} from "@patternfly/react-table";
+import {useSelectedContainerStore} from "@stores/ProjectStore";
+import {ProjectContainersContext} from "@features/project/ProjectContainersContextProvider";
+import {ContainersTableRow} from "@features/project/project-containers/ContainersTableRow";
+
+export function ContainersTable() {
+
+ const [selectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName]);
+ const context = React.useContext(ProjectContainersContext);
+ if (!context) throw new Error("ProjectContainersContext not found!");
+ const {containerStatuses} = context;
+
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table aria-label="Simple table" height={"100vh"} variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th>Name</Th>
+ <Th>Type</Th>
+ <Th>Created</Th>
+ <Th>Image</Th>
+ <Th>CPU</Th>
+ <Th>Memory</Th>
+ </Tr>
+ </Thead>
+ <Tbody className='event-table'>
+ {containerStatuses.map((containerStatus, index) => (
+ <ContainersTableRow containerStatus={containerStatus} index={index}/>
+ ))}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ );
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTableRow.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTableRow.tsx
new file mode 100644
index 00000000..586dfc6d
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersTableRow.tsx
@@ -0,0 +1,73 @@
+/*
+ * 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, Label,} from '@patternfly/react-core';
+import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import {ContainerStatus} from "@models/ProjectModels";
+import {Td, Tr} from "@patternfly/react-table";
+
+interface Props {
+ containerStatus: ContainerStatus,
+ index: number,
+}
+
+export function ContainersTableRow(props: Props) {
+
+ const {containerStatus, index} = props;
+
+ function getPodInfoLabel(info: React.ReactNode) {
+ return (
+ <Label icon={getIcon()} color={getColor()}>
+ {info}
+ </Label>
+ )
+ }
+
+ function getIcon() {
+ return (getRunning() ? <UpIcon/> : <DownIcon/>)
+ }
+
+ function getColor() {
+ return getRunning() ? "green" : "grey";
+ }
+
+ function getRunning(): boolean {
+ return props.containerStatus.state === 'running';
+ }
+
+ return (
+ <Tr key={index} style={{verticalAlign: "middle"}}>
+ <Td>
+ {getPodInfoLabel(
+ <>
+ {containerStatus.containerName}
+ <Badge isRead>{containerStatus.type}</Badge>
+ </>
+ )}
+ </Td>
+ <Td>
+ {getPodInfoLabel(containerStatus.state)}
+ </Td>
+ <Td>{(containerStatus.created)}</Td>
+ <Td>{containerStatus.image}</Td>
+ <Td>{(containerStatus.cpuInfo)}</Td>
+ <Td>{(containerStatus.memoryInfo)}</Td>
+ </Tr>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersToolbar.tsx
new file mode 100644
index 00000000..f4ac3d6e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ContainersToolbar.tsx
@@ -0,0 +1,34 @@
+/*
+ * 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 {useAppConfigStore} from "@stores/ProjectStore";
+import {ContainerButtons} from "./ContainerButtons";
+import {DeploymentButtons} from "./DeploymentButtons";
+
+export function ContainersToolbar() {
+
+ const {config} = useAppConfigStore();
+ const env = config.environment;
+
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', alignItems: 'center', gap: '8px'}}>
+ {env === config.environment && config.infrastructure !== 'kubernetes' && <ContainerButtons/>}
+ {env === config.environment && config.infrastructure === 'kubernetes' && <DeploymentButtons env={env}/>}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentButtons.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentButtons.tsx
new file mode 100644
index 00000000..9210d732
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentButtons.tsx
@@ -0,0 +1,164 @@
+/*
+ * 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, {useState} from 'react';
+import {Button,} from '@patternfly/react-core';
+
+import '@features/project/designer/karavan.css';
+import {useProjectStore, useStatusesStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import RolloutIcon from "@patternfly/react-icons/dist/esm/icons/process-automation-icon";
+import DeployIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
+import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon";
+import {KaravanApi} from "@api/KaravanApi";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+
+interface Props {
+ env: string,
+}
+
+export function DeploymentButtons (props: Props) {
+
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const [deployments] = useStatusesStore((s) => [s.deployments], shallow);
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+ const [showDeployConfirmation, setShowDeployConfirmation] = useState<boolean>(false);
+ const [showRolloutConfirmation, setShowRolloutConfirmation] = useState<boolean>(false);
+
+ function deleteDeployment() {
+ if (project.projectId) {
+ KaravanApi.deleteDeployment(props.env, project.projectId, (res: any) => {
+ if (res.status === 200) {
+ EventBus.sendAlert("Deployment deleted", "Deployment deleted: " + project.projectId, 'info');
+ }
+ });
+ }
+ }
+
+ function rolloutDeployment () {
+ KaravanApi.rolloutDeployment(project.projectId, props.env, res => {
+ if (res.status === 200) {
+ EventBus.sendAlert("Rolled out", "Rolled out: " + project.projectId, 'info');
+ }
+ });
+ }
+
+ function startDeployment(){
+ KaravanApi.startDeployment(project.projectId, props.env, res => {
+ if (res.status === 200) {
+ EventBus.sendAlert("Started", "Deployment started for " + project.projectId, 'info');
+ } else {
+ EventBus.sendAlert("Error", res.data, 'danger');
+ }
+ });
+ }
+
+
+ function rolloutButton() {
+ return (
+ <Button variant="secondary"
+ className="project-button dev-action-button"
+ icon={<RolloutIcon/>}
+ onClick={e => {
+ setShowRolloutConfirmation(true);
+ }}>
+ Rollout
+ </Button>)
+ }
+
+ function deployButton() {
+ return (
+ <Button variant="primary"
+ className="project-button dev-action-button"
+ icon={<DeployIcon/>}
+ onClick={e => {
+ setShowDeployConfirmation(true);
+ }}>
+ Deploy
+ </Button>
+ )
+ }
+ function deleteButton() {
+ return (
+ <Button variant="control"
+ isDanger
+ className="project-button dev-action-button"
+ icon={<DeleteIcon/>}
+ onClick={e => {
+ setShowDeleteConfirmation(true);
+ }}>
+ Delete
+ </Button>
+ )
+ }
+
+ const deploymentStatus = deployments.find(d => d.projectId === project?.projectId);
+
+ return (
+ <div style={{flex: '2', display: 'flex', flexDirection: 'row', justifyContent: 'end', alignItems: 'center', gap: '6px'}}>
+ {deploymentStatus !== undefined && <div>{rolloutButton()}</div>}
+ {deploymentStatus === undefined && <div>{deployButton()}</div>}
+ {deploymentStatus !== undefined && <div>{deleteButton()}</div>}
+ {showDeleteConfirmation &&
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message={"Delete deployment " + project.projectId + "?"}
+ btnConfirm='Delete'
+ btnConfirmVariant='danger'
+ onConfirm={() => {
+ if (project.projectId) {
+ deleteDeployment();
+ setShowDeleteConfirmation(false);
+ }
+ }}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ }
+ {showRolloutConfirmation &&
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message={"Rollout deployment " + project.projectId + "?"}
+ btnConfirm='Rollout'
+ btnConfirmVariant='primary'
+ onConfirm={() => {
+ if (project.projectId) {
+ rolloutDeployment();
+ setShowRolloutConfirmation(false);
+ }
+ }}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ }
+ {showDeployConfirmation &&
+ <ModalConfirmation
+ isOpen={showDeleteConfirmation}
+ message={"Deploy " + project.projectId + "?"}
+ btnConfirm='Deploy'
+ btnConfirmVariant='primary'
+ onConfirm={() => {
+ if (project.projectId) {
+ startDeployment();
+ setShowDeployConfirmation(false);
+ }
+ }}
+ onCancel={() => setShowDeleteConfirmation(false)}
+ />
+ }
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentPanel.tsx
new file mode 100644
index 00000000..a2cda4e8
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/DeploymentPanel.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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 {Flex, FlexItem, Label, LabelGroup, Tooltip,} from '@patternfly/react-core';
+import '@features/project/designer/karavan.css';
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/running-icon";
+import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import {useProjectStore, useStatusesStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+
+export function DeploymentPanel () {
+
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const [deployments] = useStatusesStore((s) => [s.deployments], shallow);
+
+ const deploymentStatus = deployments.find(d => d.projectId === project?.projectId);
+ const ok = (deploymentStatus && deploymentStatus?.readyReplicas > 0
+ && (deploymentStatus.unavailableReplicas === 0 || deploymentStatus.unavailableReplicas === undefined || deploymentStatus.unavailableReplicas === null)
+ && deploymentStatus?.replicas === deploymentStatus?.readyReplicas)
+
+ return (
+ <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
+ <FlexItem flex={{default: 'flex_2'}}>
+ {deploymentStatus && <LabelGroup numLabels={3}>
+ <Tooltip content={"Ready Replicas / Replicas"} position={"left"}>
+ <Label icon={ok ? <UpIcon/> : <DownIcon/>}
+ color={ok ? "green" : "grey"}>{"Replicas: " + deploymentStatus.readyReplicas + " / " + deploymentStatus.replicas}</Label>
+ </Tooltip>
+ {deploymentStatus.unavailableReplicas > 0 &&
+ <Tooltip content={"Unavailable replicas"} position={"right"}>
+ <Label icon={<DownIcon/>} color={"red"}>{deploymentStatus.unavailableReplicas}</Label>
+ </Tooltip>
+ }
+ </LabelGroup>}
+ {deploymentStatus === undefined && <Label icon={<DownIcon/>} color={"grey"}>No deployments</Label>}
+ </FlexItem>
+ </Flex>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ImagesPanel.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ImagesPanel.tsx
new file mode 100644
index 00000000..2efca943
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-containers/ImagesPanel.tsx
@@ -0,0 +1,293 @@
+/*
+ * 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, {useState} from 'react';
+import {
+ Bullseye,
+ Button,
+ Content,
+ Divider,
+ EmptyState,
+ EmptyStateVariant,
+ Flex,
+ FlexItem,
+ HelperText,
+ HelperTextItem,
+ Modal,
+ ModalBody,
+ ModalFooter,
+ ModalHeader,
+ Switch,
+ TextInput,
+ Tooltip
+} from '@patternfly/react-core';
+
+import {useAppConfigStore, useFilesStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {CheckIcon, CloudDownloadAltIcon, SearchIcon, TimesIcon} from '@patternfly/react-icons';
+import {KaravanApi} from "@api/KaravanApi";
+import {ProjectService} from "@services/ProjectService";
+import {ServicesYaml} from "@models/ServiceModels";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {getMegabytes} from "@util/StringUtils";
+import {DOCKER_COMPOSE} from "@models/ProjectModels";
+
+export function ImagesPanel() {
+
+ const [project, images] = useProjectStore((s) => [s.project, s.images], shallow);
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [showSetConfirmation, setShowSetConfirmation] = useState<boolean>(false);
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+ const [showPullConfirmation, setShowPullConfirmation] = useState<boolean>(false);
+ const [imageName, setImageName] = useState<string>();
+ const [commitChanges, setCommitChanges] = useState<boolean>(false);
+ const [commitMessage, setCommitMessage] = useState('');
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const isDev = config.environment === 'dev';
+
+ function setProjectImage() {
+ if (imageName) {
+ KaravanApi.setProjectImage(project.projectId, imageName, commitChanges, commitMessage, (res: any) => {
+ ProjectService.refreshProjectData(project.projectId);
+ });
+ }
+ }
+
+ function getProjectImage(): string | undefined {
+ const file = files.filter(f => f.name === DOCKER_COMPOSE).at(0);
+ if (file) {
+ const dc = ServicesYaml.yamlToServices(file.code);
+ const dcs = dc.services.filter(s => s.container_name === project.projectId).at(0);
+ return dcs?.image;
+ }
+ return undefined;
+ }
+
+ function getSetConfirmation() {
+ const index = imageName?.lastIndexOf(":");
+ const name = imageName?.substring(0, index);
+ const tag = index ? imageName?.substring(index + 1) : "";
+ return (<Modal
+ variant='small'
+ isOpen={showSetConfirmation}
+ onClose={() => setShowSetConfirmation(false)}
+ onEscapePress={(e: any) => setShowSetConfirmation(false)}>
+ <ModalHeader title="Confirmation"/>
+ <ModalBody>
+ <Flex direction={{default: "column"}} justifyContent={{default: "justifyContentFlexStart"}}>
+ <FlexItem>
+ <div>{"Set image for project " + project.projectId + ":"}</div>
+ <div>{"Name: " + name}</div>
+ <div>{"Tag: " + tag}</div>
+ </FlexItem>
+ <FlexItem>
+ <Switch
+ id="commit-switch"
+ label="Commit changes"
+ isChecked={commitChanges}
+ onChange={(event, checked) => setCommitChanges(checked)}
+ isReversed
+ />
+ </FlexItem>
+ {commitChanges && <FlexItem>
+ <TextInput value={commitMessage} type="text"
+ onChange={(_, value) => setCommitMessage(value)}
+ aria-label="commit message"/>
+ </FlexItem>}
+ </Flex>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary" onClick={e => {
+ if (imageName) {
+ setProjectImage();
+ setShowSetConfirmation(false);
+ setCommitChanges(false);
+ }
+ }}>Set
+ </Button>
+ <Button key="cancel" variant="link"
+ onClick={e => {
+ setShowSetConfirmation(false);
+ setCommitChanges(false);
+ }}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ function getDeleteConfirmation() {
+ return (<Modal
+ variant='small'
+ isOpen={showDeleteConfirmation}
+ onClose={() => setShowDeleteConfirmation(false)}
+ onEscapePress={e => setShowDeleteConfirmation(false)}>
+ <ModalHeader title="Confirmation"/>
+ <ModalBody>
+ <Content>
+ <Content component='p'>
+ {"Delete image: "}<b>{imageName}</b>
+ </Content>
+ <HelperText>
+ <HelperTextItem variant="warning">
+ Container Image will be deleted from Docker Engine only!
+ </HelperTextItem>
+ </HelperText>
+ </Content>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="danger" onClick={e => {
+ if (imageName) {
+ KaravanApi.deleteImage(imageName, () => {
+ EventBus.sendAlert("Image deleted", "Image " + imageName + " deleted", 'info');
+ setShowDeleteConfirmation(false);
+ });
+ }
+ }}>Delete
+ </Button>
+ <Button key="cancel" variant="link"
+ onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ function getPullConfirmation() {
+ return (<Modal
+ variant='small'
+ isOpen={showPullConfirmation}
+ onClose={() => setShowPullConfirmation(false)}
+ onEscapePress={e => setShowPullConfirmation(false)}>
+ <ModalHeader title="Confirmation"/>
+ <ModalBody>
+ <Content>
+ <Content component='p'>
+ {"Pull all images from Registry for project: "}<b>{project.projectId}</b>
+ </Content>
+ <HelperText>
+ <HelperTextItem variant="warning">
+ Pull is a background process that might take some time!
+ </HelperTextItem>
+ </HelperText>
+ </Content>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="primary" onClick={e => {
+ KaravanApi.pullProjectImages(project.projectId, () => {
+ setShowPullConfirmation(false);
+ });
+ }}>Pull
+ </Button>
+ <Button key="cancel" variant="link" onClick={_ => setShowPullConfirmation(false)}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ const projectImage = getProjectImage();
+ return (
+ <>
+ <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", paddingRight: "16px"}}>
+ <Content component='h6' style={{padding: '16px'}}>Images</Content>
+ <Tooltip content="Pull all images from registry" position={"bottom-end"}>
+ <Button variant={"secondary"} className="dev-action-button" icon={<CloudDownloadAltIcon/>}
+ onClick={() => setShowPullConfirmation(true)}>
+ Pull
+ </Button>
+ </Tooltip>
+ </div>
+ <Divider/>
+ <Table aria-label="Images" variant={"compact"} isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th key='status' modifier={"fitContent"}>Active</Th>
+ <Th key='image' width={20}>Image</Th>
+ <Th key='tag' width={10}>Tag</Th>
+ <Th key='size' width={10}>Size</Th>
+ <Th key='created' width={10}>Created</Th>
+ <Th key='actions' aria-label='actions' modifier={"fitContent"} textCenter>Actions</Th>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {images.map(image => {
+ const fullName = image.tag;
+ const index = fullName.lastIndexOf(":");
+ const name = fullName.substring(0, index);
+ const tag = fullName.substring(index + 1);
+ const created = new Date(image.created * 1000);
+ const size = getMegabytes(image.size)?.toFixed(0);
+ const isDisabled = fullName === projectImage || !isDev;
+ const variant = isDisabled ? "plain" : "link";
+ return <Tr key={image.id} style={{verticalAlign: "middle"}}>
+ <Td modifier={"fitContent"}>
+ {fullName === projectImage ? <CheckIcon/> : <div/>}
+ </Td>
+ <Td>{name}</Td>
+ <Td>{tag}</Td>
+ <Td>{size} MB</Td>
+ <Td>{created.toISOString()}</Td>
+ <Td modifier={"fitContent"} isActionCell>
+ <Flex direction={{default: "row"}}
+ flexWrap={{default: 'nowrap'}}
+ justifyContent={{default: "justifyContentFlexEnd"}}
+ spaceItems={{default: 'spaceItemsNone'}}>
+ <FlexItem>
+ <Tooltip content={"Delete image"} position={"bottom"}>
+ <Button variant={variant}
+ className='dev-action-button'
+ icon={<TimesIcon/>}
+ isDisabled={isDisabled}
+ onClick={e => {
+ setImageName(fullName);
+ setShowDeleteConfirmation(true);
+ }}>
+ </Button>
+ </Tooltip>
+ </FlexItem>
+ <FlexItem>
+ <Tooltip content="Set project image" position={"bottom"}>
+ <Button icon={<CheckIcon/>} variant={variant}
+ className='dev-action-button'
+ isDisabled={isDisabled}
+ onClick={e => {
+ setImageName(fullName);
+ setCommitMessage(commitMessage === '' ? new Date().toLocaleString() : commitMessage);
+ setShowSetConfirmation(true);
+ }}>
+
+ </Button>
+ </Tooltip>
+ </FlexItem>
+ </Flex>
+ </Td>
+ </Tr>
+ })}
+ {images.length === 0 &&
+ <Tr>
+ <Td colSpan={8}>
+ <Bullseye>
+ <EmptyState headingLevel="h2" icon={SearchIcon} titleText="No results found" variant={EmptyStateVariant.sm}>
+ </EmptyState>
+ </Bullseye>
+ </Td>
+ </Tr>
+ }
+ </Tbody>
+ </Table>
+ {showSetConfirmation && getSetConfirmation()}
+ {showDeleteConfirmation && getDeleteConfirmation()}
+ {showPullConfirmation && getPullConfirmation()}
+ </>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodEventsLogTable.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodEventsLogTable.tsx
new file mode 100644
index 00000000..6c44c1b8
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodEventsLogTable.tsx
@@ -0,0 +1,61 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {InnerScrollContainer, OuterScrollContainer, Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {KaravanApi} from "@api/KaravanApi";
+import {PodEvent} from "@models/ProjectModels";
+import {useSelectedContainerStore} from "@stores/ProjectStore";
+
+export function PodEventsLogTable() {
+
+ const [selectedContainerName] = useSelectedContainerStore((s) => [s.selectedContainerName]);
+ const [podEvents, setPodEvents] = useState<PodEvent[]>([]);
+
+ useEffect(() => {
+ if (selectedContainerName) {
+ KaravanApi.getPodEvents(selectedContainerName, pes => setPodEvents(pes));
+ }
+ }, []);
+
+ return (
+ <OuterScrollContainer>
+ <InnerScrollContainer>
+ <Table aria-label="Simple table" height={"100vh"} variant='compact' isStickyHeader>
+ <Thead>
+ <Tr>
+ <Th>ID</Th>
+ <Th>Reason</Th>
+ <Th>Note</Th>
+ <Th>TimeStamp</Th>
+ </Tr>
+ </Thead>
+ <Tbody className='event-table'>
+ {podEvents.map((podEvent) => (
+ <Tr key={podEvent.id}>
+ <Td>{podEvent.id}</Td>
+ <Td>{podEvent.reason}</Td>
+ <Td>{podEvent.note}</Td>
+ <Td>{podEvent.creationTimestamp}</Td>
+ </Tr>
+ ))}
+ </Tbody>
+ </Table>
+ </InnerScrollContainer>
+ </OuterScrollContainer>
+ );
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodTab.tsx
new file mode 100644
index 00000000..87b655a6
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-pod/PodTab.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import {PodEventsLogTable} from "@features/project/project-pod/PodEventsLogTable";
+import {Content, Divider} from "@patternfly/react-core";
+import {ProjectContainerContextToolbar} from "@features/project/ProjectContainerContextToolbar";
+
+export function PodTab() {
+
+ return (
+ <div className="project-page">
+ <ProjectContainerContextToolbar/>
+ <Content component='h6' style={{padding: '16px'}}>Pod Events</Content>
+ <Divider/>
+ <PodEventsLogTable/>
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomComponentFactory.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomComponentFactory.tsx
new file mode 100644
index 00000000..ef7af5bb
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomComponentFactory.tsx
@@ -0,0 +1,87 @@
+/*
+ * 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 {
+ DragObjectWithType,
+ Edge,
+ GraphComponent,
+ graphDropTargetSpec,
+ GraphElement,
+ groupDropTargetSpec,
+ Model,
+ ModelKind,
+ Node,
+ nodeDragSourceSpec,
+ nodeDropTargetSpec,
+ withContextMenu,
+ withDndDrop,
+ withDragNode,
+ withPanZoom,
+ withSelection,
+ withTargetDrag,
+} from '@patternfly/react-topology';
+import CustomGroup from "@features/project/project-topology/CustomGroup";
+import {getCustomMenu} from "@features/project/project-topology/GetCustomMenu";
+import CustomNode from "@features/project/project-topology/CustomNode";
+import CustomEdge from "@features/project/project-topology/CustomEdge";
+
+const CONNECTOR_TARGET_DROP = 'connector-target-drop';
+
+export function getCustomComponentFactory(model: Model, withDragDrop: boolean) {
+ const groupNames: string[] = model.nodes?.filter(n => n.type === 'group').map(n => n.id) ?? [];
+ return function (kind: ModelKind, type: string) {
+ switch (type) {
+ case 'group':
+ return withDragDrop
+ ? withDndDrop(groupDropTargetSpec)(withDragNode(nodeDragSourceSpec('group'))(withSelection()(CustomGroup)))
+ : (withSelection()(CustomGroup));
+ default:
+ switch (kind) {
+ case ModelKind.graph:
+ return withDndDrop(graphDropTargetSpec())(withPanZoom()(GraphComponent));
+ case ModelKind.node:
+ return withDragDrop
+ ? withDndDrop(nodeDropTargetSpec([CONNECTOR_TARGET_DROP]))(
+ withDragNode(nodeDragSourceSpec('node', true, true))(withContextMenu(element => getCustomMenu(element, groupNames))(withSelection()(CustomNode)))
+ )
+ : withContextMenu(element => getCustomMenu(element, groupNames))(withSelection()(CustomNode));
+ case ModelKind.edge:
+ return withTargetDrag<DragObjectWithType, Node, { dragging?: boolean }, { element: GraphElement; }>({
+ item: {type: CONNECTOR_TARGET_DROP},
+ begin: (monitor, props) => {
+ props.element.raise();
+ return props.element;
+ },
+ drag: (event, monitor, props) => {
+ (props.element as Edge).setEndPoint(event.x, event.y);
+ },
+ end: (dropResult: Node | undefined, monitor, props) => {
+ if (monitor.didDrop() && dropResult !== undefined && props) {
+ (props.element as Edge).setTarget(dropResult);
+ }
+ (props.element as Edge).setEndPoint();
+ },
+ collect: (monitor) => ({
+ dragging: monitor.isDragging()
+ })
+ })(withSelection()(CustomEdge));
+ default:
+ return undefined;
+ }
+ }
+ };
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomEdge.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomEdge.tsx
new file mode 100644
index 00000000..a516114e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomEdge.tsx
@@ -0,0 +1,40 @@
+/*
+ * 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 * as React from 'react';
+
+import './topology.css';
+import {DefaultEdge, EdgeTerminalType, NodeStatus, observer} from '@patternfly/react-topology';
+
+const CustomEdge: React.FC<any> = observer(({ element, ...rest }) => {
+
+ const data = element.getData();
+
+ return (
+ <DefaultEdge
+ element={element}
+ startTerminalType={EdgeTerminalType.none}
+ endTerminalType={EdgeTerminalType.directional}
+ endTerminalSize={10}
+ endTerminalStatus={data?.endTerminalStatus || NodeStatus.default}
+ tagStatus={data?.endTerminalStatus || NodeStatus.default}
+ tag={data?.label}
+ {...rest}
+ />
+ )
+})
+export default CustomEdge;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomGroup.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomGroup.tsx
new file mode 100644
index 00000000..5bc55a8e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomGroup.tsx
@@ -0,0 +1,35 @@
+/*
+ * 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 * as React from 'react';
+
+import './topology.css';
+import {DefaultGroup, observer} from '@patternfly/react-topology';
+
+const CustomGroup: React.FC<any> = observer(({ element, ...rest }) => {
+ return (
+ <DefaultGroup
+ element={element}
+ className={"topology-group"}
+ // showLabel={false}
+ // showLabelOnHover={true}
+ {...rest}
+ >
+ </DefaultGroup>
+ )
+})
+export default CustomGroup;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomNode.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomNode.tsx
new file mode 100644
index 00000000..60266fd8
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/CustomNode.tsx
@@ -0,0 +1,178 @@
+import * as React from 'react';
+import {useRef} from 'react';
+import {LockedIcon, RegionsIcon} from '@patternfly/react-icons';
+import {Decorator, DEFAULT_DECORATOR_RADIUS, DefaultNode, getDefaultShapeDecoratorCenter, observer, TopologyQuadrant, WithContextMenuProps} from '@patternfly/react-topology';
+import {BeanIcon, getDesignerIcon, OpenApiIcon} from "@features/project/designer/icons/KaravanIcons";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
+import '@features/project/project-topology/topology.css';
+import {RouteDefinition} from "@karavan-core/model/CamelDefinition";
+import {AutoStartupFalseIcon, ErrorHandlerIcon} from "@features/project/designer/icons/OtherIcons";
+import {runInAction} from "mobx";
+import {SvgIcon} from "@shared/icons/SvgIcon";
+import {useTopologyHook} from "@features/project/project-topology/useTopologyHook";
+import {Category, IntentRequestScaleIn, IntentRequestScaleOut} from "@carbon/icons-react";
+
+function getIcon(data: any) {
+ if (['route'].includes(data.icon)) {
+ return (
+ <g transform={`translate(14, 14) scale(2)`} className='icon-wrapper'>
+ <Category/>
+ {data?.generatedFromAsyncApi &&
+ <g transform={`translate(9, -2)`}>
+ {SvgIcon({icon: 'asyncapi', width: 14, height: 14})}
+ </g>
+ }
+ </g>
+ )
+ } else if (['routeConfiguration'].includes(data.icon)) {
+ return (
+ <g transform={`translate(8, 8) scale(0.75)`}>
+ {getDesignerIcon(data.icon)}
+ </g>
+ )
+ } else if (['rest'].includes(data.icon)) {
+ return (
+ <g transform={`translate(14, 14)`}>
+ {getDesignerIcon(data.icon)}
+ </g>
+ )
+ } else if (data.icon === 'bean') {
+ return (
+ <g transform={`translate(8, 8) scale(0.75)`}>
+ <BeanIcon/>
+ </g>
+ )
+ } else if (data.icon === 'element') {
+ return (
+ <g transform={`translate(8, 8) scale(0.75)`}>
+ {CamelUi.getConnectionIcon(data.step)}
+ </g>
+ )
+ } else if (data.icon === 'openapi') {
+ return (
+ <g transform={`translate(14, 14)`}>
+ <OpenApiIcon width={32} height={32} />
+ </g>
+ )
+ } else if (data.icon === 'asyncapi') {
+ return (
+ <g transform={`translate(14, 14)`}>
+ {SvgIcon({icon: 'asyncapi', width: 32, height: 32})}
+ </g>
+ )
+ } else if (data.icon === 'send') {
+ return (
+ <g rotate={45} transform={`translate(14, 14) scale(2)`}>
+ <IntentRequestScaleOut style={{fill: "var(--pf-t--global--text--color--subtle)"}}/>
+ <g transform={`translate(12, -2)`}>
+ {SvgIcon({icon: 'asyncapi', width: 6, height: 6})}
+ </g>
+ </g>
+ )
+ } else if (data.icon === 'receive') {
+ return (
+ <g rotate={45} transform={`translate(14, 14) scale(2)`}>
+ <IntentRequestScaleIn style={{fill: "var(--pf-t--global--text--color--subtle)"}}/>
+ <g transform={`translate(12, -2)`}>
+ {SvgIcon({icon: 'asyncapi', width: 6, height: 6})}
+ </g>
+ </g>
+ )
+ }
+ return <RegionsIcon/>;
+}
+
+function isDisable(data: any) {
+ if ((data && data?.step?.dslName === 'RouteDefinition')) {
+ const route: RouteDefinition = data?.step;
+ const autoStartup = route?.autoStartup === false;
+ return autoStartup;
+ } else if (data?.type === 'step' && data?.outgoing && data?.disabled) {
+ return true;
+ }
+ return false;
+}
+
+function getAttachments(data: any) {
+ const showStats = data?.showStats;
+ if (data && data?.step?.dslName === 'RouteDefinition') {
+ const route: RouteDefinition = data?.step;
+ const routeId = route?.id;
+ const errorHandler = route?.errorHandler !== undefined;
+ return (
+ <g>
+ <g className="pf-topology__node__label__badge auto-start" transform="translate(-4, -4)">
+ {errorHandler && <g className="" transform="translate(13, -4)">{ErrorHandlerIcon()}</g>}
+ {isDisable(data) && <g className="" transform="translate(-4, -4)">{AutoStartupFalseIcon()}</g>}
+ </g>
+ </g>
+ )
+ } else if (isDisable(data)) {
+ return (
+ <g className="pf-topology__node__label__badge auto-start" transform="translate(-4, -4)">
+ <g className="" transform="translate(-4, -4)">{AutoStartupFalseIcon()}</g>
+ </g>
+ )
+ } else {
+ return (<></>)
+ }
+}
+
+const CustomNode: React.FC<any & WithContextMenuProps> = observer(({element, onContextMenu, contextMenuOpen, selected, ...rest}) => {
+ const {selectFile, project} = useTopologyHook(undefined);
+ const decoratorRef = useRef(null);
+ const data = element.getData();
+ const badge: string = ['API', 'RT', 'TR'].includes(data.badge) ? data.badge : data.badge?.substring(0, 1).toUpperCase();
+ let colorClass = 'route';
+ let label = element.getLabel();
+ if (badge === 'C') {
+ colorClass = 'component'
+ } else if (badge === 'K') {
+ colorClass = 'kamelet';
+ label = element.getLabel()?.replace('kamelet:', '');
+ }
+ if (label?.length > 30) {
+ runInAction(() => {
+ element.setLabel(label?.substring(0, 30) + '...');
+ });
+ }
+ const disableClass = isDisable(data) ? 'disable-node' : '';
+
+ const { x, y } = getDefaultShapeDecoratorCenter("lowerRight" as TopologyQuadrant, element);
+
+ const decorator = (
+ <Decorator
+ radius={DEFAULT_DECORATOR_RADIUS}
+ showBackground
+ className="gen-route-decorator"
+ icon= {<LockedIcon width={14}/>}
+ x={x - DEFAULT_DECORATOR_RADIUS / 2}
+ y={y - DEFAULT_DECORATOR_RADIUS / 2}
+ innerRef={decoratorRef}
+ />
+ );
+
+ return (
+ <g onDoubleClick={event => {
+ event.stopPropagation();
+ selectFile(data.fileName)
+ }}>
+ <DefaultNode
+ showStatusDecorator
+ className={"common-node common-node-" + badge + " topology-color-" + colorClass + " " + disableClass}
+ scaleLabel={true}
+ element={element}
+ onContextMenu={onContextMenu}
+ contextMenuOpen={contextMenuOpen}
+ attachments={getAttachments(data)}
+ hideContextMenuKebab={false}
+ labelIconPadding={1}
+ label={label}
+ {...rest}
+ >
+ {getIcon(data)}
+ </DefaultNode>
+ </g>
+ )
+})
+export default CustomNode;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/GetCustomMenu.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/GetCustomMenu.tsx
new file mode 100644
index 00000000..d8efab26
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/GetCustomMenu.tsx
@@ -0,0 +1,67 @@
+/*
+ * 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 {ContextMenuItem, ContextSubMenuItem, GraphElement} from '@patternfly/react-topology';
+import * as React from "react";
+
+export function getCustomMenu(element: GraphElement, groupNames: string[]) {
+
+ const result: React.ReactElement<any, string | React.JSXElementConstructor<any>>[] | Promise<React.ReactElement<any, string | React.JSXElementConstructor<any>>[]> = []
+ const data = element.getData();
+ result.push(
+ <ContextMenuItem key={element.getId() + "-open"} onClick={() => data?.selectFile?.(data?.fileName)}>
+ Open
+ </ContextMenuItem>
+ );
+ if (data?.type === 'route') {
+ result.push(
+ <ContextMenuItem key={element.getId()}
+ onClick={() => data?.setDisabled?.(data?.fileName, data?.routeId, !(data?.autoStartup))}>
+ {data?.autoStartup === false ? 'Enable' : 'Disable'}
+ </ContextMenuItem>
+ );
+ result.push(
+ <ContextMenuItem key={element.getId() + '-delete'} onClick={() => {
+ data?.deleteRoute?.(data?.fileName, data?.step.id);
+ }}>
+ {'Delete'}
+ </ContextMenuItem>
+ );
+ if (groupNames.length > 0) {
+ result.push(
+ <ContextSubMenuItem label='Groups' key={element.getId() + '-groups'} children={
+ groupNames.filter(g => !g.startsWith("karavan-")).map(groupName => {
+ return (
+ <ContextMenuItem key={`${element.getId()}-groups-${groupName}`} isSelected={data.routeGroup === groupName} onClick={() => data?.setRouteGroup?.(data?.fileName, data?.routeId, groupName)}
+ >
+ {groupName}
+ </ContextMenuItem>
+ )
+ })
+ }/>
+ )
+ }
+ } else if (data?.type === 'step' && data?.outgoing) {
+ result.push(
+ <ContextMenuItem key={element.getId() + '-step'}
+ onClick={() => data?.setDisabled?.(data?.fileName, data?.step.id, !(data?.disabled))}>
+ {data?.disabled ? 'Enable' : 'Disable'}
+ </ContextMenuItem>
+ );
+ }
+ return result;
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx
new file mode 100644
index 00000000..cfb80842
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyApi.tsx
@@ -0,0 +1,722 @@
+import {EdgeAnimationSpeed, EdgeModel, EdgeStyle, Model, NodeModel, NodeShape, NodeStatus,} from '@patternfly/react-topology';
+import {Integration, IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {TopologyUtils} from "@karavan-core/api/TopologyUtils";
+import {
+ TopologyAsyncApiNode,
+ TopologyIncomingNode,
+ TopologyOpenApiNode,
+ TopologyOutgoingNode,
+ TopologyRestNode,
+ TopologyRouteConfigurationNode,
+ TopologyRouteNode
+} from "@karavan-core/model/TopologyDefinition";
+import {INTERNAL_COMPONENTS} from "@karavan-core/api/ComponentApi";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+
+const NODE_DIAMETER_ROUTE = 60;
+const NODE_DIAMETER_INOUT = NODE_DIAMETER_ROUTE / 1.5;
+
+export function getIntegrations(files: IntegrationFile[]): Integration[] {
+ const integrations: Integration[] = [];
+ files.filter((file) => file.name.endsWith(".camel.yaml")).forEach((file) => {
+ try {
+ const i = CamelDefinitionYaml.yamlToIntegration(file.name, file.code);
+ integrations.push(i);
+ } catch (e: any) {
+ console.error(e);
+ EventBus.sendAlert('Error', e?.message, 'danger');
+ }
+ })
+ return integrations;
+}
+
+export function getIncomingNodes(tins: TopologyIncomingNode[]): NodeModel[] {
+ return tins.filter(tin => tin.type === 'external').map(tin => {
+ return {
+ id: tin.id,
+ type: 'node',
+ label: getUriLabel(tin.uniqueUri),
+ width: NODE_DIAMETER_INOUT,
+ height: NODE_DIAMETER_INOUT,
+ shape: NodeShape.circle,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ badge: tin.connectorType,
+ icon: 'element',
+ type: 'step',
+ step: tin.from,
+ fileName: tin.fileName,
+ }
+ }
+ });
+}
+
+export function getRoutes(tins: TopologyRouteNode[], tasyncapis: TopologyAsyncApiNode, showStats?: boolean): NodeModel[] {
+ return tins.map(tin => {
+ const oper = tasyncapis?.operations?.find(o => o.operationId === tin.routeId)
+ const node: NodeModel = {
+ id: tin.id,
+ type: 'node',
+ label: tin.title,
+ width: NODE_DIAMETER_ROUTE,
+ height: NODE_DIAMETER_ROUTE,
+ shape: NodeShape.rect,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ badge: (tin.templateId !== undefined ? 'RT' : 'R'),
+ type: 'route',
+ icon: 'route',
+ step: tin.route,
+ routeId: tin.routeId,
+ routeGroup: tin.route.group,
+ fileName: tin.fileName,
+ templateId: tin.templateId,
+ templateTitle: tin.templateTitle,
+ generatedFromAsyncApi: oper?.operationId === tin.routeId,
+ autoStartup: tin.route.autoStartup !== false,
+ showStats: showStats,
+ }
+ }
+ return node;
+ });
+}
+
+export function getRouteConfigurations(trcs: TopologyRouteConfigurationNode[]): NodeModel[] {
+ return trcs.map(tin => {
+ const node: NodeModel = {
+ id: tin.id,
+ type: 'node',
+ label: tin.title,
+ width: NODE_DIAMETER_INOUT,
+ height: NODE_DIAMETER_INOUT,
+ shape: NodeShape.octagon,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ type: 'routeConfiguration',
+ icon: 'routeConfiguration',
+ step: tin.routeConfiguration,
+ routeConfigurationId: tin.routeConfigurationId,
+ fileName: tin.fileName,
+ }
+ }
+ return node;
+ });
+}
+
+export function getOutgoingNodes(tons: TopologyOutgoingNode[]): NodeModel[] {
+ return tons.filter(tin => tin.type === 'external').map(tin => {
+ const node: NodeModel = {
+ id: tin.id,
+ type: 'node',
+ label: getUriLabel(tin.uniqueUri),
+ width: NODE_DIAMETER_INOUT,
+ height: NODE_DIAMETER_INOUT,
+ shape: NodeShape.circle,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ icon: 'element',
+ type: 'step',
+ step: tin.step,
+ badge: tin.connectorType,
+ fileName: tin.fileName,
+ outgoing: true,
+ disabled: (tin.step as any)?.disabled || false
+ }
+ }
+ return node;
+ });
+}
+
+export function getIncomingEdges(tins: TopologyIncomingNode[]): EdgeModel[] {
+ return tins.filter(tin => tin.type === 'external').map((tin, index, array) => {
+ const node: EdgeModel = {
+ id: 'edge-incoming-' + tin.routeId,
+ type: 'edge',
+ source: tin.id,
+ target: 'route-' + tin.routeId,
+ edgeStyle: tin.type === 'external' ? EdgeStyle.dashedMd : EdgeStyle.solid,
+ animationSpeed: tin.type === 'external' ? EdgeAnimationSpeed.medium : EdgeAnimationSpeed.none,
+ data: {
+ label: tin.from.uri
+ }
+ }
+ return node;
+ });
+}
+
+export function getOutgoingEdges(tons: TopologyOutgoingNode[]): EdgeModel[] {
+ return tons.filter(ton => ton.type === 'external').map((ton, index, array) => {
+ const node: EdgeModel = {
+ id: 'edge-outgoing-' + ton.routeId + '-' + (ton.step as any).id,
+ type: 'edge',
+ source: 'route-' + ton.routeId,
+ target: ton.id,
+ edgeStyle: ton.type === 'external' ? EdgeStyle.dashedMd : EdgeStyle.solid,
+ animationSpeed: ton.type === 'external' ? EdgeAnimationSpeed.medium : EdgeAnimationSpeed.none,
+ data: {
+ label: ton.uniqueUri?.split(":")?.[0]
+ }
+ }
+ return node;
+ });
+}
+
+export function getExternalEdges(tons: TopologyOutgoingNode[], tins: TopologyIncomingNode[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ tons.filter(ton => ton.type === 'external').forEach((ton, index, array) => {
+ const uniqueUri = ton.uniqueUri;
+ if (uniqueUri) {
+ TopologyUtils.getIncomingNodeByUniqueUri(tins, uniqueUri).forEach(target => {
+ const node: EdgeModel = {
+ id: 'external-' + ton.id + '-' + target,
+ type: 'edge',
+ source: ton.id,
+ target: target.id,
+ edgeStyle: EdgeStyle.dotted,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ groupName: uniqueUri,
+ label: target.from.uri
+ }
+ }
+ result.push(node);
+ });
+ }
+ });
+ return result;
+}
+
+function getUriLabel(uniqueUri: string) {
+ const parts = uniqueUri.split('=');
+ const name = parts[1];
+ return `${name}`
+}
+
+export function getUniqueUriNodes(tons: TopologyOutgoingNode[], tins: TopologyIncomingNode[], troutes: TopologyRouteNode[]): NodeModel[] {
+ const result: Map<string, NodeModel> = new Map();
+
+ tons.filter(ton => ton.type === 'external').forEach((ton, index, array) => {
+ const uniqueUri = ton.uniqueUri;
+ if (uniqueUri) {
+ const node: NodeModel = result.get(uniqueUri) ?? {
+ id: uniqueUri,
+ type: 'node',
+ label: getUriLabel(uniqueUri),
+ width: NODE_DIAMETER_INOUT,
+ height: NODE_DIAMETER_INOUT,
+ shape: NodeShape.circle,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ icon: 'element',
+ type: 'step',
+ badge: ton.connectorType,
+ step: ton.step,
+ fileName: ton.fileName,
+ uniqueUri: uniqueUri,
+ outgoing: true,
+ incomingIds: [],
+ outgoingIds: [],
+ groups: []
+ }
+ }
+ node.data.outgoingIds = [...new Set([...node.data.outgoingIds, ton.routeId])];
+ TopologyUtils.getIncomingNodeByUniqueUri(tins, uniqueUri).forEach(tin => {
+ node.data.incomingIds = [...new Set([...node.data.incomingIds, tin.routeId])];
+ })
+
+ const groups: string[] = [];
+ troutes.filter(r => (node.data.incomingIds.includes(r.routeId) || node.data.outgoingIds.includes(r.routeId)) && r.route.group).forEach(r => {
+ if (r.route.group) groups.push(r.route.group)
+ });
+ node.data.groups = [...new Set(groups)];
+ result.set(uniqueUri, node)
+ }
+ });
+ tins.filter(tin => tin.type === 'external').forEach((tin, index, array) => {
+ const uniqueUri = tin.uniqueUri;
+ if (uniqueUri) {
+ const node: NodeModel = result.get(uniqueUri) ?? {
+ id: uniqueUri,
+ type: 'node',
+ label: getUriLabel(uniqueUri),
+ width: NODE_DIAMETER_INOUT,
+ height: NODE_DIAMETER_INOUT,
+ shape: NodeShape.circle,
+ status: NodeStatus.default,
+ data: {
+ uniqueUri: uniqueUri,
+ isAlternate: false,
+ icon: 'element',
+ type: 'step',
+ badge: tin.connectorType,
+ step: tin.from,
+ fileName: tin.fileName,
+ outgoing: false,
+ incomingIds: [],
+ outgoingIds: []
+ }
+ }
+ node.data.incomingIds = [...new Set([...node.data.incomingIds, tin.routeId])];
+ TopologyUtils.getOutgoingNodeByUniqueUri(tons, uniqueUri).forEach(ton => {
+ node.data.outgoingIds = [...new Set([...node.data.outgoingIds, ton.routeId])];
+ })
+ const groups: string[] = [];
+ troutes.filter(r => (node.data.incomingIds.includes(r.routeId) || node.data.outgoingIds.includes(r.routeId)) && r.route.group).forEach(r => {
+ if (r.route.group) groups.push(r.route.group)
+ });
+ node.data.groups = [...new Set(groups)];
+ result.set(uniqueUri, node)
+ }
+ });
+ return Array.from(result.values());
+}
+
+export function getUriEdges(nodes: NodeModel[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ nodes.forEach(node => {
+ node.data.incomingIds.forEach((tinRouteId: string) => {
+ const edge: EdgeModel = {
+ id: 'edge-uri-' + node.id + '-' + tinRouteId,
+ type: 'edge',
+ source: node.id,
+ target: 'route-' + tinRouteId,
+ edgeStyle: EdgeStyle.dashedMd,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ label: node.id?.split(":")?.[0]
+ }
+ }
+ result.push(edge);
+ })
+ node.data.outgoingIds.forEach((tonRouteId: string) => {
+ const edge: EdgeModel = {
+ id: 'edge-uri-' + node.id + '-' + tonRouteId,
+ type: 'edge',
+ source: 'route-' + tonRouteId,
+ target: node.id,
+ edgeStyle: EdgeStyle.dashedMd,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ label: node.id?.split(":")?.[0]
+ }
+ }
+ result.push(edge);
+ })
+ });
+ return result;
+}
+
+export function getRestNodes(tins: TopologyRestNode[]): NodeModel[] {
+ return tins.map(tin => {
+ const isOpenApi = tin.rest.openApi !== undefined;
+ return {
+ id: tin.id,
+ type: 'node',
+ label: isOpenApi ? 'REST Config' : tin.title,
+ width: NODE_DIAMETER_ROUTE,
+ height: NODE_DIAMETER_ROUTE,
+ shape: NodeShape.hexagon,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ badge: 'API',
+ icon: 'rest',
+ type: 'rest',
+ step: tin.rest,
+ fileName: tin.fileName,
+ secondaryLabel: tin.title,
+
+ }
+ }
+ });
+}
+
+export function getOpenApiNodes(topenapis: TopologyOpenApiNode[], showStats?: boolean): NodeModel[] {
+ return topenapis.map(topenapi => {
+ return {
+ id: topenapi.fileName,
+ type: 'node',
+ label: topenapi.title,
+ width: NODE_DIAMETER_ROUTE,
+ height: NODE_DIAMETER_ROUTE,
+ shape: NodeShape.hexagon,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ badge: 'OpenAPI',
+ icon: 'openapi',
+ type: 'openapi',
+ // step: tin.rest,
+ fileName: topenapi.fileName,
+ secondaryLabel: topenapi.title,
+ showStats: showStats,
+ }
+ }
+ });
+}
+
+export function getAsyncApiNodes(tasyncapis: TopologyAsyncApiNode[]): NodeModel[] {
+ const result: NodeModel[] = [];
+ tasyncapis.forEach(tasyncapi => {
+ // const node = {
+ // id: tasyncapi.fileName,
+ // type: 'node',
+ // label: tasyncapi.title,
+ // width: NODE_DIAMETER_ROUTE,
+ // height: NODE_DIAMETER_ROUTE,
+ // shape: NodeShape.circle,
+ // status: NodeStatus.default,
+ // data: {
+ // isAlternate: false,
+ // badge: 'AsyncAPI',
+ // icon: 'asyncapi',
+ // type: 'asyncapi',
+ // // step: tin.rest,
+ // fileName: tasyncapi.fileName,
+ // secondaryLabel: tasyncapi.title,
+ // }
+ // } as NodeModel;
+ // result.push(node);
+
+ tasyncapi.operations.forEach(operation => {
+ const operationNode = {
+ id: `asyncapi-operation-${operation.operationId}`,
+ type: 'node',
+ label: operation.operationId,
+ width: NODE_DIAMETER_ROUTE,
+ height: NODE_DIAMETER_ROUTE,
+ shape: NodeShape.rect,
+ status: NodeStatus.default,
+ data: {
+ isAlternate: false,
+ badge: 'AsyncAPI',
+ type: operation.action,
+ icon: operation.action,
+ // step: tin.rest,
+ fileName: tasyncapi.fileName,
+ secondaryLabel: tasyncapi.title,
+ }
+ } as NodeModel;
+ result.push(operationNode);
+ })
+ });
+ return result;
+}
+
+export function getAsyncApiEdges(tasyncapis: TopologyAsyncApiNode[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ tasyncapis.forEach(tasyncapi => {
+ tasyncapi.operations.forEach(operation => {
+ const edge: EdgeModel = {
+ id: `${operation.action}-${operation.operationId}`,
+ type: 'edge',
+ source: operation.action === 'send' ? `asyncapi-operation-${operation.operationId}` : tasyncapi.fileName,
+ target: operation.action === 'send' ? tasyncapi.fileName: `asyncapi-operation-${operation.operationId}`,
+ edgeStyle: EdgeStyle.dashed,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ label: `${operation.action}`
+ }
+ }
+ // result.push(edge);
+ })
+ });
+ return result;
+}
+
+export function getOpenApiEdges(topenapis: TopologyOpenApiNode[], tins: TopologyIncomingNode[], trcs: TopologyRestNode[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ topenapis.forEach(topenapi => {
+
+ trcs.filter(t => t.rest?.openApi !== undefined).forEach(trc => {
+ const edgeRest: EdgeModel = {
+ id: 'rest-openapi-' + topenapi.fileName + '-' + trc.id,
+ type: 'edge',
+ source: trc.id,
+ target: topenapi.fileName,
+ edgeStyle: EdgeStyle.solid,
+ animationSpeed: EdgeAnimationSpeed.none
+ }
+ result.push(edgeRest);
+ })
+
+ topenapi.operations.filter(o => o.operationId?.length > 0)
+ .forEach((operation, index, array) => {
+ const target = TopologyUtils.getRouteIdByUri(tins, 'direct:' + operation.operationId);
+ const edge: EdgeModel = {
+ id: 'incoming-' + operation.path + '-' + operation.method + '-' + index,
+ type: 'edge',
+ source: topenapi.fileName,
+ target: target,
+ edgeStyle: EdgeStyle.solid,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ label: `${operation.method} ${operation.path} `
+ }
+ }
+ if (target) result.push(edge);
+ })
+ });
+
+ return result;
+}
+
+
+export function getRestEdges(rest: TopologyRestNode[], tins: TopologyIncomingNode[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ rest.forEach(tin => {
+ tin.uris.forEach((uri, index, array) => {
+ const target = TopologyUtils.getRouteIdByUri(tins, uri);
+ const node: EdgeModel = {
+ id: 'incoming-' + tin.id + '-' + index,
+ type: 'edge',
+ source: tin.id,
+ target: target,
+ edgeStyle: EdgeStyle.solid,
+ animationSpeed: EdgeAnimationSpeed.medium
+ }
+ if (target) result.push(node);
+ })
+ });
+ return result;
+}
+
+export function getInternalEdges(tons: TopologyOutgoingNode[], tins: TopologyIncomingNode[]): EdgeModel[] {
+ const result: EdgeModel[] = [];
+ tons.filter(ton => ton.type === 'internal').forEach((ton, index, array) => {
+ const step = (ton.step as any);
+ if (step?.dslName === 'DeadLetterChannelDefinition') {
+ const parts = step.deadLetterUri?.split(":");
+ const uri: string = parts[0];
+ const name: string = parts[1];
+ const target = TopologyUtils.getRouteIdByUriAndName(tins, uri, name);
+ const node: EdgeModel = {
+ id: 'internal-' + ton.id + '-' + index,
+ type: 'edge',
+ source: 'route-' + ton.routeId,
+ target: target,
+ edgeStyle: EdgeStyle.solid,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ endTerminalStatus: NodeStatus.danger,
+ label: 'onError'
+ }
+ }
+ if (target) result.push(node);
+ } else {
+ const uri: string = step.uri;
+ const component = uri?.split(":")?.[0];
+ const name = step.parameters.name || step.parameters.address;
+ if (INTERNAL_COMPONENTS.includes(component)) {
+ const target = TopologyUtils.getRouteIdByUriAndName(tins, uri, name);
+ const node: EdgeModel = {
+ id: 'internal-' + ton.id + '-' + index,
+ type: 'edge',
+ source: 'route-' + ton.routeId,
+ target: target,
+ edgeStyle: EdgeStyle.solid,
+ animationSpeed: EdgeAnimationSpeed.medium,
+ data: {
+ label: uri
+ }
+ }
+ if (target) result.push(node);
+ }
+ }
+ });
+ return result;
+}
+
+export function getModel(projectId: string, files: IntegrationFile[], showGroups: boolean,
+ selectFile: (fileName: string) => void,
+ setDisabled: (fileName: string, elementId: string, disabled: boolean) => void,
+ deleteRoute: (fileName: string, routeId: string) => void,
+ setRouteGroup: (fileName: string, routeId: string, groupName: string) => void,
+ openApiJson?: string, asyncApiJson?: string, showStats?: boolean): Model {
+ const tasyncapis = asyncApiJson ? [TopologyUtils.findTopologyAsyncApiNodes(asyncApiJson, projectId)] : [];
+ const integrations = getIntegrations(files);
+ const troutes = TopologyUtils.findTopologyRouteNodes(integrations);
+ const tins: any[] = TopologyUtils.findTopologyRoutesIncomingNodes(troutes);
+ const tons: any[]= TopologyUtils.findTopologyRoutesOutgoingNodes(troutes);
+ const topenapis = openApiJson ? [TopologyUtils.findTopologyOpenApiNodes(openApiJson)] : [];
+
+ const trestns = TopologyUtils.findTopologyRestNodes(integrations) || [];
+
+ const trcs = TopologyUtils.findTopologyRouteConfigurationNodes(integrations);
+ const trcons = TopologyUtils.findTopologyRouteConfigurationOutgoingNodes(integrations);
+
+ const nodes: NodeModel[] = [];
+
+ nodes.push(...getRestNodes(trestns))
+ nodes.push(...getOpenApiNodes(topenapis, showStats))
+ // nodes.push(...getAsyncApiNodes(tasyncapis))
+ nodes.push(...getRoutes(troutes, tasyncapis?.at(0), showStats))
+ nodes.push(...getRouteConfigurations(trcs))
+ const uriNodes = getUniqueUriNodes(tons, tins, troutes);
+ if (showGroups) {
+ nodes.push(...getIncomingNodes(tins))
+ nodes.push(...getOutgoingNodes(tons))
+ nodes.push(...getOutgoingNodes(trcons))
+ } else {
+ nodes.push(...uriNodes);
+ }
+
+ const edges: EdgeModel[] = [];
+ const uriEdges = getUriEdges(uriNodes);
+ if (showGroups) {
+ edges.push(...getIncomingEdges(tins));
+ edges.push(...getOutgoingEdges(tons));
+ } else {
+ edges.push(...uriEdges);
+ }
+ edges.push(...getRestEdges(trestns, tins));
+ edges.push(...getOpenApiEdges(topenapis, tins, trestns));
+ // edges.push(...getAsyncApiEdges(tasyncapis));
+ edges.push(...getInternalEdges(tons, tins));
+ edges.push(...getInternalEdges(trcons, tins));
+
+ // Groups
+ const externalEdges = getExternalEdges(tons, tins);
+ const groups: NodeModel[] = [];
+ if (showGroups) {
+ const hasOpenApi = topenapis.length > 0;
+ if (hasOpenApi) {
+ const children3 = [
+ ...topenapis.map(o => o.fileName),
+ ...(trestns?.map(i => i.id) ?? [])
+ ];
+ groups.push({
+ id: 'karavan-open-api-group',
+ children: children3,
+ type: 'group',
+ group: true,
+ label: 'OpenAPI group',
+ style: {
+ padding: 20,
+ },
+ })
+ }
+
+ const asyncReceive: string[] = [];
+ const asyncSend: string[] = [];
+ // tasyncapis.forEach((asyn, i) => {
+ // asyn.operations.forEach((operation) => {
+ // if (operation.action === "send") {
+ // asyncSend.push(`asyncapi-operation-${operation.operationId}`);
+ // } else {
+ // asyncReceive.push(`asyncapi-operation-${operation.operationId}`);
+ // }
+ // })
+ // });
+
+ const children1 = [
+ ...asyncReceive,
+ ...tins.filter(i => i.type === 'external').map(i => i.id),
+ ...(!hasOpenApi ? trestns.map(i => i.id) : []),
+ ];
+ groups.push({
+ id: 'karavan-consumer-group',
+ children: children1,
+ type: 'group',
+ group: true,
+ label: 'Consumers',
+ style: {
+ padding: 20,
+ }
+ })
+
+ const children2 = [
+ ...asyncSend,
+ ...tons.filter(i => i.type === 'external').map(i => i.id)
+ ];
+ groups.push({
+ id: 'karavan-producer-group',
+ children: children2,
+ type: 'group',
+ group: true,
+ label: 'Producers',
+ style: {
+ padding: 20,
+ },
+ })
+
+ } else {
+ // edges.push(...externalEdges);
+ }
+
+ if (showGroups) {
+ const routeGroups: Map<string, string []> = new Map<string, string []>;
+ troutes.forEach(troute => {
+ if (troute.route.group && troute.route.group.trim().length > 0) {
+ const groupName = troute.route.group.trim();
+ const children = routeGroups.get(groupName) ?? [];
+ children.push(troute.id)
+ routeGroups.set(groupName, children);
+ }
+ })
+
+ // uriNodes.filter(uriNode => uriNode.data.groups?.length === 1).forEach(uriNode => {
+ // const groupName = uriNode.data.groups[0];
+ // const children = routeGroups.get(groupName) ?? [];
+ // children.push(uriNode.id)
+ // routeGroups.set(groupName, children);
+ // })
+
+ routeGroups.keys().forEach(groupName => {
+ groups.push({
+ id: groupName,
+ children: routeGroups.get(groupName) ?? [],
+ type: 'group',
+ group: true,
+ label: groupName,
+ style: {
+ padding: 20,
+ },
+ })
+ })
+
+ // const externalGroups:Map<string, string []> = new Map<string, string []>;
+ // externalEdges.forEach(edge => {
+ // if (edge.source && edge.target) {
+ // const edgeName = edge.source + '-' + edge.target;
+ // const children = routeGroups.get(edgeName) ?? [];
+ // children.push(edge.source)
+ // children.push(edge.target)
+ // externalGroups.set(edgeName, children);
+ // }
+ // })
+ //
+ // externalGroups.keys().forEach(groupName => {
+ // groups.push({
+ // id: groupName,
+ // children: externalGroups.get(groupName) ?? [],
+ // type: 'group',
+ // group: true,
+ //
+ // style: {
+ // padding: 20,
+ // },
+ // })
+ // })
+ }
+
+ nodes.push(...groups)
+
+ const nodesWithHook = nodes.map(node => {
+ const data = node.data || {}
+ data.selectFile = selectFile;
+ data.setDisabled = setDisabled;
+ data.deleteRoute = deleteRoute;
+ data.setRouteGroup = setRouteGroup;
+ node.data = data;
+ return node;
+ })
+
+ return {nodes: nodesWithHook, edges: edges, graph: {id: 'graph', type: 'graph', layout: 'elements'}};
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.css b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.css
new file mode 100644
index 00000000..005e0e99
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.css
@@ -0,0 +1,52 @@
+.karavan .topology-panel .topology-beans-card {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+}
+
+.karavan .topology-panel .topology-beans-card .pf-v6-c-card__title {
+ padding: 5px;
+ display: flex;
+ justify-content: center;
+}
+
+.karavan .topology-panel .topology-beans-card .card-body {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+ padding: 0 10px 10px 10px;
+}
+
+.karavan .topology-panel .topology-beans-card .pf-v6-c-label {
+ display: flex;
+ justify-content: start;
+ border-color: var(--pf-t--color--orange--40);
+ border-width: 1px;
+ border-style: solid;
+}
+
+.karavan .topology-panel .topology-beans-card .pf-v6-c-label__content::before {
+ background: var(--pf-topology__node__background--Fill);
+}
+
+.karavan .topology-panel .topology-beans-card .bean-button {
+ padding: 0;
+ display: flex;
+ background-color: transparent;
+}
+
+.karavan .topology-panel .topology-beans-card .pf-v6-c-badge {
+ min-width: 32px;
+ font-weight: normal;
+}
+
+.karavan .topology-panel .topology-beans-card .pf-v6-c-label__icon {
+ height: unset;
+}
+
+.karavan .topology-panel .topology-beans-card .bean-button .pf-v6-c-button__icon {
+ margin-top: auto;
+ margin-bottom: auto;
+ height: 16px;
+ width: 16px;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.tsx
new file mode 100644
index 00000000..e5bf40f2
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyBeans.tsx
@@ -0,0 +1,77 @@
+/*
+ * 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 * as React from 'react';
+import './TopologyBeans.css';
+import {Button, Card, CardBody, CardTitle, Label,} from "@patternfly/react-core";
+import {TopologyUtils} from "@karavan-core/api/TopologyUtils";
+import {useFilesStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
+import {getIntegrations} from "./TopologyApi";
+import JavaIcon from "@patternfly/react-icons/dist/js/icons/java-icon";
+import {useTopologyHook} from "./useTopologyHook";
+import {camelIcon, CamelUi} from "@features/project/designer/utils/CamelUi";
+
+export function TopologyBeans() {
+
+ const {selectFile} = useTopologyHook();
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const iFiles = files.map(f => new IntegrationFile(f.name, f.code))
+ const integrations = getIntegrations(iFiles);
+ const beans = TopologyUtils.findTopologyBeanNodes(integrations);
+
+ return (
+ beans.length > 0
+ ? <Card isCompact className="topology-beans-card">
+ <CardTitle>Beans</CardTitle>
+ <CardBody className='card-body'>
+ {beans.map((bean, index) => {
+ return (
+ <Label key={index} className='bean-label'>
+ <Button variant='link'
+ className='bean-button'
+ icon={CamelUi.getIconFromSource(camelIcon)}
+ onClick={() => {
+ selectFile(bean.fileName)
+ }}
+ >
+ {bean.name}
+ </Button>
+ </Label>
+ )
+ })}
+ {files.filter(f => f.name.endsWith('.java')).map((file, index) => {
+ return (
+ <Label key={index}>
+ <Button variant='link'
+ className='bean-button'
+ icon={<JavaIcon className='orange'/>}
+ onClick={() => {
+ selectFile(file.name)
+ }}
+ >
+ {file.name?.split('.')?.[0]}
+ </Button>
+ </Label>
+ )
+ })}
+ </CardBody>
+ </Card>
+ : <></>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyElkLayout.ts b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyElkLayout.ts
new file mode 100644
index 00000000..972d3a0e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyElkLayout.ts
@@ -0,0 +1,222 @@
+import {BaseLayout, Graph, GRAPH_LAYOUT_END_EVENT, Layout, LayoutOptions, Node} from '@patternfly/react-topology';
+import ELK, {ElkExtendedEdge, ElkNode} from 'elkjs/lib/elk.bundled';
+import Point from "@patternfly/react-topology/src/geom/Point";
+import Dimensions from "@patternfly/react-topology/src/geom/Dimensions";
+
+// --- CONFIGURATION ---
+const getRootOptions = (): any => {
+ return {
+ 'elk.algorithm': 'layered',
+ 'elk.direction': 'DOWN',
+ "elk.edgeRouting" : "ORTHOGONAL",
+ "elk.separateConnectedComponents": "true",
+ 'elk.spacing.nodeNode': '75',
+ 'elk.spacing.edgeNode': '75',
+ 'elk.portConstraints': 'FREE',
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
+
+ "elk.layered.thoroughness": "100",
+ 'elk.layered.nodePlacement.bk.fixedAlignment': 'BALANCED',
+ 'elk.layered.unnecessaryBendpoints': 'false',
+ 'elk.layered.spacing.edgeEdgeBetweenLayers': '20',
+ // 'elk.layered.layering.strategy': 'NETWORK_SIMPLEX',
+ 'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX',
+ "elk.layered.compaction.postCompaction.strategy": "EDGE_LENGTH",
+ // "elk.layered.crossingMinimization.strategy": "LAYER_SWEEP",
+ // "elk.layered.crossingMinimization.greedySwitch.type": "TWO_SIDED",
+ 'elk.layered.spacing.nodeNodeBetweenLayers': '60',
+ 'elk.layered.spacing.edgeNodeBetweenLayers': '20',
+ 'elk.layered.cycleBreaking.strategy': 'GREEDY',
+ };
+};
+
+const GROUP_OPTIONS = {
+ 'elk.padding': '[top=40,left=40,bottom=40,right=40]',
+ 'elk.portConstraints': 'FREE',
+ "elk.layered.crossingMinimization.strategy": "LAYER_SWEEP",
+ 'elk.layered.layering.strategy': 'NETWORK_SIMPLEX',
+ 'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX',
+};
+
+const NODE_OPTIONS = {
+ 'elk.portConstraints': 'FREE',
+};
+
+const EDGE_OPTIONS = {
+ 'elk.priority': '10',
+ 'elk.layered.priority.direction': '0',
+ 'elk.layered.priority.straightness': '2000',
+ 'elk.edgeRouting': 'ORTHOGONAL',
+};
+
+
+export class TopologyElkLayout extends BaseLayout implements Layout {
+ private elk: InstanceType<typeof ELK>;
+
+ constructor(graph: Graph, options?: Partial<LayoutOptions>) {
+ super(graph, options);
+ this.elk = new ELK();
+ }
+
+ protected startLayout(graph: Graph): void {
+ const elkGraph = this.createElkGraph(graph);
+
+ this.elk.layout(elkGraph)
+ .then((layoutedGraph) => {
+ this.applyLayout(layoutedGraph);
+ // Optional: Update edge bend points if your PF version supports it
+ // this.updateEdgeSegments(layoutedGraph, graph);
+
+ graph.getController().fireEvent(GRAPH_LAYOUT_END_EVENT, { graph });
+ })
+ .catch((err) => console.error('ELK Layout Failed:', err));
+ }
+
+ // --- MAPPING INPUT ---
+
+ private createElkGraph(graph: Graph): ElkNode {
+ return {
+ id: 'root',
+ layoutOptions: getRootOptions(),
+ children: graph.getNodes().map(node => this.mapNodeToElk(node)),
+ edges: this.mapEdgesToElk(graph)
+ };
+ }
+
+ private estimatedLabelWidth(text: string) {
+ // ~7px per char + padding; adjust to your font
+ return Math.min(120, Math.max(20, 64 + text.length * 7));
+ }
+
+ private mapNodeToElk(node: Node): ElkNode {
+ const children = node.getNodes().sort((a, b) => Math.random() - 0.5);
+ const isGroup = node.isGroup();
+ const dims = node.getDimensions();
+
+ const ICON_W = 75; // your circle/icon area
+
+ const label = node.getLabel?.() ?? node.getId(); // however you get label
+ const width = Math.max(ICON_W, this.estimatedLabelWidth(label));
+ const height = Math.max(60, dims.height || 60);
+
+ if (!isGroup) {
+ return {
+ id: node.getId(),
+ width: width,
+ height: height,
+ layoutOptions: NODE_OPTIONS,
+ };
+ } else {
+ return {
+ id: node.getId(),
+ children: children.map(child => this.mapNodeToElk(child)),
+ layoutOptions: GROUP_OPTIONS
+ };
+ }
+ }
+
+ private mapEdgesToElk(graph: Graph): ElkExtendedEdge[] {
+ // We map ALL edges at the root.
+ // Since we use 'INCLUDE_CHILDREN', ELK handles the hierarchy routing automatically.
+ return graph.getEdges().map(edge => {
+ const s = edge.getSource().getId();
+ const t = edge.getTarget().getId();
+ return ({
+ id: edge.getId(),
+ sources: [`${s}`],
+ targets: [`${t}`],
+ layoutOptions: EDGE_OPTIONS,
+ });
+ });
+ }
+
+ // --- APPLYING OUTPUT ---
+
+ private getNode(id: string): Node | undefined {
+ // Helper to find node even if nested deep in groups
+ return this.graph.getNodes().find(n => n.getId() === id)
+ || this.graph.getNodes().flatMap(n => n.getNodes()).find(n => n.getId() === id);
+ }
+
+ private applyLayout(elkNode: ElkNode, parentX = 0, parentY = 0) {
+ if (elkNode.id !== 'root') {
+ const pfNode = this.getNode(elkNode.id);
+ if (pfNode) {
+ // ELK coordinates are relative to parent.
+ // PF usually wants absolute, so we accumulate parent offsets.
+ const absoluteX = (elkNode.x ?? 0) + parentX;
+ const absoluteY = (elkNode.y ?? 0) + parentY;
+
+ pfNode.setPosition(new Point(absoluteX, absoluteY));
+
+ if (pfNode.isGroup() && elkNode.width && elkNode.height) {
+ pfNode.setDimensions(new Dimensions(elkNode.width, elkNode.height));
+ }
+ }
+ }
+
+ // Recurse with current node's absolute position as the new parent offset
+ if (elkNode.children) {
+ const currentX = (elkNode.id === 'root') ? 0 : (elkNode.x ?? 0) + parentX;
+ const currentY = (elkNode.id === 'root') ? 0 : (elkNode.y ?? 0) + parentY;
+
+ elkNode.children.forEach((child) => {
+ this.applyLayout(child, currentX, currentY);
+ });
+ }
+ }
+
+ /**
+ * Optional: ELK calculates complex routes to avoid nodes.
+ * If we don't apply these bend points, the frontend just draws a straight line
+ * between the new node positions, ignoring ELK's hard work.
+ */
+ private updateEdgeSegments(elkNode: ElkNode, graph: Graph) {
+ const allElkEdges: ElkExtendedEdge[] = [];
+ const collectEdges = (node: ElkNode) => {
+ if (node.edges) allElkEdges.push(...node.edges);
+ if (node.children) node.children.forEach(collectEdges);
+ };
+ collectEdges(elkNode);
+
+ allElkEdges.forEach(elkEdge => {
+ const pfEdge = graph.getEdges().find(e => e.getId() === elkEdge.id);
+ if (!pfEdge || !elkEdge.sections || elkEdge.sections.length === 0) return;
+
+ const section = elkEdge.sections[0];
+ const bendPoints = section.bendPoints || [];
+
+ if (bendPoints.length > 0) {
+ // Check if these bendpoints actually create a deviation from a straight line
+ // This prevents "jittery" lines that are 99% straight
+ const start = section.startPoint;
+ const end = section.endPoint;
+
+ const isMeaningful = bendPoints.some(bp => {
+ const distToStraightLine = this.pointToLineDistance(bp, start, end);
+ return distToStraightLine > 2; // Threshold in pixels
+ });
+
+ if (isMeaningful) {
+ // Map ELK points to PatternFly Points
+ const bends = bendPoints.map(bp => new Point(bp.x, bp.y));
+ pfEdge.setBendpoints(bends);
+ } else {
+ pfEdge.setBendpoints([]);
+ }
+ } else {
+ pfEdge.setBendpoints([]);
+ }
+ });
+ }
+
+// Helper to detect if a bendpoint is just a point on a straight line
+ private pointToLineDistance(p: {x: number, y: number}, a: {x: number, y: number}, b: {x: number, y: number}) {
+ const numerator = Math.abs((b.y - a.y) * p.x - (b.x - a.x) * p.y + b.x * a.y - b.y * a.x);
+ const denominator = Math.sqrt(Math.pow(b.y - a.y, 2) + Math.pow(b.x - a.x, 2));
+ return denominator === 0 ? 0 : numerator / denominator;
+ }
+
+ protected updateLayout(): void {}
+ protected stopSimulation(): void {}
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.css b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.css
new file mode 100644
index 00000000..d1f3d309
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.css
@@ -0,0 +1,68 @@
+.karavan .topology-panel .topology-legend-card {
+ position: absolute;
+ bottom: 6px;
+ right: 6px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-card__title {
+ padding: 5px;
+ display: flex;
+ justify-content: center;
+ margin-left: 3px;
+}
+
+.karavan .topology-panel .topology-legend-card .card-body {
+ display: flex;
+ flex-direction: row;
+ gap: 5px;
+ padding: 10px 10px 10px 10px;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-label {
+ border-width: 1px;
+ border-style: solid;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-label__content::before {
+ background: var(--pf-topology__node__background--Fill);
+}
+
+.karavan .topology-panel .topology-legend-card .orange {
+ border-color: var(--pf-t--color--orange--40);
+}
+
+.karavan .topology-panel .topology-legend-card .route-template {
+ border-style: dashed;
+}
+
+.karavan .topology-panel .topology-legend-card .blue {
+ border-color: var(--pf-t--color--blue--40);
+}
+
+.karavan .topology-panel .topology-legend-card .green {
+ border-color: var(--pf-t--color--green--40);;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-label__content {
+ gap: 3px;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-badge {
+ min-width: 32px;
+ font-weight: normal;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-label__icon {
+ height: 16px;
+ width: 16px;
+ margin: 0 0 0 0;
+}
+
+.karavan .topology-panel .topology-legend-card .pf-v6-c-label__icon svg{
+ height: 16px;
+ width: 16px;
+ margin: 0;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.tsx
new file mode 100644
index 00000000..eaaaccb3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyLegend.tsx
@@ -0,0 +1,38 @@
+/*
+ * 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 * as React from 'react';
+import './TopologyLegend.css';
+import {Card, CardBody, CardTitle, Label,} from "@patternfly/react-core";
+import {getDesignerIcon, OpenApiIcon} from "@features/project/designer/icons/KaravanIcons";
+
+export function TopologyLegend () {
+
+ return (
+ <Card isCompact className="topology-legend-card">
+ <CardTitle>Legend</CardTitle>
+ <CardBody className='card-body'>
+ <Label className='orange' icon={<div style={{display: 'flex'}}>{getDesignerIcon('route')}</div>}>Route</Label>
+ <Label className='orange' icon={<div style={{display: 'flex', gap: '6px'}}><OpenApiIcon/></div>}>OpenAPI</Label>
+ <Label className='orange' icon={<div style={{display: 'flex'}}>{getDesignerIcon('rest')}</div>}>REST</Label>
+ <Label className='orange route-template'>Route Template</Label>
+ <Label className='blue'>Component</Label>
+ <Label className='green'>Kamelet</Label>
+ </CardBody>
+ </Card>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyTab.tsx
new file mode 100644
index 00000000..9d100619
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyTab.tsx
@@ -0,0 +1,191 @@
+/*
+ * 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 * as React from 'react';
+import {useState} from 'react';
+import {
+ action,
+ createTopologyControlButtons,
+ defaultControlButtonsOptions,
+ Graph,
+ GRAPH_LAYOUT_END_EVENT,
+ Layout,
+ LayoutFactory,
+ Model,
+ SELECTION_EVENT,
+ TopologyControlBar,
+ TopologyView,
+ Visualization,
+ VisualizationProvider,
+ VisualizationSurface,
+} from '@patternfly/react-topology';
+import {getCustomComponentFactory} from "@features/project/project-topology/CustomComponentFactory";
+import {shallow} from "zustand/shallow";
+import {useTopologyStore} from "@stores/TopologyStore";
+import {useDesignerStore} from "@features/project/designer/DesignerStore";
+import {IntegrationFile} from "@karavan-core/model/IntegrationDefinition";
+import {TopologyBeans} from "@features/project/project-topology/TopologyBeans";
+import {getModel} from "@features/project/project-topology/TopologyApi";
+import {useTopologyHook} from "@features/project/project-topology/useTopologyHook";
+import {TopologyLegend} from "@features/project/project-topology/TopologyLegend";
+import {ModalConfirmation, ModalConfirmationProps} from "@shared/ui/ModalConfirmation";
+import {EyeIcon, EyeSlashIcon} from '@patternfly/react-icons';
+import {ArrayNumbers, GroupObjects, UngroupObjects} from '@carbon/icons-react';
+import {useFilesStore, useProjectStore} from "@stores/ProjectStore";
+import {NODE_POSITIONED_EVENT} from "@patternfly/react-topology/src/types";
+import {OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
+import {runInAction} from "mobx";
+import {TopologyToolbar} from "@features/project/project-topology/TopologyToolbar";
+import {TopologyElkLayout} from "@features/project/project-topology/TopologyElkLayout";
+
+interface Props {
+ asyncApiJson?: string
+}
+
+export function TopologyTab(props: Props) {
+
+ const {asyncApiJson } = props;
+ const [setFileName, showGroups, setShowGroups, showBeans, setShowBeans, showLegend, setShowLegend]
+ = useTopologyStore((s) => [s.setFileName, s.showGroups, s.setShowGroups, s.showBeans, s.setShowBeans, s.showLegend, s.setShowLegend]);
+ const [showStats, setShowStats] = useTopologyStore((s) => [s.showStats, s.setShowStats]);
+ const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], shallow)
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [project] = useProjectStore((s) => [s.project], shallow);
+ const [confirmationProps, setConfirmationProps] = useState<ModalConfirmationProps>();
+ const {selectFile, setDisabled, deleteRoute, setRouteGroup} = useTopologyHook(setConfirmationProps);
+
+ const camelFiles = files
+ .filter(f => f.name.endsWith('.camel.yaml'))
+ // .filter(f => search === '' || filedFound.includes(f.name))
+ .map(f => new IntegrationFile(f.name, f.code));
+ const openApiFile = files.filter(f => f.name === OPENAPI_FILE_NAME_JSON)?.at(0);
+ const openApiJson = openApiFile?.code;
+
+ function setTopologySelected(model: Model, ids: string []) {
+ if (ids.length > 0) {
+ const node = model.nodes?.filter(node => node.id === ids[0]);
+ if (node && node.length > 0) {
+ const data = node[0].data;
+ if (data && data.step) {
+ setFileName(data.fileName)
+ setSelectedStep(data.step)
+ } else {
+ setSelectedStep(undefined);
+ setFileName(undefined)
+ }
+ }
+ }
+ }
+
+ const customLayoutFactory: LayoutFactory = (type: string, graph: Graph): Layout => {
+ // return new TopologyDagreLayout(graph, {}, straightEdges);
+ return new TopologyElkLayout(graph, {});
+ };
+
+ const controller = React.useMemo(() => {
+ const model = getModel(project.projectId, camelFiles, showGroups, selectFile, setDisabled, deleteRoute, setRouteGroup, openApiJson, asyncApiJson, showStats);
+ const controller = new Visualization();
+
+ controller.registerLayoutFactory((type, graph) => customLayoutFactory(type, graph));
+ controller.registerComponentFactory(getCustomComponentFactory(model, false));
+
+ controller.addEventListener(SELECTION_EVENT, args => setTopologySelected(model, args));
+ controller.addEventListener(GRAPH_LAYOUT_END_EVENT, () => {
+ runInAction(() => {
+ controller.getGraph().fit(90);
+ });
+ });
+ controller.addEventListener(NODE_POSITIONED_EVENT, (args: any) => {
+ });
+ controller.fromModel(model, false);
+ return controller;
+ }, [files, showGroups, asyncApiJson, showStats]);
+
+ function getButtonTitle(title: string, icon: React.ReactNode) {
+ return (
+ <div>
+ {icon}
+ <span style={{marginLeft: '3px'}}>{title}</span>
+ </div>
+ )
+ }
+
+ const controlButtons = React.useMemo(() => {
+ return createTopologyControlButtons({
+ ...defaultControlButtonsOptions,
+ zoomInCallback: action(() => {
+ controller.getGraph().scaleBy(4 / 3);
+ }),
+ zoomOutCallback: action(() => {
+ controller.getGraph().scaleBy(0.75);
+ }),
+ legendCallback: action(() => {
+ setShowLegend(!showLegend)
+ }),
+ legendIcon: showLegend ? getButtonTitle('Legend', <EyeIcon/>) : getButtonTitle('Legend', <EyeSlashIcon/>),
+ legendTip: 'Show/Hide Legend',
+ fitToScreenCallback: action(() => {
+ controller.getGraph().fit(80);
+ }),
+ resetViewCallback: action(() => {
+ controller.getGraph().reset();
+ controller.getGraph().layout();
+ }),
+ customButtons: [
+ {
+ id: 'showGroups',
+ icon: showGroups ? getButtonTitle('Grouped', <GroupObjects className='carbon'/> ) : getButtonTitle('Ungrouped', <UngroupObjects className='carbon'/>) ,
+ tooltip: 'Switch Ungrouped/Grouped',
+ callback: id => setShowGroups(!showGroups)
+ },
+ {
+ id: 'showBeans',
+ icon: showBeans ? getButtonTitle('Beans', <EyeIcon/>) : getButtonTitle('Beans', <EyeSlashIcon/>),
+ tooltip: 'Show/Hide Beans',
+ callback: id => setShowBeans(!showBeans)
+ },
+ {
+ id: "stats",
+ icon: <ArrayNumbers className='carbon'/>,
+ tooltip: showStats ? "Hide stats" : "Show stats",
+ callback: (id: any) => setShowStats(!showStats),
+ }
+ ],
+ });
+ }, [controller, showLegend, showBeans, showGroups]);
+
+ return (
+ <>
+ <TopologyToolbar/>
+ <TopologyView
+ className="topology-panel"
+ controlBar={
+ <TopologyControlBar
+ controlButtons={controlButtons}
+ />
+ }
+ >
+ <VisualizationProvider controller={controller}>
+ <VisualizationSurface/>
+ {showBeans && <TopologyBeans/>}
+ {showLegend && <TopologyLegend/>}
+ {confirmationProps?.isOpen && <ModalConfirmation {...confirmationProps}/>}
+ </VisualizationProvider>
+ </TopologyView>
+ </>
+ );
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyToolbar.tsx
new file mode 100644
index 00000000..ead29fef
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/TopologyToolbar.tsx
@@ -0,0 +1,102 @@
+/*
+ * 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 * as React from 'react';
+import {MouseEventHandler, ReactElement} from 'react';
+import {Button} from '@patternfly/react-core';
+import {shallow} from "zustand/shallow";
+import {useAppConfigStore} from '@stores/ProjectStore';
+import {useTopologyHook} from '@features/project/project-topology/useTopologyHook';
+import {useRouteDesignerHook} from "@features/project/designer/route/useRouteDesignerHook";
+import {APPLICATION_PROPERTIES, DOCKER_COMPOSE, DOCKER_STACK} from "@models/ProjectModels";
+import {ProjectTitle} from "@features/project/ProjectTitle";
+import {useProjectFunctions} from "@features/project/ProjectContext";
+import {AddLarge} from "@carbon/icons-react";
+
+export function TopologyToolbar() {
+
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const isDev = config.environment === 'dev';
+
+ const {
+ createNewBean,
+ createRouteConfiguration,
+ createOpenApi,
+ createNewKamelet,
+ project
+ } = useProjectFunctions();
+ const {openSelector} = useRouteDesignerHook();
+
+ const {selectFile} = useTopologyHook();
+
+ function getInfraButton(): ReactElement {
+ const isKubernetes = config.infrastructure === 'kubernetes';
+ const swarmMode = config.swarmMode;
+ const fileName = isKubernetes
+ ? 'deployment.jkube.yaml'
+ : (swarmMode ? DOCKER_STACK : DOCKER_COMPOSE);
+
+ return (
+ <div>
+ <Button variant={"tertiary"}
+ className='bean-button'
+ // icon={<OutlinedFileAltIcon/>}
+ onClick={() => {
+ selectFile(fileName)
+ }}
+ >
+ {isKubernetes ? "Deployment" : "Compose"}
+ </Button>
+ </div>
+ )
+ }
+
+ function getButton(caption: string,
+ variant?: 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning' | 'link' | 'plain' | 'control' | 'stateful',
+ icon?: ReactElement,
+ onClick?: MouseEventHandler<any> | undefined): ReactElement {
+ return (
+ <div>
+ <Button className="dev-action-button "
+ isDisabled={!isDev}
+ icon={icon}
+ variant={variant}
+ onClick={onClick}
+ >
+ {caption}
+ </Button>
+ </div>
+ )
+ }
+
+
+ return (
+ <div className='topology-toolbar'>
+ <div className="group-switch">
+ <ProjectTitle/>
+ </div>
+
+ {getButton("Route", 'primary', <AddLarge className='carbon'/>, event => openSelector(undefined, undefined))}
+ {getButton("Route Configuration", 'secondary', <AddLarge className='carbon'/>, event => createRouteConfiguration())}
+ {getButton("Route Template", 'secondary', <AddLarge className='carbon'/>, event => openSelector(undefined, undefined, true, undefined, true))}
+ {getButton("Kamelet", 'tertiary', <AddLarge className='carbon'/>, event => createNewKamelet())}
+ {getButton("Bean", 'tertiary', <AddLarge className='carbon'/>, event => createNewBean())}
+ {getButton("Properties", 'tertiary', undefined, event => selectFile(APPLICATION_PROPERTIES))}
+ {getInfraButton()}
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/topology.css b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/topology.css
new file mode 100644
index 00000000..241b3cf2
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/topology.css
@@ -0,0 +1,202 @@
+.karavan .topology-toolbar {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 16px 8px 16px;
+ position: relative;
+ text-wrap: nowrap;
+}
+
+.karavan .topology-toolbar::before {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ content: "";
+ border-bottom: var(--pf-t--global--border--color--default) solid var(--pf-t--global--border--width--box--default);
+ border-radius: inherit;
+}
+
+.karavan .topology-toolbar .group-switch {
+ display: flex;
+ flex-direction: row;
+ flex-grow: 4;
+ margin-top: auto;
+ margin-bottom: auto;
+ margin-left: 0;
+ gap: 16px;
+}
+
+.karavan .topology-toolbar .dev-action-button {
+ padding-left: 12px;
+ padding-right: 12px;
+}
+
+.karavan .topology-panel .pf-topology-control-bar {
+ .pf-v6-c-toolbar {
+ padding: 6px;
+ }
+}
+
+.karavan .topology-panel .properties {
+ padding: 16px;
+ overflow: auto;
+}
+
+.karavan .topology-panel .properties .headers {
+ display: none;
+}
+
+.karavan .topology-panel .common-node {
+ cursor: pointer;
+ .validation-icon {
+ height: 21px;
+ width: 21px;
+ }
+ .validation-icon-danger {
+ color: var(--pf-t--global--icon--color--status--danger--default);
+ fill: var(--pf-t--global--icon--color--status--danger--default);
+ }
+ .validation-icon-pending {
+ fill: var(--pf-t--global--color--brand--default);
+ color: var(--pf-t--global--color--brand--default);
+ }
+}
+
+.karavan .topology-panel .common-node .icon {
+ height: 32px;
+ width: 32px;
+}
+
+.karavan .topology-panel .common-node-R {
+
+}
+
+.karavan .topology-panel .pf-v6-c-panel__header {
+ padding-bottom: 0;
+}
+
+.karavan .topology-panel .file-button {
+ padding: 0;
+}
+
+.karavan .topology-toolbar .button-icon-k8s {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.125em;
+}
+
+.karavan .topology-panel .pf-topology__group .pf-topology__group__background {
+ stroke-width: 2px;
+ /*stroke-dasharray: 3;*/
+}
+
+.karavan .topology-panel .pf-topology__group .pf-topology__node__label__background {
+ opacity: 0.5;
+}
+
+.karavan .topology-panel .auto-start .badge {
+ fill: var(--pf-topology__node__label__background--Fill);
+ stroke-width: var(--pf-topology__node__label__background--StrokeWidth);
+ stroke: var(--pf-topology__node__label__background--Stroke);
+}
+
+.karavan .topology-panel .auto-start .text {
+ fill: var(--pf-topology__node__label__text--Fill);
+}
+
+.karavan .topology-panel .disable-node {
+ opacity: 0.6;
+ filter: grayscale(100%);
+}
+
+.karavan .pf-topology__node__label__badge > text {
+ fill: white;
+}
+
+.karavan .topology-panel .common-node-RT .pf-topology__node__background {
+ outline: 1px dashed grey;
+ outline-offset: 2px;
+ border-radius: 9px;
+}
+
+.karavan .topology-panel .gen-route-decorator {
+ background-color: red;
+ circle {
+ stroke: var(--pf-t--global--icon--color--status--warning--default);
+ }
+ svg {
+ fill: var(--pf-t--global--icon--color--status--warning--default);
+ transform: translate(1px, -1px);
+ }
+}
+
+.pf-topology__group__label .pf-topology__node__label__background {
+ fill: grey;
+}
+
+.pf-topology__node.topology-color-component {
+ --pf-topology__node__label__background--Stroke: var(--pf-t--global--color--brand--100);
+}
+
+.pf-topology__node.topology-color-component .pf-topology__node__background {
+ --pf-topology__node__background--Stroke: var(--pf-t--global--color--brand--100);
+}
+
+.pf-topology__node.topology-color-kamelet {
+ --pf-topology__node__label__background--Stroke: #6ec664;
+}
+
+.pf-topology__node.topology-color-kamelet .pf-topology__node__background {
+ --pf-topology__node__background--Stroke: #6ec664;
+}
+
+.pf-topology__node.topology-color-gen-route {
+ .pf-topology__node__background {
+ --pf-topology__node__background--Stroke: #ef9234;
+ }
+ .icon-wrapper svg {
+ fill: #ef9234;
+ }
+}
+
+.pf-topology__edge {
+ text,
+ .pf-topology__edge__tag__background {
+ visibility: hidden;
+ }
+}
+.pf-topology__edge:hover {
+ text,
+ .pf-topology__edge__tag__background {
+ visibility: visible;
+ }
+}
+
+.karavan .topology-panel .node-metric {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: space-between;
+ justify-items: center;
+ width: 100%;
+ height: 100%;
+ .metric {
+ font-weight: normal;
+ }
+
+ .inflight-color {
+ color: var(--pf-t--global--background--color--primary--default);
+ background-color: var(--pf-t--global--color--brand--default);
+ }
+
+ .failed-color {
+ color: var(--pf-t--global--text--color--status--on-danger--default);
+ background-color: var(--pf-t--global--color--status--danger--default);
+ }
+ .total-color {
+ color: var(--pf-t--global--text--color--status--on-success--default);
+ background-color: var(--pf-t--global--color--status--success--default);
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/project-topology/useTopologyHook.tsx b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/useTopologyHook.tsx
new file mode 100644
index 00000000..fa4a34b2
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/project-topology/useTopologyHook.tsx
@@ -0,0 +1,128 @@
+/*
+ * 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 {shallow} from "zustand/shallow";
+import {useFilesStore, useFileStore, useProjectStore} from "@stores/ProjectStore";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {RouteDefinition} from "@karavan-core/model/CamelDefinition";
+import {ProjectService} from "@services/ProjectService";
+import {ModalConfirmationProps} from "@shared/ui/ModalConfirmation";
+
+export function useTopologyHook(setConfirmationProps?: React.Dispatch<React.SetStateAction<ModalConfirmationProps | undefined>>) {
+
+ const [setFile] = useFileStore((s) => [s.setFile], shallow);
+ const [files] = useFilesStore((s) => [s.files], shallow);
+ const [setTabIndex, project] = useProjectStore((s) => [s.setTabIndex, s.project], shallow);
+
+ function selectFile(fileName: string) {
+ const file = files.filter(f => f.name === fileName)?.at(0);
+ if (file) {
+ setFile('select', file);
+ setTabIndex(0);
+ }
+ }
+
+ function setDisabled(fileName: string, elementId: string, enable: boolean) {
+ try {
+ const file = files.filter(f => f.name === fileName)?.at(0);
+ if (file) {
+ const integration = CamelDefinitionYaml.yamlToIntegration(file.name, file?.code);
+ const element = CamelDefinitionApiExt.findElementById(integration, elementId);
+ if (element) {
+ if (element.dslName === 'RouteDefinition') {
+ (element as RouteDefinition).autoStartup = enable;
+ } else {
+ (element as any).disabled = enable;
+ }
+ const newIntegration = CamelDefinitionApiExt.updateIntegrationRouteElement(integration, element);
+ file.code = CamelDefinitionYaml.integrationToYaml(newIntegration);
+ ProjectService.updateFile(file, true);
+ }
+
+ }
+ } catch (e: any) {
+ EventBus.sendAlert('Error disabling Route', e?.message);
+ }
+ }
+
+ function deleteRoute(fileName: string, routeId: string) {
+ try {
+ const file = files.filter(f => f.name === fileName)?.at(0);
+ if (file) {
+ const integration = CamelDefinitionYaml.yamlToIntegration(file.name, file?.code);
+ const newIntegration = CamelDefinitionApiExt.deleteRouteFromIntegration(integration, routeId);
+ const isEmpty = newIntegration?.spec.flows?.length === 0 && newIntegration?.spec.template === undefined;
+ const propsClose: ModalConfirmationProps = {
+ isOpen: false,
+ title: '',
+ message: '',
+ onConfirm: () => {
+ },
+ onCancel: () => {
+ }
+ };
+ const props: ModalConfirmationProps = {
+ isOpen: true,
+ title: 'Confirmation',
+ btnConfirmVariant: 'danger',
+ message: `Delete route ${isEmpty ? ' and file ' + fileName : ''}`,
+ onConfirm: () => {
+ if (isEmpty) {
+ ProjectService.deleteFile(file);
+ } else {
+ file.code = CamelDefinitionYaml.integrationToYaml(newIntegration);
+ ProjectService.updateFile(file, true);
+ }
+ setConfirmationProps?.(propsClose)
+ },
+ onCancel: () => setConfirmationProps?.(propsClose)
+ };
+ setConfirmationProps?.({...props})
+ }
+ } catch (e: any) {
+ console.error(e);
+ EventBus.sendAlert('Error deleting Route', e?.message);
+ }
+ }
+
+ function setRouteGroup (fileName: string, elementId: string, groupName: string) {
+ try {
+ const file = files.filter(f => f.name === fileName)?.at(0);
+ if (file) {
+ const integration = CamelDefinitionYaml.yamlToIntegration(file.name, file?.code);
+ const element = CamelDefinitionApiExt.findElementById(integration, elementId);
+ if (element) {
+ if (element.dslName === 'RouteDefinition') {
+ (element as RouteDefinition).group = groupName;
+ }
+ const newIntegration = CamelDefinitionApiExt.updateIntegrationRouteElement(integration, element);
+ file.code = CamelDefinitionYaml.integrationToYaml(newIntegration);
+ ProjectService.updateFile(file, true);
+ }
+
+ }
+ } catch (e: any) {
+ EventBus.sendAlert('Error changing Route group', e?.message);
+ }
+ }
+
+ return {
+ selectFile, setDisabled, deleteRoute, setRouteGroup, project
+ }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/readme/ReadmeTab.tsx b/karavan-app/src/main/webui/src/karavan/features/project/readme/ReadmeTab.tsx
new file mode 100644
index 00000000..82bd30a3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/readme/ReadmeTab.tsx
@@ -0,0 +1,31 @@
+/*
+ * 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 MarkdownPreview from '@uiw/react-markdown-preview';
+import {useFilesStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+
+export function ReadmeTab() {
+
+ const [files] = useFilesStore((s) => [s.files], shallow);
+
+ const markdown = files.find(f => f.name.toLowerCase() === 'readme.md')?.code;
+ return (
+ <MarkdownPreview style={{padding: 16}} source={markdown}/>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/toolbar/BuildToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/BuildToolbar.tsx
new file mode 100644
index 00000000..ecd49b60
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/BuildToolbar.tsx
@@ -0,0 +1,185 @@
+/*
+ * 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, {useState} from 'react';
+import {Button, Content, Label, Modal, ModalBody, ModalFooter, ModalHeader, Tooltip} from '@patternfly/react-core';
+import {KaravanApi} from "@api/KaravanApi";
+import BuildIcon from "@patternfly/react-icons/dist/esm/icons/build-icon";
+import ClockIcon from "@patternfly/react-icons/dist/esm/icons/clock-icon";
+import TagIcon from "@patternfly/react-icons/dist/esm/icons/tag-icon";
+import {useProjectStore} from "@stores/ProjectStore";
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ContainerButton} from "@shared/ui/ContainerButton";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
+
+export function BuildToolbar() {
+
+ const [project] = useProjectStore((s) => [s.project]);
+ const {containers} = useContainerStatusesStore();
+ const [isBuilding, setIsBuilding] = useState<boolean>(false);
+ const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+ const [deleteEntityName, setDeleteEntityName] = useState<string>();
+ const [tag, setTag] = useState<string>('latest');
+
+ function deleteEntity() {
+ const buildName = getBuildName();
+ if (buildName) {
+ KaravanApi.manageContainer(project.projectId, 'build', buildName, 'delete', 'never', res => {
+ EventBus.sendAlert("Container deleted", "Container " + buildName + " deleted", 'info')
+ });
+ }
+ }
+
+ function build() {
+ setIsBuilding(true);
+ KaravanApi.buildProject(project, tag, res => {
+ if (res.status === 200 || res.status === 201) {
+ setIsBuilding(false);
+ } else {
+ console.error(res);
+ EventBus.sendAlert("Error", (res as any)?.response?.data, 'danger')
+ }
+ });
+ }
+
+ function buildButton() {
+ const status = containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0);
+ const isRunning = status?.state === 'running';
+ const buildName = getBuildName();
+ return (
+ <div style={{display: 'flex', gap: '8px'}}>
+ {status !== undefined && <Tooltip content={"Delete build container"}>
+ <Button
+ isDanger
+ // icon={<DeleteIcon/>}
+ className="dev-action-button"
+ variant="danger" onClick={e => {
+ setShowDeleteConfirmation(true);
+ setDeleteEntityName(buildName);
+ }}>Delete</Button>
+ </Tooltip>}
+ <Tooltip content={"Build project"} position={"bottom"}>
+ <Button isLoading={isBuilding ? true : undefined}
+ isDisabled={isBuilding || isRunning}
+ variant="primary"
+ className="project-button dev-action-button"
+ icon={!isBuilding ? <BuildIcon/> : <div></div>}
+ onClick={e => build()}>
+ {isBuilding ? "..." : "Build"}
+ </Button>
+ </Tooltip>
+ </div>
+ )
+ }
+
+ function getContainerStatus() {
+ return containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0);
+ }
+
+ function getBuildName() {
+ const status = getContainerStatus();
+ return status?.containerName;
+ }
+
+ function getBuildState() {
+ const status = getContainerStatus();
+ const buildName = getBuildName();
+ const state = status?.state;
+ let buildTime = 0;
+ if (status?.created) {
+ const start: Date = new Date(status.created);
+ const finish: Date = status.finished !== undefined && status.finished !== null ? new Date(status.finished) : new Date();
+ buildTime = Math.round((finish.getTime() - start.getTime()) / 1000);
+ }
+ const showTime = buildTime && buildTime > 0;
+ const isRunning = state === 'running';
+ const isFailed = state === 'failed';
+ const color = (isRunning ? "blue" : (isFailed ? "red" : "grey"));
+ return (
+ <div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start', gap: '8px'}}>
+ {status && <ContainerButton container={status}/>}
+ {buildName !== undefined && showTime === true && buildTime !== undefined &&
+ <Label icon={<ClockIcon className="not-spinner"/>}
+ color={color}>{buildTime + "s"}</Label>}
+ </div>
+ )
+ }
+
+ function getBuildTag() {
+ const status = containers.filter(c => c.projectId === project.projectId && c.type === 'build').at(0);
+ const state = status?.state;
+ const isRunning = state === 'running';
+ const isExited = state === 'exited';
+ const color = isExited ? "grey" : (isRunning ? "blue" : "grey");
+ return (
+ <Label isEditable={!isRunning} onEditComplete={(_, v) => setTag(v)}
+ icon={<TagIcon className="not-spinner"/>}
+ color={color}>
+ {tag}
+ </Label>
+ )
+ }
+
+ function getDeleteConfirmation() {
+ return (<Modal
+ variant='small'
+ isOpen={showDeleteConfirmation}
+ onClose={() => setShowDeleteConfirmation(false)}
+ onEscapePress={e => setShowDeleteConfirmation(false)}>
+ <ModalHeader>
+ <Content component='h2'>Confirmation</Content>
+ </ModalHeader>
+ <ModalBody>
+ <div>{"Delete build " + deleteEntityName + "?"}</div>
+ </ModalBody>
+ <ModalFooter>
+ <Button key="confirm" variant="danger" onClick={e => {
+ if (deleteEntityName && deleteEntity) {
+ deleteEntity();
+ setShowDeleteConfirmation(false);
+ }
+ }}>Delete
+ </Button>
+ <Button key="cancel" variant="link"
+ onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
+ </ModalFooter>
+ </Modal>)
+ }
+
+ function getTitle(title: string, width: string = 'auto') {
+ return (
+ <Content style={{width: width, margin: 0, color: 'var(--pf-t--global--dark--text--color--200)'}} component='h4'>{title}</Content>
+ )
+ }
+
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'start', alignItems: 'center', gap: '16px'}}>
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'start', gap: '16px', alignItems: 'center'}}>
+ {getTitle("Build with tag")}
+ {getBuildTag()}
+ </div>
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'start', gap: '16px', alignItems: 'center'}}>
+ {/*{getTitle("Status")}*/}
+ {/*{getBuildState()}*/}
+ </div>
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'end', flexGrow: 2, alignItems: 'center'}}>
+ {buildButton()}
+ </div>
+ {showDeleteConfirmation && getDeleteConfirmation()}
+ </div>
+ )
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.css b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.css
new file mode 100644
index 00000000..c368f8e3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.css
@@ -0,0 +1,60 @@
+
+.karavan .refresher {
+ width: 34px;
+ height: 34px;
+}
+
+.karavan .refresher .spinner {
+ position: absolute;
+ width: 34px;
+ height: 34px;
+}
+
+.karavan .refresher .button {
+ position: absolute;
+ width: 34px;
+ height: 34px;
+ padding: 0;
+ font-size: 16px;
+}
+
+.karavan .refresher .button .pf-v6-c-button__icon {
+ margin: 0;
+}
+
+.karavan .main-toolbar {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+}
+
+.karavan .main-toolbar .main-run-button .pf-v6-svg {
+ margin-right: 5px;
+}
+
+.karavan .main-toolbar .main-run-dropdown-toggle .pf-v6-c-menu-toggle__button:last-child {
+ padding-left: 0;
+ padding-right: 0;
+}
+
+.karavan .main-toolbar .try-out-button {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.karavan .main-toolbar .try-out-button .pf-v6-c-button__icon {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.karavan .main-toolbar .pf-m-disabled .tryout-icon {
+ opacity: 0.5;
+}
+.karavan .main-toolbar .tryout-icon {
+ width: 1.4em;
+ height: 1.4em;
+ line-height: 1.4em;
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.tsx
new file mode 100644
index 00000000..36889be0
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/DevModeToolbar.tsx
@@ -0,0 +1,164 @@
+/*
+ * 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, {useEffect, useState} from 'react';
+import {Button, Dropdown, DropdownItem, DropdownList, MenuToggle, MenuToggleElement, Tooltip, TooltipPosition} from '@patternfly/react-core';
+import DevIcon from "@patternfly/react-icons/dist/esm/icons/dev-icon";
+import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon";
+import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon";
+import {useAppConfigStore, useProjectStore} from "@stores/ProjectStore";
+import {ProjectService} from "@services/ProjectService";
+import {shallow} from "zustand/shallow";
+import CompileIcon from "@patternfly/react-icons/dist/esm/icons/code-icon";
+import VerboseIcon from "@patternfly/react-icons/dist/esm/icons/list-icon";
+import "./DevModeToolbar.css"
+import StopIcon from "@patternfly/react-icons/dist/js/icons/stop-icon";
+import {ProjectContainersContext} from "../ProjectContainersContextProvider";
+import EllipsisVIcon from "@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon";
+
+export function DevModeToolbar() {
+
+ const context = React.useContext(ProjectContainersContext);
+ if (!context) throw new Error("ProjectContainersContext not found!");
+ const {packagedContainerStatuses, devModeContainerStatus, devModeIsRunning, containerStatuses} = context;
+
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const [project, refreshTrace, tabIndex] = useProjectStore((s) => [s.project, s.refreshTrace, s.tabIndex], shallow)
+
+ const [showSpinner, setShowSpinner] = useState(false);
+ const [reloadAvailable, setReloadAvailable] = useState(false);
+
+ const isKubernetes = config.infrastructure === 'kubernetes'
+
+ const isProjectContainer = packagedContainerStatuses.length > 0;
+
+ const commands = devModeContainerStatus?.commands || ['run'];
+ const inTransit = devModeContainerStatus?.inTransit;
+ const inDevMode = devModeContainerStatus?.type === 'devmode';
+ const isExited = devModeContainerStatus?.state === 'exited';
+
+ useEffect(() => {
+ if (showSpinner && hasContainer()) {
+ setShowSpinner(false);
+ }
+ }, [devModeContainerStatus, refreshTrace]);
+
+ const [isToggleOpen, setIsToggleOpen] = React.useState(false);
+
+ const hasContainer = () => {
+ return devModeContainerStatus?.containerId !== undefined && devModeContainerStatus?.containerId !== null
+ };
+
+ const onToggleClick = () => {
+ setIsToggleOpen(!isToggleOpen);
+ };
+
+ const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, value: string | number | undefined) => {
+ // eslint-disable-next-line no-console
+ setIsToggleOpen(false);
+ };
+
+ function runDevMode(ev: any, verbose: boolean, compile: boolean = false) {
+ ev.preventDefault();
+ setShowSpinner(true);
+ setReloadAvailable(!compile);
+ ProjectService.startDevModeContainer(project.projectId, verbose, compile);
+ }
+
+ function getRunButton() {
+ return (
+ <Dropdown
+ className="dev-action-button"
+ onSelect={onSelect}
+ popperProps={{position: 'right'}}
+ toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
+ <MenuToggle
+ ref={toggleRef}
+ onClick={onToggleClick}
+ variant="plain"
+ isExpanded={isToggleOpen}
+ aria-label="Action list single group kebab"
+ icon={<EllipsisVIcon/>}
+ />
+ )}
+ isOpen={isToggleOpen}
+ onOpenChange={(isOpen: boolean) => setIsToggleOpen(isOpen)}
+ >
+ <DropdownList>
+ <DropdownItem value={0} key="verbose" icon={<VerboseIcon/>} onClick={(ev) => runDevMode(ev, true, false)}>
+ Run verbose
+ </DropdownItem>
+ <DropdownItem value={1} key="compile" icon={<CompileIcon/>} onClick={(ev) => runDevMode(ev, false, true)}>
+ Run compile
+ </DropdownItem>
+ </DropdownList>
+ </Dropdown>
+ )
+ }
+
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', gap: '8px'}}>
+
+ {!devModeIsRunning && !hasContainer() && !isProjectContainer && tabIndex !== "build" &&
+ <Tooltip content="Run in Developer mode" position={TooltipPosition.bottomEnd}>
+ <Button className="dev-action-button"
+ isDisabled={inTransit}
+ variant={"primary"}
+ icon={<DevIcon/>}
+ onClick={(ev) => runDevMode(ev, false, false)}>
+ Run
+ </Button>
+ </Tooltip>
+ }
+ {!devModeIsRunning && !hasContainer() && !isProjectContainer && tabIndex !== "build" && getRunButton()}
+ {devModeIsRunning && inDevMode && reloadAvailable &&
+ <Tooltip content="Reload" position={TooltipPosition.bottom}>
+ <Button className="project-button dev-action-button"
+ isDisabled={inTransit}
+ variant={"secondary"}
+ icon={<ReloadIcon/>}
+ onClick={() => ProjectService.reloadDevModeCode(project)}>
+ {"Reload"}
+ </Button>
+ </Tooltip>
+ }
+ {inDevMode && !isKubernetes &&
+ <Tooltip content="Stop container" position={TooltipPosition.bottomEnd}>
+ <Button className="dev-action-button"
+ isDisabled={!commands.includes('stop') || inTransit}
+ variant={"control"}
+ icon={<StopIcon/>}
+ onClick={() => {
+ setShowSpinner(true);
+ ProjectService.stopDevModeContainer(project.projectId);
+ }}>
+ </Button>
+ </Tooltip>
+ }
+ {inDevMode &&
+ <Tooltip content="Delete container" position={TooltipPosition.bottomEnd}>
+ <Button className="dev-action-button"
+ variant={"control"}
+ icon={<DeleteIcon/>}
+ onClick={() => {
+ setShowSpinner(true);
+ ProjectService.deleteDevModeContainer(project.projectId);
+ }}>
+ </Button>
+ </Tooltip>
+ }
+ </div>);
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/toolbar/ProjectToolbar.tsx b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/ProjectToolbar.tsx
new file mode 100644
index 00000000..dcff9777
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/toolbar/ProjectToolbar.tsx
@@ -0,0 +1,48 @@
+import React, {useEffect} from 'react';
+import {DevModeToolbar} from "./DevModeToolbar";
+import {SettingsToolbar} from "@features/projects/SettingsToolbar";
+import {useAppConfigStore, useFileStore, useProjectStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {EditorToolbar} from "@features/project/developer/EditorToolbar";
+import {BUILD_IN_PROJECTS} from "@models/ProjectModels";
+import {ProjectContainersContextProvider} from "../ProjectContainersContextProvider";
+import {BuildToolbar} from "@features/project/toolbar/BuildToolbar";
+
+export function ProjectToolbar() {
+
+ const [project, tabIndex] = useProjectStore((s) => [s.project, s.tabIndex], shallow)
+ const [file, operation] = useFileStore((state) => [state.file, state.operation], shallow)
+ const [config] = useAppConfigStore((s) => [s.config], shallow);
+ const isDev = config.environment === 'dev';
+ const isBuildInProject = BUILD_IN_PROJECTS.includes(project?.projectId);
+ const showDevModeToolbar = isDev && !isBuildInProject && tabIndex !== "build";
+ const showPackageToolbar = isDev && !isBuildInProject && tabIndex === "build";
+ const showResourceToolbar = (isBuildInProject || !isDev) && tabIndex !== "build";
+
+ useEffect(() => {
+ }, [project, file]);
+
+ function isFile(): boolean {
+ return file !== undefined && operation !== 'delete';
+ }
+
+ function getProjectToolbar() {
+ return (
+ <div id="toolbar-group-types" className='main-toolbar-toolbar'>
+ {showDevModeToolbar &&
+ <ProjectContainersContextProvider>
+ <DevModeToolbar/>
+ </ProjectContainersContextProvider>
+ }
+ {showPackageToolbar &&
+ <ProjectContainersContextProvider>
+ <BuildToolbar/>
+ </ProjectContainersContextProvider>
+ }
+ {showResourceToolbar && <SettingsToolbar/>}
+ </div>
+ )
+ }
+
+ return isFile() ? <EditorToolbar/> : getProjectToolbar();
+}
diff --git a/karavan-app/src/main/webui/src/karavan/features/project/useProjectHook.tsx b/karavan-app/src/main/webui/src/karavan/features/project/useProjectHook.tsx
new file mode 100644
index 00000000..3fac563e
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/features/project/useProjectHook.tsx
@@ -0,0 +1,173 @@
+import './OpenApiDesigner.css'
+import {EventBus} from "@features/project/designer/utils/EventBus";
+import {ProjectFile} from "@models/ProjectModels";
+import {DslMetaModel} from "@features/project/designer/utils/DslMetaModel";
+import {v4 as uuidv4} from "uuid";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
+import {KaravanApi} from "@api/KaravanApi";
+import {Integration} from "@karavan-core/model/IntegrationDefinition";
+import {FILE_WORDS_SEPARATOR, KARAVAN_DOT_EXTENSION, KARAVAN_FILENAME, OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
+import {FromDefinition, RouteConfigurationDefinition} from "@karavan-core/model/CamelDefinition";
+import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
+import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
+import {CamelUtil} from "@karavan-core/api/CamelUtil";
+import {CamelDefinitionApi} from "@karavan-core/api/CamelDefinitionApi";
+import {useDesignerStore, useSelectorStore} from "@features/project/designer/DesignerStore";
+import {shallow} from "zustand/shallow";
+import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore, useWizardStore} from "@stores/ProjectStore";
+
+export function useProjectHook() {
+
+ const [config] = useAppConfigStore((state) => [state.config], shallow)
+ const [project, tab, setTabIndex] = useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex], shallow);
+ const [files, setFiles, setSelectedFileNames] = useFilesStore((s) => [s.files, s.setFiles, s.setSelectedFileNames], shallow);
+ const [showSelector, isRouteTemplate] = useSelectorStore((s) => [s.showSelector, s.isRouteTemplate], shallow)
+ const [setFile] = useFileStore((s) => [s.setFile], shallow);
+ const [setShowWizard] = useWizardStore((s) => [s.setShowWizard], shallow)
+ const [setDesignerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch], shallow)
+
+ function createRouteConfiguration() {
+ const integration = Integration.createNew(KARAVAN_FILENAME.ROUTE_CONFIGURATION);
+ const routeConfiguration = new RouteConfigurationDefinition();
+ const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(integration, routeConfiguration);
+ const yaml = CamelDefinitionYaml.integrationToYaml(i);
+ const file = new ProjectFile(KARAVAN_FILENAME.ROUTE_CONFIGURATION, project.projectId, yaml, Date.now());
+ saveNewFile(file, true, 'routes')
+ }
+
+ function createNewRouteFile(dsl: DslMetaModel) {
+ try {
+ if (dsl.dsl === 'FromDefinition' && dsl.uri) {
+ const uuid = uuidv4().substring(0, 3)
+ const simpleUri = dsl.uri?.replace('kamelet:', '');
+ const paramsUri =
+ dsl.properties && Object.keys(dsl.properties).length > 0
+ ? Object.values(dsl.properties).join(FILE_WORDS_SEPARATOR)
+ : uuid;
+
+ const fullUri = paramsUri
+ ? `${simpleUri}${FILE_WORDS_SEPARATOR}${paramsUri}`
+ : simpleUri;
+
+ const name = `from${FILE_WORDS_SEPARATOR}${fullUri}`;
+ const fileName = name + FILE_WORDS_SEPARATOR + KARAVAN_DOT_EXTENSION.CAMEL_YAML;
+ const nodePrefixId = `route${FILE_WORDS_SEPARATOR}` + fullUri;
+ const route = CamelUi.createRouteFromComponent(dsl.uri, '', '');
+ route.id = nodePrefixId;
+ route.nodePrefixId = nodePrefixId;
+ route.description = CamelUtil.capitalizeName(name.replace(FILE_WORDS_SEPARATOR, ' '));
+ const integration = Integration.createNew(fileName);
+ let i;
+ if (isRouteTemplate) {
+ const route = CamelDefinitionApi.createRouteDefinition({
+ from: new FromDefinition({uri: dsl.uri}),
+ nodePrefixId: `route${FILE_WORDS_SEPARATOR}${fullUri}`
+ });
+ const routeTemplate = CamelDefinitionApi.createRouteTemplateDefinition({route: route});
+ i = CamelDefinitionApiExt.addRouteTemplateToIntegration(integration, routeTemplate);
+ } else {
+ i = CamelDefinitionApiExt.addStepToIntegration(integration, route, '');
+ }
+
+ const yaml = CamelDefinitionYaml.integrationToYaml(i);
+ const file = new ProjectFile(fileName, project.projectId, yaml, Date.now());
+ saveNewFile(file, true, 'routes')
+ }
+ } catch (e: any) {
+ console.error(e);
+ EventBus.sendAlert("Error creating file", e.message, "danger");
+ }
+ }
+
+ function createNewRestFile() {
+ try {
+ const fileExists = files.find(f => f.name === "rest-api.camel.yaml") !== undefined;
+ const uuid = uuidv4().substring(0, 3)
+ const fileName = 'rest-api' + (fileExists ? FILE_WORDS_SEPARATOR + uuid : '') + '.camel.yaml';
+ const nodePrefixId = 'rest-' + uuid;
+ const rest = CamelDefinitionApi.createRestDefinition({
+ id: nodePrefixId,
+ description: 'Service Example',
+ path: 'example',
+ consumes: 'application/json',
+ produces: 'application/json',
+ get: [CamelDefinitionApi.createGetDefinition({to: 'direct:getExample', description: 'GET Example'})],
+ post: [CamelDefinitionApi.createPostDefinition({to: 'direct:postExample', description: 'POST Example'})],
+ delete: [CamelDefinitionApi.createDeleteDefinition({to: 'direct:deleteExample', description: 'DELETE Example'})],
+ });
+ const restConfiguration = CamelDefinitionApi.createRestConfigurationDefinition({
+ inlineRoutes: false,
+ });
+ const integration = Integration.createNew(fileName);
+ let i = CamelDefinitionApiExt.addRestToIntegration(integration, rest);
+ i = CamelDefinitionApiExt.addRestToIntegration(i, restConfiguration);
+ const yaml = CamelDefinitionYaml.integrationToYaml(i);
+ const file = new ProjectFile(fileName, project.projectId, yaml, Date.now());
+ saveNewFile(file, true, 'rest')
+ } catch (e: any) {
+ EventBus.sendAlert("Error creating file", e.message, "danger");
+ }
+ }
+
+ function createNewKamelet() {
+ setFile('create', undefined, 'kamelet')
+ }
+
+ function createNewBean() {
+ setShowWizard(true)
+ }
+
+ function createOpenApiRestFile() {
+ try {
+ const fileName = 'openapi-rest-config.camel.yaml';
+ const rest = CamelDefinitionApi.createRestDefinition({
+ id: 'openApiRestService',
+ openApi: CamelDefinitionApi.createOpenApiDefinition({specification: 'classpath://' + OPENAPI_FILE_NAME_JSON})
+ });
+ const restConfiguration = CamelDefinitionApi.createRestConfigurationDefinition({
+ inlineRoutes: false,
+ });
+ const integration = Integration.createNew(fileName);
+ let i = CamelDefinitionApiExt.addRestToIntegration(integration, rest);
+ i = CamelDefinitionApiExt.addRestToIntegration(i, restConfiguration);
+ const yaml = CamelDefinitionYaml.integrationToYaml(i);
+ const file = new ProjectFile(fileName, project.projectId, yaml, Date.now());
+ saveNewFile(file, false)
+ } catch (e: any) {
+ EventBus.sendAlert("Error creating file", e.message, "danger");
+ }
+ }
+
+
+ function onOpenApiButtonClick() {
+ const openApiFile = files.filter(f => f.name === OPENAPI_FILE_NAME_JSON)?.at(0);
+ if (openApiFile === undefined) {
+ createOpenApiRestFile();
+ setDesignerSwitch(true);
+ const code = "{}";
+ const openApiFile = new ProjectFile(OPENAPI_FILE_NAME_JSON, project.projectId, code, Date.now());
+ saveNewFile(openApiFile, true);
+ } else {
+ setFile('select', openApiFile);
+ }
+ }
+
+ function saveNewFile(file: ProjectFile, openFile: boolean, designerTab?: "routes" | "rest" | "beans" | "kamelet") {
+ KaravanApi.saveProjectFile(file, (result, fileRes) => {
+ if (result) {
+ EventBus.sendAlert("Success", `File ${file.name} successfully created`, "success");
+ // ProjectService.refreshProjectData(project.projectId);
+ if (file.code && openFile) {
+ setFile('select', file, designerTab);
+ setTabIndex(0);
+ } else {
+ setFile("none");
+ }
+ } else {
+ EventBus.sendAlert("Error creating file", fileRes?.response?.data, "danger");
+ }
+ })
+ }
+
+ return {createNewRouteFile, createOpenApiRestFile, createNewBean, createNewKamelet, createRouteConfiguration}
+}
(camel-karavan) 23/33: Front-end Access for 4.18.0
Posted by ma...@apache.org.
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 694e264da50a0118c2bdd680194b7eb687159151
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:48:36 2026 -0500
Front-end Access for 4.18.0
---
.../src/karavan/features/access/AccessPage.css | 0
.../src/karavan/features/access/AccessPage.tsx | 85 +++++++++++++---------
.../karavan/features/access/roles/RoleModal.tsx | 18 ++++-
.../karavan/features/access/roles/RolesTable.tsx | 20 ++++-
.../features/access/roles/RolesTableRow.tsx | 26 ++++++-
.../features/access/users/ChangePassword.tsx | 18 ++++-
.../features/access/users/PasswordModal.tsx | 18 ++++-
.../karavan/features/access/users/UserModal.tsx | 18 ++++-
.../karavan/features/access/users/UserProfile.tsx | 18 ++++-
.../features/access/users/UserProfileTab.tsx | 16 ++++
.../karavan/features/access/users/UsersTable.tsx | 20 ++++-
.../features/access/users/UsersTableRow.tsx | 17 ++++-
12 files changed, 229 insertions(+), 45 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.css b/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.css
deleted file mode 100644
index e69de29b..00000000
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.tsx b/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.tsx
index 3eef0643..2ad6abb3 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/AccessPage.tsx
@@ -1,6 +1,22 @@
+/*
+ * 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, {useEffect, useState} from 'react';
import {Button, capitalize, Content, Nav, NavItem, NavList, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities,} from '@patternfly/react-core';
-import {useAccessStore} from "../../stores/AccessStore";
+import {useAccessStore} from "@stores/AccessStore";
import {shallow} from "zustand/shallow";
import {AccessService} from "@services/AccessService";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
@@ -9,7 +25,7 @@ import {RightPanel} from "@shared/ui/RightPanel";
import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
import TimesIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
import {UsersTable} from "@features/access/users/UsersTable";
-import {ErrorBoundaryWrapper} from "@features/integration/designer/ErrorBoundaryWrapper";
+import {ErrorBoundaryWrapper} from "@features/project/designer/ErrorBoundaryWrapper";
import {RolesTable} from "@features/access/roles/RolesTable";
import {UserModal} from "./users/UserModal";
import {RoleModal} from "@features/access/roles/RoleModal";
@@ -33,14 +49,14 @@ export const AccessPage = () => {
function searchInput() {
return (
- <TextInputGroup className="search">
+ <TextInputGroup className="search" style={{width:'300px'}}>
<TextInputGroupMain
value={filter}
placeholder='Search'
type="text"
autoComplete={"off"}
autoFocus={true}
- icon={<SearchIcon />}
+ icon={<SearchIcon/>}
onChange={(_event, value) => {
setFilter(value);
}}
@@ -58,24 +74,24 @@ export const AccessPage = () => {
}
function tools() {
- return (<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
- <Button icon={<RefreshIcon/>}
- variant={"link"}
- onClick={e => AccessService.refreshAccess()}
- />
- {searchInput()}
- <Button className="dev-action-button"
- icon={<PlusIcon/>}
- onClick={e => {
- setCurrentUser(undefined)
- if (activeItem === "users") {
- setShowUserModal(true)
- } else {
- setShowRoleModal(true)
- }
- }}
- >Add</Button>
- </div>);
+ return (<div className="project-files-toolbar" style={{justifyContent: "flex-end"}}>
+ <Button icon={<RefreshIcon/>}
+ variant={"link"}
+ onClick={e => AccessService.refreshAccess()}
+ />
+ {searchInput()}
+ <Button className="dev-action-button"
+ icon={<PlusIcon/>}
+ onClick={e => {
+ setCurrentUser(undefined)
+ if (activeItem === "users") {
+ setShowUserModal(true)
+ } else {
+ setShowRoleModal(true)
+ }
+ }}
+ >Add</Button>
+ </div>);
}
function title() {
@@ -90,10 +106,10 @@ export const AccessPage = () => {
<NavList>
{(getCurrentUser()?.roles?.includes(PLATFORM_ADMIN) ? adminMenus : userMenus)
.filter(m => []).map((item, i) =>
- <NavItem key={item} preventDefault itemId={item} isActive={activeItem === item} to="#">
- {capitalize(item?.toString())}
- </NavItem>
- )}
+ <NavItem key={item} preventDefault itemId={item} isActive={activeItem === item} to="#">
+ {capitalize(item?.toString())}
+ </NavItem>
+ )}
</NavList>
</Nav>
)
@@ -103,16 +119,19 @@ export const AccessPage = () => {
<RightPanel
title={title()}
toolsStart={getNavigation()}
- tools={tools()}
+ tools={undefined}
mainPanel={
<div className="right-panel-card">
<ErrorBoundaryWrapper key='info' onError={error => console.error(error)}>
- {activeItem === 'users' && <UsersTable/>}
- {activeItem === 'roles' && <RolesTable/>}
- {activeItem === 'profile' && <UserProfileTab/>}
- {showUserModal && <UserModal/>}
- {showRoleModal && <RoleModal/>}
- {showPasswordModal && <PasswordModal/>}
+ <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
+ {activeItem !== 'profile' && tools()}
+ {activeItem === 'users' && <UsersTable/>}
+ {activeItem === 'roles' && <RolesTable/>}
+ {activeItem === 'profile' && <UserProfileTab/>}
+ {showUserModal && <UserModal/>}
+ {showRoleModal && <RoleModal/>}
+ {showPasswordModal && <PasswordModal/>}
+ </div>
</ErrorBoundaryWrapper>
</div>
}
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/roles/RoleModal.tsx b/karavan-app/src/main/webui/src/karavan/features/access/roles/RoleModal.tsx
index d6df79cc..cc7987ff 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/roles/RoleModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/roles/RoleModal.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useEffect} from 'react';
import {Alert, Button, Content, Form, FormAlert, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant,} from '@patternfly/react-core';
import {SubmitHandler, useForm} from "react-hook-form";
@@ -5,7 +21,7 @@ import {AxiosResponse} from "axios";
import {AccessRole} from "../../../models/AccessModels";
import {useAccessStore} from "../../../stores/AccessStore";
import {useFormUtil} from "@util/useFormUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {shallow} from "zustand/shallow";
import {AccessApi} from "../../../api/AccessApi";
import {AccessService} from "@services/AccessService";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
index f06b76e7..c8200518 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTable.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useState} from 'react';
import {Bullseye, EmptyState, EmptyStateVariant, Spinner} from '@patternfly/react-core';
import '../AccessPage.css';
@@ -32,8 +48,8 @@ export function RolesTable() {
const conts = roles.filter(role =>
role.name?.toLowerCase().includes(filter)
- || role.name.toLowerCase().includes(filter)
- || role.name.toLowerCase().includes(filter)
+ || role.name?.toLowerCase().includes(filter)
+ || role.name?.toLowerCase().includes(filter)
).sort((a, b) => a.name.localeCompare(b.name));
return (
<OuterScrollContainer>
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTableRow.tsx b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTableRow.tsx
index 66fdbd9f..c26653ac 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTableRow.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/roles/RolesTableRow.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useState} from 'react';
import {Button, capitalize, Content, Label} from '@patternfly/react-core';
import {Tbody, Td, Tr} from "@patternfly/react-table";
@@ -7,6 +23,8 @@ import {shallow} from "zustand/shallow";
import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
import {ShieldAltIcon, UsersIcon} from "@patternfly/react-icons";
import {ModalConfirmation} from "@shared/ui/ModalConfirmation";
+import {AccessApi} from "@api/AccessApi";
+import {AccessService} from "@services/AccessService";
interface Props {
index: number
@@ -22,7 +40,11 @@ export function RolesTableRow(props: Props) {
const {role} = props;
function executeAction() {
-
+ if (command === 'delete') {
+ AccessApi.deleteRole(role.name, result => {
+ AccessService.refreshAccess();
+ });
+ }
setShowConfirmation(false);
}
@@ -39,7 +61,7 @@ export function RolesTableRow(props: Props) {
}
}
- const usersWithRole = users.filter(user => user.roles.includes(role.name))
+ const usersWithRole = users.filter(user => user.roles?.includes(role.name))
const isBuildInRole = [PLATFORM_DEVELOPER, PLATFORM_USER, PLATFORM_ADMIN].includes(role?.name);
const canBeDeleted = !isBuildInRole && usersWithRole.length === 0;
return (
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/ChangePassword.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/ChangePassword.tsx
index ed420a48..dc0fc670 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/ChangePassword.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/ChangePassword.tsx
@@ -1,10 +1,26 @@
+/*
+ * 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, {useEffect} from 'react';
import {Alert, Button, Card, CardBody, CardFooter, CardHeader, Content, Form, FormAlert, FormGroup, FormHelperText, HelperText, HelperTextItem,} from '@patternfly/react-core';
import {SubmitHandler, useForm} from "react-hook-form";
import {AxiosResponse} from "axios";
import {AccessPassword} from "../../../models/AccessModels";
import {useFormUtil} from "@util/useFormUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {AuthApi} from "@api/auth/AuthApi";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/PasswordModal.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/PasswordModal.tsx
index 7d70f759..8a4959b5 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/PasswordModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/PasswordModal.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useEffect} from 'react';
import {
Alert,
@@ -19,7 +35,7 @@ import {SubmitHandler, useForm} from "react-hook-form";
import {AxiosResponse} from "axios";
import {useAccessStore} from "../../../stores/AccessStore";
import {useFormUtil} from "@util/useFormUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {shallow} from "zustand/shallow";
import {AccessPassword} from "@models/AccessModels";
import {AccessApi} from "@api/AccessApi";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UserModal.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UserModal.tsx
index 332e9f64..5744f633 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UserModal.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UserModal.tsx
@@ -1,10 +1,26 @@
+/*
+ * 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, {useEffect} from 'react';
import {Alert, Button, Content, Form, FormAlert, FormGroup, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant, TextInput,} from '@patternfly/react-core';
import {SubmitHandler, useForm} from "react-hook-form";
import {AxiosResponse} from "axios";
import {useAccessStore} from "../../../stores/AccessStore";
import {useFormUtil} from "@util/useFormUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {shallow} from "zustand/shallow";
import {AccessApi} from "../../../api/AccessApi";
import {getCurrentUser} from "@api/auth/AuthApi";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfile.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfile.tsx
index c0387543..1f9272e0 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfile.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfile.tsx
@@ -1,10 +1,26 @@
+/*
+ * 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, {useEffect} from 'react';
import {Alert, Button, Card, CardBody, CardFooter, CardHeader, Content, Form, FormAlert, FormGroup, TextInput,} from '@patternfly/react-core';
import {SubmitHandler, useForm} from "react-hook-form";
import {AxiosResponse} from "axios";
import {AccessUser} from "../../../models/AccessModels";
import {useFormUtil} from "@util/useFormUtil";
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+import {EventBus} from "@features/project/designer/utils/EventBus";
import {AccessApi} from "../../../api/AccessApi";
import {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfileTab.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfileTab.tsx
index 785fbf85..9f36d4f8 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfileTab.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UserProfileTab.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 UserProfile from "@features/access/users/UserProfile";
import {ChangePassword} from "@features/access/users/ChangePassword";
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
index d1436f17..db763e3e 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTable.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useState} from 'react';
import {Bullseye, EmptyState, EmptyStateVariant, Spinner} from '@patternfly/react-core';
import '../AccessPage.css';
@@ -32,8 +48,8 @@ export function UsersTable() {
const conts = users.filter(user =>
user.username?.toLowerCase().includes(filter)
- || user.firstName.toLowerCase().includes(filter)
- || user.lastName.toLowerCase().includes(filter)
+ || user.firstName?.toLowerCase().includes(filter)
+ || user.lastName?.toLowerCase().includes(filter)
).sort((a, b) => a.username.localeCompare(b.username));
return (
<OuterScrollContainer>
diff --git a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTableRow.tsx b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTableRow.tsx
index 7b35dc51..f1dacf4c 100644
--- a/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTableRow.tsx
+++ b/karavan-app/src/main/webui/src/karavan/features/access/users/UsersTableRow.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useState} from 'react';
import {Button, capitalize, Label, Switch} from '@patternfly/react-core';
import {Tbody, Td, Tr} from "@patternfly/react-table";
@@ -39,7 +55,6 @@ export function UsersTableRow(props: Props) {
AccessService.refreshAccess();
});
}
-
setShowConfirmation(false);
}
(camel-karavan) 19/33: Fix Backend for 4.18.0
Posted by ma...@apache.org.
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 19960ff7f75c017ab15e3f2ec630927c99c33a5e
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 18:38:56 2026 -0500
Fix Backend for 4.18.0
---
.../java/org/apache/camel/karavan/cache/KaravanCache.java | 1 +
.../org/apache/camel/karavan/listener/ActivityListener.java | 12 ++++++------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java b/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
index 4495659e..318711f8 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/cache/KaravanCache.java
@@ -480,6 +480,7 @@ public class KaravanCache {
public Map<String, ActivityUser> getCopyUsersWorking() {
return Map.copyOf(usersWorking);
}
+
public void saveUserHeartBeat(ActivityUser activityUser) {
usersHeartBeat.put(activityUser.getUserName(), activityUser);
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java b/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
index 6cff2d7c..b9d4d3f4 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/listener/ActivityListener.java
@@ -39,13 +39,13 @@ public class ActivityListener {
@ConsumeEvent(value = ON_USER_ACTIVITY, ordered = true)
public void onUserActivity(JsonObject json) {
var activityUser = json.mapTo(ActivityUser.class);
- if (Objects.isNull(activityUser)) {
- } else if (ActivityUser.ActivityType.WORKING.equals(activityUser.getType())) {
- karavanCache.saveUserWorking(activityUser);
- } else {
- karavanCache.saveUserHeartBeat(activityUser);
+ if (activityUser != null && activityUser.getUserName() != null) {
+ if (ActivityUser.ActivityType.WORKING.equals(activityUser.getType())) {
+ karavanCache.saveUserWorking(activityUser);
+ } else {
+ karavanCache.saveUserHeartBeat(activityUser);
+ }
}
-
}
@ConsumeEvent(value = ON_PROJECT_ACTIVITY, ordered = true)
(camel-karavan) 03/33: Dockerfile for 4.18.0
Posted by ma...@apache.org.
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 cea7f0aa15e2c1717c19d4c5af64ec67cc7d3c03
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 15:46:11 2026 -0500
Dockerfile for 4.18.0
---
karavan-app/src/main/docker/Dockerfile | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/karavan-app/src/main/docker/Dockerfile b/karavan-app/src/main/docker/Dockerfile
index 8f386225..2701f60e 100644
--- a/karavan-app/src/main/docker/Dockerfile
+++ b/karavan-app/src/main/docker/Dockerfile
@@ -22,11 +22,20 @@ LABEL "org.opencontainers.image.licenses"="Apache 2.0"
LABEL "org.opencontainers.image.version"="4.14.5"
LABEL "org.apache.camel.karavan/type"="internal"
-RUN mkdir /opt/app
+USER root
+ARG DOCKER_GROUP_ID=999
+RUN groupadd -g ${DOCKER_GROUP_ID} docker && usermod -aG docker default
+RUN mkdir -p /opt/app/data && chown -R default:0 /opt/app
+USER default
+
COPY target/*-runner.jar /opt/app/karavan.jar
-EXPOSE 8080
+ENV JAVA_TOOL_OPTIONS="-Dquarkus.http.host=0.0.0.0 \
+-Djava.util.logging.manager=org.jboss.logmanager.LogManager \
+-XX:+UseContainerSupport \
+-XX:InitialRAMPercentage=25 -XX:MaxRAMPercentage=70 \
+-XX:+ExitOnOutOfMemoryError \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof"
-CMD exec "java" \
- ${JAVA_OPTS} \
- "-jar" "/opt/app/karavan.jar"
+EXPOSE 8080
+CMD ["java", "-jar", "/opt/app/karavan.jar"]
(camel-karavan) 04/33: Front-end config for 4.18.0
Posted by ma...@apache.org.
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 d902703afe38648c5af44384008af014d61b5854
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 15:51:14 2026 -0500
Front-end config for 4.18.0
---
karavan-app/src/main/webui/index.html | 17 +-
karavan-app/src/main/webui/package-lock.json | 2950 +++++++-------------------
karavan-app/src/main/webui/package.json | 68 +-
karavan-app/src/main/webui/tsconfig.json | 1 +
karavan-app/src/main/webui/vite-env.d.ts | 2 +-
karavan-app/src/main/webui/vite.config.ts | 81 +-
6 files changed, 841 insertions(+), 2278 deletions(-)
diff --git a/karavan-app/src/main/webui/index.html b/karavan-app/src/main/webui/index.html
index d2677fa8..05d1c6f4 100644
--- a/karavan-app/src/main/webui/index.html
+++ b/karavan-app/src/main/webui/index.html
@@ -1,20 +1,5 @@
-<!-- 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. -->
-
<!DOCTYPE html>
-<html lang="en">
+<html lang="en" >
<head>
<meta charset="utf-8" />
diff --git a/karavan-app/src/main/webui/package-lock.json b/karavan-app/src/main/webui/package-lock.json
index b9fcb3a2..656e9568 100644
--- a/karavan-app/src/main/webui/package-lock.json
+++ b/karavan-app/src/main/webui/package-lock.json
@@ -1,78 +1,74 @@
{
"name": "karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"dependencies": {
- "@carbon/icons-react": "11.69.0",
- "@hookform/error-message": "2.0.1",
- "@hookform/resolvers": "5.2.2",
+ "@carbon/icons-react": "11.73.0",
+ "@dagrejs/dagre": "2.0.3",
"@microsoft/fetch-event-source": "^2.0.1",
"@monaco-editor/react": "4.7.0",
"@patternfly/patternfly": "6.4.0",
"@patternfly/react-charts": "8.4.0",
"@patternfly/react-core": "6.4.0",
+ "@patternfly/react-icons": "6.4.0",
"@patternfly/react-log-viewer": "6.3.0",
"@patternfly/react-table": "6.4.0",
"@patternfly/react-templates": "6.4.0",
"@patternfly/react-topology": "6.4.0",
- "@types/js-yaml": "4.0.9",
- "@types/node": "24.2.1",
- "@types/uuid": "11.0.0",
"@uiw/react-markdown-preview": "5.1.5",
- "axios": "1.12.2",
+ "axios": "1.13.5",
"buffer": "6.0.3",
+ "chance": "1.1.13",
+ "elkjs": "^0.11.0",
"file-saver": "2.0.5",
- "javascript-time-ago": "2.5.12",
- "keycloak-js": "26.2.1",
- "lodash": "^4.17.21",
+ "javascript-time-ago": "2.6.2",
+ "keycloak-js": "26.2.3",
+ "lodash": "^4.17.23",
"react": "18.3.1",
"react-dom": "18.3.1",
- "react-hook-form": "7.65.0",
- "react-resizable-panels": "3.0.6",
- "react-router-dom": "7.9.4",
+ "react-hook-form": "7.71.2",
+ "react-resizable-panels": "4.6.5",
+ "react-router-dom": "^7.13.1",
"rxjs": "7.8.2",
"use-sync-external-store": "1.6.0",
"usehooks-ts": "3.1.1",
"uuid": "13.0.0",
"victory": "37.3.6",
- "yup": "1.7.1",
- "zustand": "5.0.9"
+ "zustand": "5.0.11"
},
"devDependencies": {
- "@eslint/js": "9.33.0",
- "@types/dagre": "0.7.53",
+ "@eslint/js": "9.39.2",
+ "@types/chance": "1.1.7",
"@types/file-saver": "2.0.7",
"@types/js-yaml": "^4.0.9",
- "@types/lodash": "^4.17.21",
- "@types/react": "18.3.27",
- "@types/react-dom": "18.3.1",
- "@typescript-eslint/eslint-plugin": "8.39.1",
- "@typescript-eslint/parser": "8.39.1",
- "@vitejs/plugin-react": "^4.7.0",
- "eslint": "9.33.0",
- "monaco-editor": "0.53.0",
- "rollup-plugin-visualizer": "6.0.5",
- "source-map-explorer": "^2.5.3",
+ "@types/lodash": "^4.17.23",
+ "@types/node": "25.0.10",
+ "@types/react": "18.3.28",
+ "@types/react-dom": "18.3.7",
+ "@types/uuid": "11.0.0",
+ "@vitejs/plugin-react": "^5.1.4",
+ "eslint": "10.0.1",
+ "monaco-editor": "^0.52.0",
"typescript": "5.9.3",
- "typescript-eslint": "8.46.2",
- "vite": "7.2.6",
+ "typescript-eslint": "8.56.1",
+ "vite": "7.3.1",
"vite-plugin-svgr": "4.5.0",
- "vite-tsconfig-paths": "5.1.4"
+ "vite-tsconfig-paths": "6.1.1"
}
},
"node_modules/@babel/code-frame": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
- "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
@@ -81,9 +77,9 @@
}
},
"node_modules/@babel/compat-data": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
- "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -91,21 +87,21 @@
}
},
"node_modules/@babel/core": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
- "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.5",
- "@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-module-transforms": "^7.28.3",
- "@babel/helpers": "^7.28.4",
- "@babel/parser": "^7.28.5",
- "@babel/template": "^7.27.2",
- "@babel/traverse": "^7.28.5",
- "@babel/types": "^7.28.5",
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
@@ -121,25 +117,15 @@
"url": "https://opencollective.com/babel"
}
},
- "node_modules/@babel/core/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@babel/generator": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
- "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
+ "version": "7.29.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.5",
- "@babel/types": "^7.28.5",
+ "@babel/parser": "^7.29.0",
+ "@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -149,13 +135,13 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
- "version": "7.27.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
- "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/compat-data": "^7.27.2",
+ "@babel/compat-data": "^7.28.6",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
@@ -165,16 +151,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
@@ -186,29 +162,29 @@
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
- "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/traverse": "^7.27.1",
- "@babel/types": "^7.27.1"
+ "@babel/traverse": "^7.28.6",
+ "@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.28.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
- "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/helper-module-imports": "^7.27.1",
- "@babel/helper-validator-identifier": "^7.27.1",
- "@babel/traverse": "^7.28.3"
+ "@babel/helper-module-imports": "^7.28.6",
+ "@babel/helper-validator-identifier": "^7.28.5",
+ "@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
@@ -218,9 +194,9 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
- "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
"dev": true,
"license": "MIT",
"engines": {
@@ -258,27 +234,27 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
- "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/template": "^7.27.2",
- "@babel/types": "^7.28.4"
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
- "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
+ "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.5"
+ "@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -320,42 +296,42 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.28.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
- "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
+ "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
- "version": "7.27.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
- "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "version": "7.28.6",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/parser": "^7.27.2",
- "@babel/types": "^7.27.1"
+ "@babel/code-frame": "^7.28.6",
+ "@babel/parser": "^7.28.6",
+ "@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
- "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.5",
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.28.5",
- "@babel/template": "^7.27.2",
- "@babel/types": "^7.28.5",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
@@ -363,9 +339,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.28.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
- "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -377,9 +353,9 @@
}
},
"node_modules/@carbon/icon-helpers": {
- "version": "10.69.0",
- "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.69.0.tgz",
- "integrity": "sha512-AYkP9+le5pLllM4OX1zHCSpBIX4uk8hzaV7EakyzQsUoWZIdLip0+j1n9WJvGA7EnMMaFxtmRkt1KAbSGi+YIg==",
+ "version": "10.73.0",
+ "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.73.0.tgz",
+ "integrity": "sha512-Grn/QxHZfSOdXp/WBadegVfq1LT96QwX9b977dqMU5qmxp6cxKqUGvV1oqs6GiBacKoQFrH2xgbKwlcecgSHfA==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -387,13 +363,13 @@
}
},
"node_modules/@carbon/icons-react": {
- "version": "11.69.0",
- "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.69.0.tgz",
- "integrity": "sha512-4ourN8a6IZD/eCCbsFYMQytUkmsMfcVCk/SxX2QyCCgy1jQlMVl5pn9koRkylblpV8n/4yn86XYZqw1Ec3zuDA==",
+ "version": "11.73.0",
+ "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.73.0.tgz",
+ "integrity": "sha512-nAgyfcEKzQUt+68+mvz0gQQtcn7jpRxiUsvG/uZ/MIJZoLHhtRt5u5pymU9JLNnQFJWwyIUhraDeLip7MpHjIQ==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
- "@carbon/icon-helpers": "^10.68.0",
+ "@carbon/icon-helpers": "^10.70.0",
"@ibm/telemetry-js": "^1.5.0",
"prop-types": "^15.8.1"
},
@@ -402,27 +378,27 @@
}
},
"node_modules/@dagrejs/dagre": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.2.tgz",
- "integrity": "sha512-F09dphqvHsbe/6C2t2unbmpr5q41BNPEfJCdn8Z7aEBpVSy/zFQ/b4SWsweQjWNsYMDvE2ffNUN8X0CeFsEGNw==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-2.0.3.tgz",
+ "integrity": "sha512-ig9Vg52tsijTIKNgW9BAeUVBhDRvqlZ2a6FQ6i41YcPpoAy7VXXt2qye22PXRecGSjAp0OEEVUBhJ4oS9BnBzQ==",
"license": "MIT",
"dependencies": {
- "@dagrejs/graphlib": "2.2.2"
+ "@dagrejs/graphlib": "2.2.4"
}
},
"node_modules/@dagrejs/graphlib": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.2.tgz",
- "integrity": "sha512-CbyGpCDKsiTg/wuk79S7Muoj8mghDGAESWGxcSyhHX5jD35vYMBZochYVFzlHxynpE9unpu6O+4ZuhrLxASsOg==",
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz",
+ "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==",
"license": "MIT",
"engines": {
"node": ">17.0.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
- "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
+ "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
"cpu": [
"ppc64"
],
@@ -437,9 +413,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
- "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
+ "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
"cpu": [
"arm"
],
@@ -454,9 +430,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
- "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
+ "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
"cpu": [
"arm64"
],
@@ -471,9 +447,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
- "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
+ "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
"cpu": [
"x64"
],
@@ -488,9 +464,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
- "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
+ "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
"cpu": [
"arm64"
],
@@ -505,9 +481,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
- "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
+ "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
"cpu": [
"x64"
],
@@ -522,9 +498,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
- "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
"cpu": [
"arm64"
],
@@ -539,9 +515,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
- "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
+ "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
"cpu": [
"x64"
],
@@ -556,9 +532,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
- "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
+ "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
"cpu": [
"arm"
],
@@ -573,9 +549,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
- "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
+ "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
"cpu": [
"arm64"
],
@@ -590,9 +566,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
- "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
+ "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
"cpu": [
"ia32"
],
@@ -607,9 +583,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
- "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
+ "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
"cpu": [
"loong64"
],
@@ -624,9 +600,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
- "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
+ "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
"cpu": [
"mips64el"
],
@@ -641,9 +617,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
- "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
+ "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
"cpu": [
"ppc64"
],
@@ -658,9 +634,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
- "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
+ "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
"cpu": [
"riscv64"
],
@@ -675,9 +651,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
- "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
+ "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
"cpu": [
"s390x"
],
@@ -692,9 +668,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
- "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
+ "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
"cpu": [
"x64"
],
@@ -709,9 +685,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
- "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
"cpu": [
"arm64"
],
@@ -726,9 +702,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
- "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
"cpu": [
"x64"
],
@@ -743,9 +719,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
- "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
+ "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
"cpu": [
"arm64"
],
@@ -760,9 +736,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
- "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
+ "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
"cpu": [
"x64"
],
@@ -777,9 +753,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
- "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
+ "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
"cpu": [
"arm64"
],
@@ -794,9 +770,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
- "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
+ "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
"cpu": [
"x64"
],
@@ -811,9 +787,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
- "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
+ "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
"cpu": [
"arm64"
],
@@ -828,9 +804,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
- "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
+ "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
"cpu": [
"ia32"
],
@@ -845,9 +821,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
- "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
+ "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
"cpu": [
"x64"
],
@@ -862,9 +838,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
- "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -880,6 +856,19 @@
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@eslint-community/regexpp": {
"version": "4.12.2",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
@@ -891,129 +880,50 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.21.1",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
- "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.2.tgz",
+ "integrity": "sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/object-schema": "^2.1.7",
+ "@eslint/object-schema": "^3.0.2",
"debug": "^4.3.1",
- "minimatch": "^3.1.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/config-array/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/@eslint/config-array/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
+ "minimatch": "^10.2.1"
},
"engines": {
- "node": "*"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz",
- "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==",
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz",
+ "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==",
"dev": true,
"license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.1.0"
+ },
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/core": {
- "version": "0.15.2",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
- "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz",
+ "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
- "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^10.0.1",
- "globals": "^14.0.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.1",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/js": {
- "version": "9.33.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz",
- "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==",
+ "version": "9.39.2",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
+ "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1024,50 +934,27 @@
}
},
"node_modules/@eslint/object-schema": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
- "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.2.tgz",
+ "integrity": "sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
- "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz",
+ "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.15.2",
+ "@eslint/core": "^1.1.0",
"levn": "^0.4.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@hookform/error-message": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@hookform/error-message/-/error-message-2.0.1.tgz",
- "integrity": "sha512-U410sAr92xgxT1idlu9WWOVjndxLdgPUHEB8Schr27C9eh7/xUnITWpCMF93s+lGiG++D4JnbSnrb5A21AdSNg==",
- "license": "MIT",
- "peerDependencies": {
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0",
- "react-hook-form": "^7.0.0"
- }
- },
- "node_modules/@hookform/resolvers": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz",
- "integrity": "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==",
- "license": "MIT",
- "dependencies": {
- "@standard-schema/utils": "^0.3.0"
- },
- "peerDependencies": {
- "react-hook-form": "^7.55.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@humanfs/core": {
@@ -1123,9 +1010,9 @@
}
},
"node_modules/@ibm/telemetry-js": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.10.2.tgz",
- "integrity": "sha512-F8+/NNUwtm8BuFz18O9KPvIFTFDo8GUSoyhPxPjEpk7nEyEzWGfhIiEPhL00B2NdHRLDSljh3AiCfSnL/tutiQ==",
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@ibm/telemetry-js/-/telemetry-js-1.11.0.tgz",
+ "integrity": "sha512-RO/9j+URJnSfseWg9ZkEX9p+a3Ousd33DBU7rOafoZB08RqdzxFVYJ2/iM50dkBuD0o7WX7GYt1sLbNgCoE+pA==",
"license": "Apache-2.0",
"bin": {
"ibmtelemetry": "dist/collect.js"
@@ -1210,44 +1097,6 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/@patternfly/patternfly": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-6.4.0.tgz",
@@ -1461,10 +1310,28 @@
"react-dom": "^17 || ^18 || ^19"
}
},
+ "node_modules/@patternfly/react-topology/node_modules/@dagrejs/dagre": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.2.tgz",
+ "integrity": "sha512-F09dphqvHsbe/6C2t2unbmpr5q41BNPEfJCdn8Z7aEBpVSy/zFQ/b4SWsweQjWNsYMDvE2ffNUN8X0CeFsEGNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@dagrejs/graphlib": "2.2.2"
+ }
+ },
+ "node_modules/@patternfly/react-topology/node_modules/@dagrejs/graphlib": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.2.tgz",
+ "integrity": "sha512-CbyGpCDKsiTg/wuk79S7Muoj8mghDGAESWGxcSyhHX5jD35vYMBZochYVFzlHxynpE9unpu6O+4ZuhrLxASsOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">17.0.0"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.27",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
- "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "version": "1.0.0-rc.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
+ "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
"dev": true,
"license": "MIT"
},
@@ -1491,23 +1358,10 @@
}
}
},
- "node_modules/@rollup/pluginutils/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
- "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
+ "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
"cpu": [
"arm"
],
@@ -1519,9 +1373,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
- "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
+ "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
"cpu": [
"arm64"
],
@@ -1533,9 +1387,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
- "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
+ "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
"cpu": [
"arm64"
],
@@ -1547,9 +1401,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
- "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
+ "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
"cpu": [
"x64"
],
@@ -1561,9 +1415,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
- "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
+ "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
"cpu": [
"arm64"
],
@@ -1575,9 +1429,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
- "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
+ "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
"cpu": [
"x64"
],
@@ -1589,9 +1443,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
- "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
+ "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
"cpu": [
"arm"
],
@@ -1603,9 +1457,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
- "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
+ "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
"cpu": [
"arm"
],
@@ -1617,9 +1471,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
- "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
+ "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
"cpu": [
"arm64"
],
@@ -1631,9 +1485,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
- "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
+ "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
"cpu": [
"arm64"
],
@@ -1645,9 +1499,23 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
- "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
+ "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
+ "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
"cpu": [
"loong64"
],
@@ -1659,9 +1527,23 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
- "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
+ "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
+ "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
"cpu": [
"ppc64"
],
@@ -1673,9 +1555,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
- "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
+ "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
"cpu": [
"riscv64"
],
@@ -1687,9 +1569,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
- "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
+ "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
"cpu": [
"riscv64"
],
@@ -1701,9 +1583,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
- "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
+ "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
"cpu": [
"s390x"
],
@@ -1715,9 +1597,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
- "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
+ "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
"cpu": [
"x64"
],
@@ -1729,9 +1611,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
- "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
+ "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
"cpu": [
"x64"
],
@@ -1742,10 +1624,24 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
+ "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
"node_modules/@rollup/rollup-openharmony-arm64": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
- "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
+ "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
"cpu": [
"arm64"
],
@@ -1757,9 +1653,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
- "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
+ "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
"cpu": [
"arm64"
],
@@ -1771,9 +1667,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
- "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
+ "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
"cpu": [
"ia32"
],
@@ -1785,9 +1681,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
- "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
+ "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
"cpu": [
"x64"
],
@@ -1799,9 +1695,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
- "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
+ "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
"cpu": [
"x64"
],
@@ -1812,12 +1708,6 @@
"win32"
]
},
- "node_modules/@standard-schema/utils": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
- "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
- "license": "MIT"
- },
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
@@ -2101,6 +1991,13 @@
"@babel/types": "^7.28.2"
}
},
+ "node_modules/@types/chance": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@types/chance/-/chance-1.1.7.tgz",
+ "integrity": "sha512-40you9610GTQPJyvjMBgmj9wiDO6qXhbfjizNYod/fmvLSfUUxURAJMTD8tjmbcZSsyYE5iEUox61AAcCjW/wQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/d3": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
@@ -2309,9 +2206,9 @@
"license": "MIT"
},
"node_modules/@types/d3-shape": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
- "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz",
+ "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==",
"license": "MIT",
"dependencies": {
"@types/d3-path": "*"
@@ -2354,13 +2251,6 @@
"@types/d3-selection": "*"
}
},
- "node_modules/@types/dagre": {
- "version": "0.7.53",
- "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.53.tgz",
- "integrity": "sha512-f4gkWqzPZvYmKhOsDnhq/R8mO4UMcKdxZo+i5SCkOU1wvGeHJeUXGIHeE9pnwGyPMDof1Vx5ZQo4nxpeg2TTVQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
@@ -2370,6 +2260,13 @@
"@types/ms": "*"
}
},
+ "node_modules/@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -2422,9 +2319,9 @@
"license": "MIT"
},
"node_modules/@types/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==",
+ "version": "4.17.24",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz",
+ "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==",
"dev": true,
"license": "MIT"
},
@@ -2444,18 +2341,19 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "24.2.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
- "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
+ "version": "25.0.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz",
+ "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~7.10.0"
+ "undici-types": "~7.16.0"
}
},
"node_modules/@types/prismjs": {
- "version": "1.26.5",
- "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz",
- "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
+ "version": "1.26.6",
+ "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz",
+ "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==",
"license": "MIT"
},
"node_modules/@types/prop-types": {
@@ -2465,9 +2363,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
- "version": "18.3.27",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
- "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
+ "version": "18.3.28",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
+ "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -2475,21 +2373,15 @@
}
},
"node_modules/@types/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==",
+ "version": "18.3.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
+ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@types/react": "*"
+ "peerDependencies": {
+ "@types/react": "^18.0.0"
}
},
- "node_modules/@types/trusted-types": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
- "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==",
- "license": "MIT"
- },
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@@ -2501,27 +2393,27 @@
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-11.0.0.tgz",
"integrity": "sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==",
"deprecated": "This is a stub types definition. uuid provides its own type definitions, so you do not need this installed.",
+ "dev": true,
"license": "MIT",
"dependencies": {
"uuid": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz",
- "integrity": "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz",
+ "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.39.1",
- "@typescript-eslint/type-utils": "8.39.1",
- "@typescript-eslint/utils": "8.39.1",
- "@typescript-eslint/visitor-keys": "8.39.1",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/type-utils": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "ignore": "^7.0.5",
"natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2531,23 +2423,33 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.39.1",
- "eslint": "^8.57.0 || ^9.0.0",
+ "@typescript-eslint/parser": "^8.56.1",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/@typescript-eslint/parser": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz",
- "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz",
+ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.39.1",
- "@typescript-eslint/types": "8.39.1",
- "@typescript-eslint/typescript-estree": "8.39.1",
- "@typescript-eslint/visitor-keys": "8.39.1",
- "debug": "^4.3.4"
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2557,20 +2459,20 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.1.tgz",
- "integrity": "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz",
+ "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.39.1",
- "@typescript-eslint/types": "^8.39.1",
- "debug": "^4.3.4"
+ "@typescript-eslint/tsconfig-utils": "^8.56.1",
+ "@typescript-eslint/types": "^8.56.1",
+ "debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2584,14 +2486,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.1.tgz",
- "integrity": "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz",
+ "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.39.1",
- "@typescript-eslint/visitor-keys": "8.39.1"
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2602,9 +2504,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz",
- "integrity": "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz",
+ "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2619,17 +2521,17 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz",
- "integrity": "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz",
+ "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.39.1",
- "@typescript-eslint/typescript-estree": "8.39.1",
- "@typescript-eslint/utils": "8.39.1",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2639,14 +2541,14 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz",
- "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz",
+ "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2658,22 +2560,21 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.1.tgz",
- "integrity": "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz",
+ "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.39.1",
- "@typescript-eslint/tsconfig-utils": "8.39.1",
- "@typescript-eslint/types": "8.39.1",
- "@typescript-eslint/visitor-keys": "8.39.1",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/project-service": "8.56.1",
+ "@typescript-eslint/tsconfig-utils": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/visitor-keys": "8.56.1",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2686,17 +2587,30 @@
"typescript": ">=4.8.4 <6.0.0"
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@typescript-eslint/utils": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.1.tgz",
- "integrity": "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz",
+ "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.39.1",
- "@typescript-eslint/types": "8.39.1",
- "@typescript-eslint/typescript-estree": "8.39.1"
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.56.1",
+ "@typescript-eslint/types": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2706,19 +2620,19 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.39.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.1.tgz",
- "integrity": "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz",
+ "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.39.1",
- "eslint-visitor-keys": "^4.2.1"
+ "@typescript-eslint/types": "8.56.1",
+ "eslint-visitor-keys": "^5.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2728,23 +2642,10 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
"node_modules/@uiw/copy-to-clipboard": {
- "version": "1.0.17",
- "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.17.tgz",
- "integrity": "sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A==",
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.20.tgz",
+ "integrity": "sha512-IFQhS62CLNon1YgYJTEzXR2N3WVXg7V1FaBRDLMlzU6JY5X6Hr3OPAcw4WNoKcz2XcFD6XCgwEjlsmj+JA0mWA==",
"license": "MIT",
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
@@ -2785,30 +2686,30 @@
"license": "ISC"
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
- "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
+ "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.28.0",
+ "@babel/core": "^7.29.0",
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
- "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@rolldown/pluginutils": "1.0.0-rc.3",
"@types/babel__core": "^7.20.5",
- "react-refresh": "^0.17.0"
+ "react-refresh": "^0.18.0"
},
"engines": {
- "node": "^14.18.0 || >=16.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true,
"license": "MIT",
"bin": {
@@ -2829,9 +2730,9 @@
}
},
"node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2845,32 +2746,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -2878,13 +2753,6 @@
"dev": true,
"license": "Python-2.0"
},
- "node_modules/async": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
- "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -2901,13 +2769,13 @@
}
},
"node_modules/axios": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
- "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
+ "version": "1.13.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
+ "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.4",
+ "follow-redirects": "^1.15.11",
+ "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
@@ -2922,11 +2790,14 @@
}
},
"node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
},
"node_modules/base64-js": {
"version": "1.5.1",
@@ -2949,13 +2820,16 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
- "version": "2.9.4",
- "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.4.tgz",
- "integrity": "sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA==",
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
+ "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
- "baseline-browser-mapping": "dist/cli.js"
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
}
},
"node_modules/bcp-47-match": {
@@ -2975,26 +2849,16 @@
"license": "ISC"
},
"node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
+ "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "fill-range": "^7.1.1"
+ "balanced-match": "^4.0.2"
},
"engines": {
- "node": ">=8"
+ "node": "18 || 20 || >=22"
}
},
"node_modules/browserslist": {
@@ -3031,19 +2895,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
- "node_modules/btoa": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
- "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
- "dev": true,
- "license": "(MIT OR Apache-2.0)",
- "bin": {
- "btoa": "bin/btoa.js"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -3105,9 +2956,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001759",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz",
- "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==",
+ "version": "1.0.30001774",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz",
+ "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==",
"dev": true,
"funding": [
{
@@ -3135,22 +2986,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
+ "node_modules/chance": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.13.tgz",
+ "integrity": "sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg==",
+ "license": "MIT"
},
"node_modules/character-entities": {
"version": "2.0.2",
@@ -3192,41 +3032,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -3258,13 +3063,6 @@
"node": ">= 10"
}
},
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -3328,9 +3126,9 @@
}
},
"node_modules/css-selector-parser": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.2.0.tgz",
- "integrity": "sha512-L1bdkNKUP5WYxiW5dW6vA2hd3sL8BdRNLy2FCX0rLVise4eNw9nBdeBuJHxlELieSE2H1f6bYQFfwVUwWCV9rQ==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz",
+ "integrity": "sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==",
"funding": [
{
"type": "github",
@@ -3555,9 +3353,9 @@
}
},
"node_modules/d3-format": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
- "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
+ "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
"license": "ISC",
"engines": {
"node": ">=12"
@@ -3774,9 +3572,9 @@
}
},
"node_modules/decode-named-character-reference": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
- "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+ "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
"license": "MIT",
"dependencies": {
"character-entities": "^2.0.0"
@@ -3793,16 +3591,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/define-lazy-prop": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
- "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/delaunator": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
@@ -3896,42 +3684,18 @@
"node": ">= 0.4"
}
},
- "node_modules/duplexer": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
- "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/ejs": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
- "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "jake": "^10.8.5"
- },
- "bin": {
- "ejs": "bin/cli.js"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/electron-to-chromium": {
- "version": "1.5.266",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz",
- "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==",
+ "version": "1.5.302",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz",
+ "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==",
"dev": true,
"license": "ISC"
},
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
+ "node_modules/elkjs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.11.0.tgz",
+ "integrity": "sha512-u4J8h9mwEDaYMqo0RYJpqNMFDoMK7f+pu4GjcV+N8jIC7TRdORgzkfSjTJemhqONFfH6fBI3wpysgWbhgVWIXw==",
+ "license": "EPL-2.0"
},
"node_modules/entities": {
"version": "6.0.1",
@@ -4001,9 +3765,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
- "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
+ "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -4014,32 +3778,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.12",
- "@esbuild/android-arm": "0.25.12",
- "@esbuild/android-arm64": "0.25.12",
- "@esbuild/android-x64": "0.25.12",
- "@esbuild/darwin-arm64": "0.25.12",
- "@esbuild/darwin-x64": "0.25.12",
- "@esbuild/freebsd-arm64": "0.25.12",
- "@esbuild/freebsd-x64": "0.25.12",
- "@esbuild/linux-arm": "0.25.12",
- "@esbuild/linux-arm64": "0.25.12",
- "@esbuild/linux-ia32": "0.25.12",
- "@esbuild/linux-loong64": "0.25.12",
- "@esbuild/linux-mips64el": "0.25.12",
- "@esbuild/linux-ppc64": "0.25.12",
- "@esbuild/linux-riscv64": "0.25.12",
- "@esbuild/linux-s390x": "0.25.12",
- "@esbuild/linux-x64": "0.25.12",
- "@esbuild/netbsd-arm64": "0.25.12",
- "@esbuild/netbsd-x64": "0.25.12",
- "@esbuild/openbsd-arm64": "0.25.12",
- "@esbuild/openbsd-x64": "0.25.12",
- "@esbuild/openharmony-arm64": "0.25.12",
- "@esbuild/sunos-x64": "0.25.12",
- "@esbuild/win32-arm64": "0.25.12",
- "@esbuild/win32-ia32": "0.25.12",
- "@esbuild/win32-x64": "0.25.12"
+ "@esbuild/aix-ppc64": "0.27.3",
+ "@esbuild/android-arm": "0.27.3",
+ "@esbuild/android-arm64": "0.27.3",
+ "@esbuild/android-x64": "0.27.3",
+ "@esbuild/darwin-arm64": "0.27.3",
+ "@esbuild/darwin-x64": "0.27.3",
+ "@esbuild/freebsd-arm64": "0.27.3",
+ "@esbuild/freebsd-x64": "0.27.3",
+ "@esbuild/linux-arm": "0.27.3",
+ "@esbuild/linux-arm64": "0.27.3",
+ "@esbuild/linux-ia32": "0.27.3",
+ "@esbuild/linux-loong64": "0.27.3",
+ "@esbuild/linux-mips64el": "0.27.3",
+ "@esbuild/linux-ppc64": "0.27.3",
+ "@esbuild/linux-riscv64": "0.27.3",
+ "@esbuild/linux-s390x": "0.27.3",
+ "@esbuild/linux-x64": "0.27.3",
+ "@esbuild/netbsd-arm64": "0.27.3",
+ "@esbuild/netbsd-x64": "0.27.3",
+ "@esbuild/openbsd-arm64": "0.27.3",
+ "@esbuild/openbsd-x64": "0.27.3",
+ "@esbuild/openharmony-arm64": "0.27.3",
+ "@esbuild/sunos-x64": "0.27.3",
+ "@esbuild/win32-arm64": "0.27.3",
+ "@esbuild/win32-ia32": "0.27.3",
+ "@esbuild/win32-x64": "0.27.3"
}
},
"node_modules/escalade": {
@@ -4052,13 +3816,6 @@
"node": ">=6"
}
},
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -4073,34 +3830,30 @@
}
},
"node_modules/eslint": {
- "version": "9.33.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz",
- "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.1.tgz",
+ "integrity": "sha512-20MV9SUdeN6Jd84xESsKhRly+/vxI+hwvpBMA93s+9dAcjdCuCojn4IqUGS3lvVaqjVYGYHSRMCpeFtF2rQYxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.21.0",
- "@eslint/config-helpers": "^0.3.1",
- "@eslint/core": "^0.15.2",
- "@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.33.0",
- "@eslint/plugin-kit": "^0.3.5",
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.2",
+ "@eslint/config-helpers": "^0.5.2",
+ "@eslint/core": "^1.1.0",
+ "@eslint/plugin-kit": "^0.6.0",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6",
- "@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
- "chalk": "^4.0.0",
"cross-spawn": "^7.0.6",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.4.0",
- "eslint-visitor-keys": "^4.2.1",
- "espree": "^10.4.0",
- "esquery": "^1.5.0",
+ "eslint-scope": "^9.1.1",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.1.1",
+ "esquery": "^1.7.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^8.0.0",
@@ -4110,8 +3863,7 @@
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
+ "minimatch": "^10.2.1",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3"
},
@@ -4119,7 +3871,7 @@
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://eslint.org/donate"
@@ -4134,117 +3886,59 @@
}
},
"node_modules/eslint-scope": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
- "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.1.tgz",
+ "integrity": "sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/eslint/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint/node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/eslint/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.1.tgz",
+ "integrity": "sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "eslint-visitor-keys": "^5.0.1"
},
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
- "dev": true,
- "license": "Apache-2.0",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esquery": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
- "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -4317,36 +4011,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -4361,14 +4025,22 @@
"dev": true,
"license": "MIT"
},
- "node_modules/fastq": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
- "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4"
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
}
},
"node_modules/file-entry-cache": {
@@ -4402,42 +4074,6 @@
"node": ">= 12"
}
},
- "node_modules/filelist": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
- "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "minimatch": "^5.0.1"
- }
- },
- "node_modules/filelist/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -4521,13 +4157,6 @@
"node": ">= 6"
}
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -4562,16 +4191,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -4615,28 +4234,6 @@
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
"license": "ISC"
},
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -4650,93 +4247,23 @@
"node": ">=10.13.0"
}
},
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "node_modules/globrex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
+ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true,
+ "license": "MIT"
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/glob/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/globals": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globrex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
- "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/gzip-size": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
- "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "duplexer": "^0.1.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
@@ -5141,9 +4668,9 @@
"license": "BSD-3-Clause"
},
"node_modules/ignore": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5177,25 +4704,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/inline-style-parser": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
@@ -5252,22 +4760,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/is-docker": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
- "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5278,16 +4770,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -5311,16 +4793,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.12.0"
- }
- },
"node_modules/is-plain-obj": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
@@ -5333,19 +4805,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-docker": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -5353,31 +4812,13 @@
"dev": true,
"license": "ISC"
},
- "node_modules/jake": {
- "version": "10.9.4",
- "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
- "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "async": "^3.2.6",
- "filelist": "^1.0.4",
- "picocolors": "^1.1.1"
- },
- "bin": {
- "jake": "bin/cli.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/javascript-time-ago": {
- "version": "2.5.12",
- "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.12.tgz",
- "integrity": "sha512-s8PPq2HQ3HIbSU0SjhNvTitf5VoXbQWof9q6k3gIX7F2il0ptjD5lONTDccpuKt/2U7RjbCp/TCHPK7eDwO7zQ==",
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.6.2.tgz",
+ "integrity": "sha512-gagMB4fetS1M1ZHaxQ9kX2amORXa5Los5PGh8NZzWSKrytz43KnpJlaPFTXbg/R7iPMN7U/6MoevgxqJ0QQ5lA==",
"license": "MIT",
"dependencies": {
- "relative-time-format": "^1.1.7"
+ "relative-time-format": "^1.1.11"
}
},
"node_modules/js-tokens": {
@@ -5460,9 +4901,9 @@
}
},
"node_modules/keycloak-js": {
- "version": "26.2.1",
- "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.1.tgz",
- "integrity": "sha512-bZt6fQj/TLBAmivXSxSlqAJxBx/knNZDQGJIW4ensGYGN4N6tUKV8Zj3Y7/LOV8eIpvWsvqV70fbACihK8Ze0Q==",
+ "version": "26.2.3",
+ "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.3.tgz",
+ "integrity": "sha512-widjzw/9T6bHRgEp6H/Se3NCCarU7u5CwFKBcwtu7xfA1IfdZb+7Q7/KGusAnBo34Vtls8Oz9vzSqkQvQ7+b4Q==",
"license": "Apache-2.0",
"workspaces": [
"test"
@@ -5516,9 +4957,9 @@
}
},
"node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash.debounce": {
@@ -5527,13 +4968,6 @@
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
"license": "MIT"
},
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/longest-streak": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
@@ -5624,9 +5058,9 @@
}
},
"node_modules/mdast-util-from-markdown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
- "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
+ "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -5883,16 +5317,6 @@
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
"license": "MIT"
},
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/micromark": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
@@ -6456,20 +5880,6 @@
],
"license": "MIT"
},
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -6492,44 +5902,21 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "10.2.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
+ "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"dev": true,
- "license": "ISC",
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^5.0.2"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/mkdirp": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
- "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.6"
- },
- "bin": {
- "mkdirp": "bin/cmd.js"
- }
- },
"node_modules/mobx": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.0.tgz",
@@ -6588,13 +5975,10 @@
}
},
"node_modules/monaco-editor": {
- "version": "0.53.0",
- "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0.tgz",
- "integrity": "sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==",
- "license": "MIT",
- "dependencies": {
- "@types/trusted-types": "^1.0.6"
- }
+ "version": "0.52.2",
+ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
+ "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
+ "license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
@@ -6667,34 +6051,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/open": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
- "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-lazy-prop": "^2.0.0",
- "is-docker": "^2.1.1",
- "is-wsl": "^2.2.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -6830,16 +6186,6 @@
"node": ">=8"
}
},
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -6868,13 +6214,13 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=8.6"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
@@ -6950,12 +6296,6 @@
"react-is": "^16.13.1"
}
},
- "node_modules/property-expr": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
- "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
- "license": "MIT"
- },
"node_modules/property-information": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
@@ -6982,27 +6322,6 @@
"node": ">=6"
}
},
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
"node_modules/react": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -7029,9 +6348,9 @@
}
},
"node_modules/react-dropzone": {
- "version": "14.3.8",
- "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz",
- "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==",
+ "version": "14.4.1",
+ "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.4.1.tgz",
+ "integrity": "sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==",
"license": "MIT",
"dependencies": {
"attr-accept": "^2.2.4",
@@ -7052,9 +6371,9 @@
"license": "MIT"
},
"node_modules/react-hook-form": {
- "version": "7.65.0",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.65.0.tgz",
- "integrity": "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==",
+ "version": "7.71.2",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz",
+ "integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
@@ -7100,9 +6419,9 @@
}
},
"node_modules/react-refresh": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
- "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7110,19 +6429,19 @@
}
},
"node_modules/react-resizable-panels": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.6.tgz",
- "integrity": "sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==",
+ "version": "4.6.5",
+ "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-4.6.5.tgz",
+ "integrity": "sha512-pmQP6qv9KmsesNMvWVNvVfVJAwYSOWWbAOAtrPR8Cre20+j1NWIlyft0btjtDQE+OepXmI6g3VPrCXQY0oD7+Q==",
"license": "MIT",
"peerDependencies": {
- "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
- "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
}
},
"node_modules/react-router": {
- "version": "7.9.4",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz",
- "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==",
+ "version": "7.13.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz",
+ "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
@@ -7142,12 +6461,12 @@
}
},
"node_modules/react-router-dom": {
- "version": "7.9.4",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz",
- "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==",
+ "version": "7.13.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz",
+ "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==",
"license": "MIT",
"dependencies": {
- "react-router": "7.9.4"
+ "react-router": "7.13.1"
},
"engines": {
"node": ">=20.0.0"
@@ -7204,6 +6523,21 @@
"url": "https://jaywcjlove.github.io/#/sponsor"
}
},
+ "node_modules/rehype-attr/node_modules/unist-util-visit": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
+ "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
"node_modules/rehype-autolink-headings": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz",
@@ -7223,9 +6557,9 @@
}
},
"node_modules/rehype-ignore": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-2.0.2.tgz",
- "integrity": "sha512-BpAT/3lU9DMJ2siYVD/dSR0A/zQgD6Fb+fxkJd4j+wDVy6TYbYpK+FZqu8eM9EuNKGvi4BJR7XTZ/+zF02Dq8w==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-2.0.3.tgz",
+ "integrity": "sha512-IzhP6/u/6sm49sdktuYSmeIuObWB+5yC/5eqVws8BhuGA9kY25/byz6uCy/Ravj6lXUShEd2ofHM5MyAIj86Sg==",
"license": "MIT",
"dependencies": {
"hast-util-select": "^6.0.0",
@@ -7284,9 +6618,9 @@
}
},
"node_modules/rehype-rewrite": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-4.0.3.tgz",
- "integrity": "sha512-y6zPHL2tBqm1TF+lFV8SKH65+DYqkm1CUXipNebTo4l4R/rL4bOLOS+klp9VlcKhytiyYVZB72AA/1F4+lOk9g==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-4.0.4.tgz",
+ "integrity": "sha512-L/FO96EOzSA6bzOam4DVu61/PB3AGKcSPXpa53yMIozoxH4qg1+bVZDF8zh1EsuxtSauAhzt5cCnvoplAaSLrw==",
"license": "MIT",
"dependencies": {
"hast-util-select": "^6.0.0",
@@ -7318,9 +6652,9 @@
}
},
"node_modules/relative-time-format": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.11.tgz",
- "integrity": "sha512-TH+oV/w77hjaB9xCzoFYJ/Icmr/12+02IAoCI/YGS2UBTbjCbBjHGEBxGnVy4EJvOR1qadGzyFRI6hGaJJG93Q==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.12.tgz",
+ "integrity": "sha512-qaZBjmRIuXLfuLnzgqpFdBPa5W0euSX1tMnoMUHGPphLwJmrt8xbNiOIHrlvYOD6oNJ0M5owPCZyPibI8de5pQ==",
"license": "MIT"
},
"node_modules/remark-gfm": {
@@ -7404,16 +6738,6 @@
"url": "https://opencollective.com/unified"
}
},
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -7424,31 +6748,6 @@
"node": ">=4"
}
},
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
"node_modules/robust-predicates": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
@@ -7456,9 +6755,9 @@
"license": "Unlicense"
},
"node_modules/rollup": {
- "version": "4.53.3",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
- "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
+ "version": "4.59.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
+ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7472,99 +6771,34 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.53.3",
- "@rollup/rollup-android-arm64": "4.53.3",
- "@rollup/rollup-darwin-arm64": "4.53.3",
- "@rollup/rollup-darwin-x64": "4.53.3",
- "@rollup/rollup-freebsd-arm64": "4.53.3",
- "@rollup/rollup-freebsd-x64": "4.53.3",
- "@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
- "@rollup/rollup-linux-arm-musleabihf": "4.53.3",
- "@rollup/rollup-linux-arm64-gnu": "4.53.3",
- "@rollup/rollup-linux-arm64-musl": "4.53.3",
- "@rollup/rollup-linux-loong64-gnu": "4.53.3",
- "@rollup/rollup-linux-ppc64-gnu": "4.53.3",
- "@rollup/rollup-linux-riscv64-gnu": "4.53.3",
- "@rollup/rollup-linux-riscv64-musl": "4.53.3",
- "@rollup/rollup-linux-s390x-gnu": "4.53.3",
- "@rollup/rollup-linux-x64-gnu": "4.53.3",
- "@rollup/rollup-linux-x64-musl": "4.53.3",
- "@rollup/rollup-openharmony-arm64": "4.53.3",
- "@rollup/rollup-win32-arm64-msvc": "4.53.3",
- "@rollup/rollup-win32-ia32-msvc": "4.53.3",
- "@rollup/rollup-win32-x64-gnu": "4.53.3",
- "@rollup/rollup-win32-x64-msvc": "4.53.3",
+ "@rollup/rollup-android-arm-eabi": "4.59.0",
+ "@rollup/rollup-android-arm64": "4.59.0",
+ "@rollup/rollup-darwin-arm64": "4.59.0",
+ "@rollup/rollup-darwin-x64": "4.59.0",
+ "@rollup/rollup-freebsd-arm64": "4.59.0",
+ "@rollup/rollup-freebsd-x64": "4.59.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.59.0",
+ "@rollup/rollup-linux-arm64-musl": "4.59.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.59.0",
+ "@rollup/rollup-linux-loong64-musl": "4.59.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.59.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.59.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.59.0",
+ "@rollup/rollup-linux-x64-gnu": "4.59.0",
+ "@rollup/rollup-linux-x64-musl": "4.59.0",
+ "@rollup/rollup-openbsd-x64": "4.59.0",
+ "@rollup/rollup-openharmony-arm64": "4.59.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.59.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.59.0",
+ "@rollup/rollup-win32-x64-gnu": "4.59.0",
+ "@rollup/rollup-win32-x64-msvc": "4.59.0",
"fsevents": "~2.3.2"
}
},
- "node_modules/rollup-plugin-visualizer": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.5.tgz",
- "integrity": "sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "open": "^8.0.0",
- "picomatch": "^4.0.2",
- "source-map": "^0.7.4",
- "yargs": "^17.5.1"
- },
- "bin": {
- "rollup-plugin-visualizer": "dist/bin/cli.js"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "rolldown": "1.x || ^1.0.0-beta",
- "rollup": "2.x || 3.x || 4.x"
- },
- "peerDependenciesMeta": {
- "rolldown": {
- "optional": true
- },
- "rollup": {
- "optional": true
- }
- }
- },
- "node_modules/rollup-plugin-visualizer/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
"node_modules/rw": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
@@ -7596,16 +6830,13 @@
}
},
"node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
}
},
"node_modules/set-cookie-parser": {
@@ -7648,109 +6879,6 @@
"tslib": "^2.0.3"
}
},
- "node_modules/source-map": {
- "version": "0.7.6",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
- "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">= 12"
- }
- },
- "node_modules/source-map-explorer": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/source-map-explorer/-/source-map-explorer-2.5.3.tgz",
- "integrity": "sha512-qfUGs7UHsOBE5p/lGfQdaAj/5U/GWYBw2imEpD6UQNkqElYonkow8t+HBL1qqIl3CuGZx7n8/CQo4x1HwSHhsg==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "btoa": "^1.2.1",
- "chalk": "^4.1.0",
- "convert-source-map": "^1.7.0",
- "ejs": "^3.1.5",
- "escape-html": "^1.0.3",
- "glob": "^7.1.6",
- "gzip-size": "^6.0.0",
- "lodash": "^4.17.20",
- "open": "^7.3.1",
- "source-map": "^0.7.4",
- "temp": "^0.9.4",
- "yargs": "^16.2.0"
- },
- "bin": {
- "sme": "bin/cli.js",
- "source-map-explorer": "bin/cli.js"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/source-map-explorer/node_modules/cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
- "node_modules/source-map-explorer/node_modules/convert-source-map": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
- "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/source-map-explorer/node_modules/open": {
- "version": "7.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
- "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/source-map-explorer/node_modules/yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/source-map-explorer/node_modules/yargs-parser": {
- "version": "20.2.9",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
- "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -7777,21 +6905,6 @@
"integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==",
"license": "MIT"
},
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/stringify-entities": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
@@ -7806,32 +6919,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/style-to-js": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz",
@@ -7850,19 +6937,6 @@
"inline-style-parser": "0.2.7"
}
},
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/svg-parser": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
@@ -7871,29 +6945,9 @@
"license": "MIT"
},
"node_modules/tabbable": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.3.0.tgz",
- "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==",
- "license": "MIT"
- },
- "node_modules/temp": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz",
- "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mkdirp": "^0.5.1",
- "rimraf": "~2.6.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/tiny-case": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
- "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
"license": "MIT"
},
"node_modules/tinyglobby": {
@@ -7913,56 +6967,6 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/tinyglobby/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/toposort": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
- "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
- "license": "MIT"
- },
"node_modules/trim-lines": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
@@ -7984,9 +6988,9 @@
}
},
"node_modules/ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
+ "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8036,18 +7040,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/type-fest": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
- "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=12.20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -8063,45 +7055,16 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz",
- "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/eslint-plugin": "8.46.2",
- "@typescript-eslint/parser": "8.46.2",
- "@typescript-eslint/typescript-estree": "8.46.2",
- "@typescript-eslint/utils": "8.46.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz",
- "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==",
+ "version": "8.56.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz",
+ "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.46.2",
- "@typescript-eslint/type-utils": "8.46.2",
- "@typescript-eslint/utils": "8.46.2",
- "@typescript-eslint/visitor-keys": "8.46.2",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
+ "@typescript-eslint/eslint-plugin": "8.56.1",
+ "@typescript-eslint/parser": "8.56.1",
+ "@typescript-eslint/typescript-estree": "8.56.1",
+ "@typescript-eslint/utils": "8.56.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -8111,220 +7074,15 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.46.2",
- "eslint": "^8.57.0 || ^9.0.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz",
- "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.46.2",
- "@typescript-eslint/types": "8.46.2",
- "@typescript-eslint/typescript-estree": "8.46.2",
- "@typescript-eslint/visitor-keys": "8.46.2",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz",
- "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.46.2",
- "@typescript-eslint/types": "^8.46.2",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz",
- "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.46.2",
- "@typescript-eslint/visitor-keys": "8.46.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz",
- "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz",
- "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.46.2",
- "@typescript-eslint/typescript-estree": "8.46.2",
- "@typescript-eslint/utils": "8.46.2",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz",
- "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz",
- "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.46.2",
- "@typescript-eslint/tsconfig-utils": "8.46.2",
- "@typescript-eslint/types": "8.46.2",
- "@typescript-eslint/visitor-keys": "8.46.2",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz",
- "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.46.2",
- "@typescript-eslint/types": "8.46.2",
- "@typescript-eslint/typescript-estree": "8.46.2"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.46.2",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz",
- "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.46.2",
- "eslint-visitor-keys": "^4.2.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
"node_modules/undici-types": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/unified": {
@@ -8397,9 +7155,9 @@
}
},
"node_modules/unist-util-visit": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
- "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
+ "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
"license": "MIT",
"dependencies": {
"@types/unist": "^3.0.0",
@@ -8426,9 +7184,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",
- "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"dev": true,
"funding": [
{
@@ -9072,13 +7830,13 @@
}
},
"node_modules/vite": {
- "version": "7.2.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz",
- "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==",
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "esbuild": "^0.25.0",
+ "esbuild": "^0.27.0",
"fdir": "^6.5.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.6",
@@ -9162,9 +7920,9 @@
}
},
"node_modules/vite-tsconfig-paths": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz",
- "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==",
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.1.1.tgz",
+ "integrity": "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9174,42 +7932,6 @@
},
"peerDependencies": {
"vite": "*"
- },
- "peerDependenciesMeta": {
- "vite": {
- "optional": true
- }
- }
- },
- "node_modules/vite/node_modules/fdir": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
- "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- },
- "peerDependencies": {
- "picomatch": "^3 || ^4"
- },
- "peerDependenciesMeta": {
- "picomatch": {
- "optional": true
- }
- }
- },
- "node_modules/vite/node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/web-namespaces": {
@@ -9303,41 +8025,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -9345,35 +8032,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -9387,22 +8045,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/yup": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/yup/-/yup-1.7.1.tgz",
- "integrity": "sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==",
- "license": "MIT",
- "dependencies": {
- "property-expr": "^2.0.5",
- "tiny-case": "^1.0.3",
- "toposort": "^2.0.2",
- "type-fest": "^2.19.0"
- }
- },
"node_modules/zustand": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.9.tgz",
- "integrity": "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==",
+ "version": "5.0.11",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz",
+ "integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==",
"license": "MIT",
"engines": {
"node": ">=12.20.0"
diff --git a/karavan-app/src/main/webui/package.json b/karavan-app/src/main/webui/package.json
index 95fc6682..a8ed1a0a 100644
--- a/karavan-app/src/main/webui/package.json
+++ b/karavan-app/src/main/webui/package.json
@@ -1,14 +1,14 @@
{
"name": "karavan",
- "version": "4.14.2",
+ "version": "4.18.0",
"private": true,
"type": "module",
"scripts": {
- "dev": "npm run && vite --port 3008",
- "build": "npm run && tsc && vite build",
- "serve": "npm run && vite preview"
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "serve": "vite preview"
},
- "proxy": "http://127.0.0.1:8888/",
+ "proxy": "http://127.0.0.1:8080/",
"eslintConfig": {
"extends": [
"react-app"
@@ -27,60 +27,56 @@
]
},
"dependencies": {
- "@carbon/icons-react": "11.69.0",
- "@hookform/error-message": "2.0.1",
- "@hookform/resolvers": "5.2.2",
+ "@carbon/icons-react": "11.73.0",
+ "@dagrejs/dagre": "2.0.3",
"@microsoft/fetch-event-source": "^2.0.1",
"@monaco-editor/react": "4.7.0",
"@patternfly/patternfly": "6.4.0",
"@patternfly/react-charts": "8.4.0",
"@patternfly/react-core": "6.4.0",
+ "@patternfly/react-icons": "6.4.0",
"@patternfly/react-log-viewer": "6.3.0",
"@patternfly/react-table": "6.4.0",
"@patternfly/react-templates": "6.4.0",
"@patternfly/react-topology": "6.4.0",
- "@types/js-yaml": "4.0.9",
- "@types/node": "24.2.1",
- "@types/uuid": "11.0.0",
"@uiw/react-markdown-preview": "5.1.5",
- "axios": "1.12.2",
+ "axios": "1.13.5",
"buffer": "6.0.3",
+ "chance": "1.1.13",
+ "elkjs": "^0.11.0",
"file-saver": "2.0.5",
- "javascript-time-ago": "2.5.12",
- "keycloak-js": "26.2.1",
- "lodash": "^4.17.21",
+ "javascript-time-ago": "2.6.2",
+ "keycloak-js": "26.2.3",
+ "lodash": "^4.17.23",
"react": "18.3.1",
"react-dom": "18.3.1",
- "react-hook-form": "7.65.0",
- "react-resizable-panels": "3.0.6",
- "react-router-dom": "7.9.4",
+ "react-hook-form": "7.71.2",
+ "react-resizable-panels": "4.6.5",
+ "react-router-dom": "^7.13.1",
"rxjs": "7.8.2",
"use-sync-external-store": "1.6.0",
"usehooks-ts": "3.1.1",
"uuid": "13.0.0",
"victory": "37.3.6",
- "yup": "1.7.1",
- "zustand": "5.0.9"
+ "zustand": "5.0.11"
},
"devDependencies": {
- "@eslint/js": "9.33.0",
- "@types/dagre": "0.7.53",
+ "@eslint/js": "9.39.2",
+ "@types/chance": "1.1.7",
"@types/file-saver": "2.0.7",
"@types/js-yaml": "^4.0.9",
- "@types/lodash": "^4.17.21",
- "@types/react": "18.3.27",
- "@types/react-dom": "18.3.1",
- "@typescript-eslint/eslint-plugin": "8.39.1",
- "@typescript-eslint/parser": "8.39.1",
- "@vitejs/plugin-react": "^4.7.0",
- "eslint": "9.33.0",
- "monaco-editor": "0.53.0",
- "rollup-plugin-visualizer": "6.0.5",
- "source-map-explorer": "^2.5.3",
+ "@types/lodash": "^4.17.23",
+ "@types/node": "25.0.10",
+ "@types/react": "18.3.28",
+ "@types/react-dom": "18.3.7",
+ "@types/uuid": "11.0.0",
+ "@vitejs/plugin-react": "^5.1.4",
+ "eslint": "10.0.1",
+ "monaco-editor": "^0.52.0",
"typescript": "5.9.3",
- "typescript-eslint": "8.46.2",
- "vite": "7.2.6",
+ "typescript-eslint": "8.56.1",
+ "vite": "7.3.1",
"vite-plugin-svgr": "4.5.0",
- "vite-tsconfig-paths": "5.1.4"
+ "vite-tsconfig-paths": "6.1.1"
}
-}
\ No newline at end of file
+}
diff --git a/karavan-app/src/main/webui/tsconfig.json b/karavan-app/src/main/webui/tsconfig.json
index 63272138..a25692f0 100644
--- a/karavan-app/src/main/webui/tsconfig.json
+++ b/karavan-app/src/main/webui/tsconfig.json
@@ -13,6 +13,7 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
+ "strictNullChecks": false,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx",
"types": ["vite/client", "vite-plugin-svgr/client"],
diff --git a/karavan-app/src/main/webui/vite-env.d.ts b/karavan-app/src/main/webui/vite-env.d.ts
index 151aa685..11f02fe2 100644
--- a/karavan-app/src/main/webui/vite-env.d.ts
+++ b/karavan-app/src/main/webui/vite-env.d.ts
@@ -1 +1 @@
-/// <reference types="vite/client" />
\ No newline at end of file
+/// <reference types="vite/client" />
diff --git a/karavan-app/src/main/webui/vite.config.ts b/karavan-app/src/main/webui/vite.config.ts
index 44ce1b0b..0fa2b447 100644
--- a/karavan-app/src/main/webui/vite.config.ts
+++ b/karavan-app/src/main/webui/vite.config.ts
@@ -1,92 +1,27 @@
-/*
- * 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 {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'
import viteTsconfigPaths from 'vite-tsconfig-paths'
-import {visualizer} from 'rollup-plugin-visualizer';
-import path from 'path';
import svgr from 'vite-plugin-svgr';
// https://vitejs.dev/config/
export default defineConfig({
base: '',
plugins: [
+ viteTsconfigPaths(),
svgr(),
react(),
- viteTsconfigPaths(),
- visualizer({
- filename: 'stats.html',
- template: 'treemap',
- gzipSize: true,
- brotliSize: true,
- open: true
- })
],
server: {
- // this ensures that the browser opens upon server start
open: false,
- // this sets a default port to 3000, you can change this
port: 3003,
},
build: {
- // sourcemap: true,
- rollupOptions: {
- output: {
- // vite.config.ts (replace only the manualChunks function body)
- manualChunks(id) {
- // Normalize path for cross-platform matching
- const n = id.replace(/\\/g, '/');
-
- // Helper: extract top-level package name, works with pnpm + npm
- const m = n.match(/node_modules\/(?:\.pnpm\/)?((?:@[^/]+\/)?[^/@]+)/);
- const pkg = m?.[1] ?? '';
-
- if (n.includes('/node_modules/')) {
- // --- React family in one chunk ---
- // if (
- // pkg === 'react' ||
- // pkg === 'react-dom' ||
- // pkg === 'react-is' ||
- // pkg === 'scheduler' ||
- // pkg === 'history' ||
- // pkg.startsWith('react-router')
- // ) return 'vendor-react';
-
- // --- Monaco bucket ---
- if (pkg.includes('monaco-')) return 'vendor-monaco';
-
- // --- PatternFly ---
- if (pkg.startsWith('@patternfly/')) return 'vendor-patternfly';
-
- // --- Known heavy libs (named buckets so you can spot them) ---
- if (pkg.startsWith('refractor')) return 'vendor-refractor';
- if (pkg.startsWith('chance')) return 'vendor-chance';
- if (pkg.startsWith('victory')) return 'vendor-victory';
-
- // --- Fallback: group by package to avoid one huge "others" ---
- return `vendor-other`;
- }
-
- // --- Your app code buckets ---
- // Keep your special case for the local package:
- if (n.includes('karavan-core')) return 'karavan-core';
- }
- }
- }
+ rollupOptions: {}
+ },
+ // CRITICAL FIX: Placed at the root level!
+ // This forces Vite to convert the old CommonJS path-browserify into an ES Module.
+ // (Do NOT include the worker.js files here, as Vite handles them natively now)
+ optimizeDeps: {
+ include: ['path-browserify']
}
})
\ No newline at end of file
(camel-karavan) 16/33: Front-end App for 4.18.0
Posted by ma...@apache.org.
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 09ea30ee09b10db001105bdcfe7f901a4592690a
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:43:56 2026 -0500
Front-end App for 4.18.0
---
karavan-app/src/main/webui/src/karavan/app/App.tsx | 20 +-
.../src/main/webui/src/karavan/app/MainHook.tsx | 31 +-
.../main/webui/src/karavan/app/ReadinessPanel.tsx | 29 +-
.../main/webui/src/karavan/app/login/LoginPage.css | 358 ++++++++++++++++++++-
.../main/webui/src/karavan/app/login/LoginPage.tsx | 215 ++++++++++---
.../webui/src/karavan/app/login/UserPopupOidc.tsx | 1 -
.../src/karavan/app/navigation/MainRoutes.tsx | 57 +++-
.../src/karavan/app/navigation/NavigationMenu.tsx | 50 ++-
.../karavan/app/navigation/NotAuthorizedPage.tsx | 16 +
.../src/karavan/app/navigation/PageNavigation.css | 178 ++++++----
.../src/karavan/app/navigation/PageNavigation.tsx | 137 ++++----
.../webui/src/karavan/app/navigation/Routes.ts | 27 +-
.../webui/src/karavan/app/theme/DarkModeToggle.tsx | 16 +
.../webui/src/karavan/app/theme/ThemeContext.tsx | 45 ++-
14 files changed, 940 insertions(+), 240 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/app/App.tsx b/karavan-app/src/main/webui/src/karavan/app/App.tsx
index e7f7536e..a75ee5d1 100644
--- a/karavan-app/src/main/webui/src/karavan/app/App.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/App.tsx
@@ -1,12 +1,28 @@
+/*
+ * 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, {useContext, useEffect, useRef} from "react";
import './App.css';
import {mainHook} from "./MainHook";
-import {Notification} from "@features/integration/designer/utils/Notification";
+import {Notification} from "@features/project/designer/utils/Notification";
import {NotificationApi} from "@api/NotificationApi";
import {AuthContext} from "@api/auth/AuthProvider";
import {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
import {PLATFORM_DEVELOPER} from "@models/AccessModels";
-import {PageNavigation} from "@app/navigation/PageNavigation";
+import PageNavigation from "@app/navigation/PageNavigation";
import {MainRoutes} from "@app/navigation/MainRoutes";
import {ReadinessPanel} from "@app/ReadinessPanel";
import {useReadinessStore} from "@stores/ReadinessStore";
diff --git a/karavan-app/src/main/webui/src/karavan/app/MainHook.tsx b/karavan-app/src/main/webui/src/karavan/app/MainHook.tsx
index b27c052a..09f53db3 100644
--- a/karavan-app/src/main/webui/src/karavan/app/MainHook.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/MainHook.tsx
@@ -1,8 +1,24 @@
+/*
+ * 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 {KaravanApi} from "@api/KaravanApi";
import {ComponentApi} from "@karavan-core/api/ComponentApi";
-import {AppConfig, ContainerStatus, Project} from "@models/ProjectModels";
-import {useAppConfigStore, useProjectsStore, useStatusesStore} from "@stores/ProjectStore";
-import {InfrastructureAPI} from "@features/integration/designer/utils/InfrastructureAPI";
+import {AppConfig, Project} from "@models/ProjectModels";
+import {useAppConfigStore, useProjectsStore} from "@stores/ProjectStore";
+import {InfrastructureAPI} from "@features/project/designer/utils/InfrastructureAPI";
import {shallow} from "zustand/shallow";
import {ProjectService} from "@services/ProjectService";
import {SpiBeanApi} from "@karavan-core/api/SpiBeanApi";
@@ -11,21 +27,20 @@ import {useContext} from "react";
import {AuthContext} from "@api/auth/AuthProvider";
import {useReadinessStore} from "@stores/ReadinessStore";
import {AuthApi} from "@api/auth/AuthApi";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
export function mainHook () {
const {readiness} = useReadinessStore();
const [setConfig, setDockerInfo] = useAppConfigStore((s) => [s.setConfig, s.setDockerInfo], shallow)
const [setProjects] = useProjectsStore((s) => [s.setProjects], shallow)
- const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow);
+ const {fetchContainers} = useContainerStatusesStore();
const [selectedEnv, selectEnvironment] = useAppConfigStore((state) => [state.selectedEnv, state.selectEnvironment], shallow)
const { user } = useContext(AuthContext);
const getStatuses = () => {
if (user) {
- KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
- setContainers(statuses);
- });
+ fetchContainers();
}
}
@@ -50,8 +65,6 @@ export function mainHook () {
updateBeans();
updateAllConfigurations();
ProjectService.loadCamelAndCustomKamelets();
- ProjectService.reloadBlockedTemplates();
- // updateSupportedComponents(); // not implemented yet
}
}
diff --git a/karavan-app/src/main/webui/src/karavan/app/ReadinessPanel.tsx b/karavan-app/src/main/webui/src/karavan/app/ReadinessPanel.tsx
index b777151b..9f75b8d0 100644
--- a/karavan-app/src/main/webui/src/karavan/app/ReadinessPanel.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/ReadinessPanel.tsx
@@ -1,27 +1,36 @@
+/*
+ * 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 './App.css';
import {useReadinessStore} from "@stores/ReadinessStore";
import {useDataPolling} from "@shared/polling/useDataPolling";
import {Bullseye, Content, ContentVariants, Flex, FlexItem, ProgressStep, ProgressStepper, Spinner, Tooltip, TooltipPosition} from "@patternfly/react-core";
import {mainHook} from "@app/MainHook";
-import {KaravanIcon} from "@features/integration/designer/icons/KaravanIcons";
+import {KaravanIcon} from "@features/project/designer/icons/KaravanIcons";
+import {PlatformLogoBase64} from "@app/navigation/PlatformLogo";
const FAST_INTERVAL = 1000; // 1 second (when not ready)
const SLOW_INTERVAL = 10000; // 10 seconds (when ready)
export function ReadinessPanel() {
- // 1. Subscribe to the state and action
const { readiness, fetchReadiness } = useReadinessStore();
-
- // 2. Determine the dynamic interval based on the current state
const isReady = readiness && readiness.status === true;
-
const currentInterval = isReady ? SLOW_INTERVAL : FAST_INTERVAL;
-
- console.log(`Polling interval set to: ${currentInterval}ms`);
-
- // 3. Pass the dynamic interval to the hook
useDataPolling('readiness', fetchReadiness, currentInterval);
const {showSpinner, showStepper} = mainHook();
@@ -31,7 +40,7 @@ export function ReadinessPanel() {
<Bullseye className="loading-page">
<Flex direction={{default: "column"}} justifyContent={{default: "justifyContentCenter"}}>
<FlexItem style={{textAlign: "center"}}>
- {KaravanIcon()}
+ <img src={PlatformLogoBase64()} className="logo" alt='logo'/>
<Content>
<Content component={ContentVariants.h2}>
Waiting for services
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
index 439a3243..40e29f1a 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
+++ b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.css
@@ -1,19 +1,355 @@
-.karavan .login-page {
+.karavan-container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-evenly;
+ align-items: center;
+ height: 100vh;
+ width: 100vw;
+ overflow: hidden;
+}
+
+/* --- LEFT PANEL: Branding --- */
+.karavan-brand-panel {
+ width: 35%;
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ background: var(--pf-t--color--gray--95);
+ gap: 48px;
+}
+
+.brand-content {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
width: 100%;
- height: 100%;
+
+ .brand-name {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 20px;
+
+ .brand-logo-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 12px;
+
+ .logo {
+ height: 40px;
+ width: 40px;
+ }
+ .platform-name-text {
+ font-size: 24px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ }
+ }
+ .gradient-text-blue {
+ background: linear-gradient(to right, #4394e5, #92c5f9);
+
+ -webkit-background-clip: text; /* Safari / Chrome */
+ background-clip: text;
+ color: transparent;
+ }
+ .gradient-text-blue-gold {
+ background: linear-gradient(to right, #fda422, #ec7a08);
+
+ -webkit-background-clip: text; /* Safari / Chrome */
+ background-clip: text;
+ color: transparent;
+ }
+ .gradient-text-gold {
+ background: linear-gradient(to right, #ec7a08, #db5b04);
+
+ -webkit-background-clip: text; /* Safari / Chrome */
+ background-clip: text;
+ color: transparent;
+ }
+
+ .tagline1 {
+ font-weight: 800;
+ font-size: 56px;
+ line-height: 1.1;
+ text-align: center;
+ }
+
+ .tagline2 {
+ font-weight: 400;
+ line-height: 1.5;
+ color: #b9dafc; /* Tblue-200 for subtitle */
+ font-size: 20px;
+ letter-spacing: 0.5px;
+ margin-top: 16px;
+ text-align: center;
+ }
+ }
+}
+
+.solar-content {
display: flex;
flex-direction: column;
- background-color: var(--pf-t--global--background--color--secondary--default);
+ justify-content: center;
+ gap: 8px;
+ /* Container that holds both the center logo and the ring */
+ .solar-system {
+ position: relative;
+ width: 350px; /* Width of the whole system */
+ height: 350px;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ }
}
-.karavan .login-page .logo-panel {
- background-color: var(--pf-t--color--gray--95);
- height: 64px;
+
+.orbit-lines-svg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ transform: translate(-50%, -50%);
+ width: 350px; /* Must match SVG viewBox width */
+ height: 350px; /* Must match SVG viewBox height */
+ z-index: 1; /* Lowest level, behind icons */
+ pointer-events: none; /* Let clicks pass through to the logo */
+
+ /* OPTIONAL: Rotate the gradient slowly for extra "flash" */
+ animation: slowSpin 20s linear infinite;
+}
+
+/* Ensure your icons are on top */
+.orbit-ring {
+ z-index: 5;
+}
+
+/* 1. THE STATIC CENTER LOGO */
+.static-sun {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%); /* Perfectly centered */
+ width: 100px;
+ height: 100px;
+ z-index: 10; /* Ensures it sits ON TOP of the ring lines */
+
+ /* Optional: A nice glow behind the main logo */
+ background: radial-gradient(
+ circle,
+ rgba(236, 122, 8, 0.4) 0%,
+ rgba(236, 122, 8, 0) 60%
+ );
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
-.karavan .login-page .login {
- width: 470px;
+.static-sun a {
+ pointer-events: auto;
+ width: 48px; /* Your actual logo size */
+ height: 48px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: transform 0.3s ease, filter 0.3s ease;
+ &:hover {
+ transform: scale(1.1);
+ }
}
-.karavan .login-page .logo {
- /*height: 48px;*/
-}
\ No newline at end of file
+.static-sun .logo {
+ width: 100%; /* Adjust to fit inside the glow */
+ height: auto;
+ filter: none;
+}
+
+/* 1. The Ring spins clockwise */
+.orbit-ring {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ animation: slowSpin 60s linear infinite;
+}
+
+/* 2. The Item is placed on the ring (Static Position) */
+.orbit-item {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 32px; /* Adjusted size */
+ height: 32px;
+ margin-top: -16px;
+ margin-left: -16px;
+
+ /* Logic: Rotate to angle -> Move out -> Rotate back to upright */
+ transform:
+ rotate(var(--angle))
+ translate(var(--radius))
+ rotate(calc(var(--angle) * -1));
+}
+
+/* 3. The Counter-Rotator spins Counter-Clockwise
+ This cancels out the ring's rotation so the icon always faces North */
+.counter-rotator {
+ width: 100%;
+ height: 100%;
+ animation: slowSpinReverse 60s linear infinite;
+}
+
+/* 4. The Image handles ONLY the look and hover scale */
+.counter-rotator img,
+.counter-rotator svg {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+
+ /* Look */
+ /*filter: grayscale(100%);*/
+ transition: transform 0.3s ease, filter 0.3s ease;
+}
+
+/* Hover Effect: Scale the image, NOT the rotating wrapper */
+.counter-rotator:hover img,
+.counter-rotator:hover svg {
+ filter: none;
+ transform: scale(1.2);
+}
+
+/* --- Keyframes --- */
+@keyframes slowSpin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+@keyframes slowSpinReverse {
+ /* Must match the ring's speed but in REVERSE */
+ from { transform: rotate(360deg); }
+ to { transform: rotate(0deg); }
+}
+
+.anchor-line {
+ width: 1px;
+ height: 50px; /* Length of line */
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 10%, rgba(236, 122, 8, 1) 50%, rgba(255, 255, 255, 0.1) 100%);
+ margin: 0 auto 8px auto; /* Center it and add space below */
+}
+
+.brand-footer {
+ opacity: 0.6;
+ font-size: 0.85rem;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ text-align: center;
+ color: var(--pf-t--color--blue--10);
+ padding-bottom: 60px;
+}
+
+/* --- RIGHT PANEL: Minimal Form --- */
+.karavan-form-panel {
+ width: 65%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+.form-wrapper {
+ width: 100%;
+ max-width: 400px;
+ padding: 20px;
+
+ .login {
+ &::before {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ content: "";
+ border-color: var(--pf-t--color--blue--60);
+ border-style: var(--pf-v6-c-card--BorderStyle);
+ border-width: var(--pf-v6-c-card--BorderWidth);
+ border-radius: inherit;
+ }
+
+ .login-header {
+ color: var(--pf-t--global--text--color--subtle);
+ }
+
+ .environment-dev {
+ background-color: var(--pf-t--global--text--color--brand--default);
+ }
+ .environment-default {
+ background-color: var(--pf-t--global--icon--color--status--warning--default);
+ }
+ .environment-prod {
+ background-color: var(--pf-t--global--icon--color--status--danger--default);
+ }
+ }
+
+ .pf-v6-c-form-control, .pf-v6-c-text-input-group {
+ /*background-color: transparent;*/
+ }
+
+ .pf-v6-c-card__header, .pf-v6-c-card__title, .pf-v6-c-card__body {
+ padding-block-end: var(--pf-t--global--spacer--xl);
+ }
+
+ .pf-v6-c-card__footer {
+ padding-block-end: var(--pf-t--global--spacer--md);
+ }
+
+ .platform-version {
+ color: var(--pf-t--global--text--color--subtle);
+ font-size: var(--pf-t--global--font--size--xs);
+ }
+
+ .button {
+ width: 100%;
+ }
+
+ .button-disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+.powered-by-logo {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+
+
+ .logo, .icon{
+ width: 32px;
+ height: 32px;
+ }
+ .openapi-logo {
+ height: 36px;
+ }
+ .asyncapi-logo {
+ height: 32px;
+ }
+ .json-schema-logo {
+ height: 28px;
+ }
+ .groovy-logo {
+ height: 32px;
+ }
+ .jib-logo {
+ height: 32px;
+ }
+ .infinispan-logo {
+ height: 30px;
+ }
+ .jkube-logo {
+ height: 32px;
+ }
+ .patternfly-logo {
+ height: 28px;
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
index 1d2cefc0..aeac2333 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/login/LoginPage.tsx
@@ -1,12 +1,12 @@
-import React, {useContext} from 'react';
+import React, {useContext, useEffect} from 'react';
import {
- ActionGroup,
Alert,
- Bullseye,
Button,
Card,
CardBody,
- CardTitle,
+ CardFooter,
+ CardHeader,
+ Checkbox,
Content,
Form,
FormAlert,
@@ -19,11 +19,15 @@ import {
import './LoginPage.css'
import EyeIcon from '@patternfly/react-icons/dist/esm/icons/eye-icon';
import EyeSlashIcon from '@patternfly/react-icons/dist/esm/icons/eye-slash-icon';
-import DarkModeToggle from "../theme/DarkModeToggle";
-import {MainToolbar} from "@shared/ui/MainToolbar";
import {AuthContext} from "@api/auth/AuthProvider";
import {AuthApi} from "@api/auth/AuthApi";
-import {KaravanIcon} from "@features/integration/designer/icons/KaravanIcons";
+import {CamelIcon, KaravanIcon, OpenApiIcon} from "@features/project/designer/icons/KaravanIcons";
+import {SvgIcon} from "@shared/icons/SvgIcon";
+import jibLogo from '@shared/icons/jib.png';
+import {PlatformNameForToolbar, PlatformVersion} from "@shared/ui/PlatformLogos";
+import PlatformLogo from "@app/navigation/PlatformLogo";
+import OrbitLines from "@app/login/OrbitLines";
+import {useReadinessStore} from "@stores/ReadinessStore";
export const LoginPage: React.FunctionComponent = () => {
@@ -33,19 +37,31 @@ export const LoginPage: React.FunctionComponent = () => {
const [showError, setShowError] = React.useState(false);
const [error, setError] = React.useState('');
const {reload} = useContext(AuthContext);
+ const { readiness } = useReadinessStore();
+
+ const [titleSvg, setTitleSvg] = React.useState<string>();
+
+ useEffect(() => {
+ }, []);
function onLoginButtonClick(event: any) {
- event.preventDefault();
- AuthApi.login(username, password, (ok, res) => {
- if (!ok) {
- setError(res?.response?.data);
- setShowError(true);
- } else {
- setError('');
- setShowError(false);
- reload();
- }
- })
+ if (!getButtonDisabled()) {
+ event.preventDefault();
+ AuthApi.login(username, password, (ok, res) => {
+ if (!ok) {
+ setError(res?.response?.data);
+ setShowError(true);
+ } else {
+ setError('');
+ setShowError(false);
+ reload();
+ }
+ })
+ }
+ }
+
+ function getButtonDisabled(): boolean {
+ return (username?.length < 3 || password?.length < 3);
}
function onKeyDown(event: React.KeyboardEvent<HTMLFormElement>): void {
@@ -56,24 +72,74 @@ export const LoginPage: React.FunctionComponent = () => {
}
}
+
+ function getLogos() {
+ return [
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://github.com/apache/camel-karavan" target="_blank">{KaravanIcon("logo")}</a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://www.openapis.org/" target="_blank"><OpenApiIcon className={"logo"}/></a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://www.asyncapi.com/" target="_blank">{SvgIcon({icon: 'asyncapi', className: 'asyncapi-logo'})}</a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://json-schema.org/" target="_blank">
+ {SvgIcon({icon: 'json-schema-dark', className: 'json-schema-logo'})}
+ </a>
+ </div>,
+ // <div className="powered-by-logo counter-rotator">
+ // <a href="https://groovy-lang.org/" target="_blank">{SvgIcon({icon: 'groovy', className: 'groovy-logo'})}</a>
+ // </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://github.com/GoogleContainerTools/jib" target="_blank">
+ <img src={jibLogo} alt="Logo" className="jib-logo"/>
+ </a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://camel.apache.org/" target="_blank">{CamelIcon()}</a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://www.patternfly.org/" target={'_blank'}>
+ {SvgIcon({icon: 'patternfly', className: 'patternfly-logo'})}
+ </a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://eclipse.dev/jkube/" target="_blank">
+ {SvgIcon({icon: 'jkube', className: 'jkube-logo'})}
+ </a>
+ </div>,
+ <div className="powered-by-logo counter-rotator">
+ <a href="https://www.keycloak.org/" target="_blank">
+ {SvgIcon({icon: 'keycloak', className: 'patternfly-logo'})}
+ </a>
+ </div>
+ ];
+ }
+
+ const LOGOS = getLogos();
+
function getLoginForm() {
return (
<Form onKeyDown={onKeyDown}>
- <FormGroup fieldId="username" label="Username" isRequired>
+ <FormGroup fieldId="username">
<TextInput className="text-field"
type="text"
id="username"
name="username"
value={username}
+ placeholder={"Username"}
onChange={(_, value) => setUsername(value)}/>
</FormGroup>
- <FormGroup fieldId="password" label="Password" isRequired>
+ <FormGroup fieldId="password">
<TextInputGroup>
<TextInputGroupMain className="text-field"
type={passwordHidden ? "password" : 'text'}
id="password"
name="password"
value={password}
+ placeholder={"Password"}
onChange={(_, value) => setPassword(value)}
/>
<TextInputGroupUtilities>
@@ -87,14 +153,6 @@ export const LoginPage: React.FunctionComponent = () => {
</TextInputGroupUtilities>
</TextInputGroup>
</FormGroup>
- <ActionGroup>
- <Button variant="primary"
- style={{width: '100%'}}
- onClick={onLoginButtonClick}
- >
- Login
- </Button>
- </ActionGroup>
{showError && (
<FormAlert>
<Alert variant="danger" title={<div>{error?.toString()}</div>} aria-live="polite" isInline/>
@@ -104,29 +162,88 @@ export const LoginPage: React.FunctionComponent = () => {
)
}
- return (
- <div className='login-page'>
- <div className="logo-panel">
- <MainToolbar title={<></>} toolsStart={<></>} tools={
- <div id="toolbar-group-types" style={{display: 'flex', alignItems: 'center', gap: '8px', height: '65px'}}>
- {KaravanIcon()}
- <Content component='h1' style={{color: 'var(--pf-t--color--blue--30)'}}>Apache Camel Karavan</Content>
- </div>
- }/>
+
+ function getRightSide() {
+ const buttonClassName = getButtonDisabled() ? "button button-disabled" : "button";
+ return (
+ <div className="karavan-form-panel dark-form">
+ <div className="form-wrapper">
+ <Card className="login" isLarge>
+ <CardHeader>
+ <div style={{display: "flex", flexDirection: 'row', justifyContent: 'space-between', alignItems: "center"}}>
+ <Content component='h3' className="login-header">Login</Content>
+ <PlatformVersion environment={readiness?.environment}/>
+ </div>
+ </CardHeader>
+ <CardBody>
+ {getLoginForm()}
+ </CardBody>
+ <CardFooter style={{ textAlign: "center" }}>
+ <Button variant="primary"
+ className={buttonClassName}
+ onClick={onLoginButtonClick}
+ >
+ Access Platform
+ </Button>
+ </CardFooter>
+ </Card>
+ {/*<DarkModeToggle/>*/}
+ </div>
</div>
- <Bullseye>
- <Card className="login">
- <CardTitle>
- <Content component="h2">Login</Content>
- </CardTitle>
- <CardBody>
- {getLoginForm()}
- </CardBody>
- </Card>
- </Bullseye>
- <div style={{padding: 16}}>
- <DarkModeToggle/>
+ )
+ }
+
+ function getLeftSide() {
+ return (
+ <div className="karavan-brand-panel">
+ <div className="brand-content">
+ <div className="brand-name">
+ <div className="brand-logo-container">
+ {PlatformLogo("logo")}
+ <span className="platform-name-text">{PlatformNameForToolbar()}</span>
+ </div>
+ <div>
+ <div className="tagline1 gradient-text-blue">Accelerate</div>
+ <div className="tagline1 gradient-text-blue-gold">Integration</div>
+ <div className="tagline1 gradient-text-gold">Development</div>
+ </div>
+ <Content component='p' className="tagline2">Unified Design and Runtime for <br/> APIs • Events • Data Pipelines</Content>
+ </div>
+ </div>
+ <div className="solar-content">
+ <div className="solar-system">
+ <OrbitLines />
+ <div className="static-sun">
+ <a href="" target="_blank">
+ {PlatformLogo("logo")}
+ </a>
+ </div>
+ <div className="orbit-ring">
+ {LOGOS.map((logo, index) => {
+ const total = LOGOS.length;
+ const angle = (360 / total) * index;
+ // Increased radius slightly to make room for the center logo
+ const radius = 150;
+ const style = {'--angle': `${angle}deg`, '--radius': `${radius}px`,} as React.CSSProperties;
+ return (
+ <div key={index} className="orbit-item" style={style}>
+ {logo}
+ </div>
+ );
+ })}
+ </div>
+ <div className="anchor-line"></div>
+ <p className="brand-footer">Powered by</p>
+ </div>
+ </div>
</div>
+ )
+ }
+
+ return (
+ <div className="karavan-container">
+ {getLeftSide()}
+ {getRightSide()}
</div>
)
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/UserPopupOidc.tsx b/karavan-app/src/main/webui/src/karavan/app/login/UserPopupOidc.tsx
index 79b8b472..1498d6a9 100644
--- a/karavan-app/src/main/webui/src/karavan/app/login/UserPopupOidc.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/login/UserPopupOidc.tsx
@@ -1,6 +1,5 @@
import React from 'react';
import {Badge, Content, ContentVariants, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Flex, Popover,} from '@patternfly/react-core';
-import '../App.css';
import UserIcon from "@patternfly/react-icons/dist/esm/icons/user-icon";
import {shallow} from "zustand/shallow";
import {useAccessStore} from "@stores/AccessStore";
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
index 5e5822bb..799d4293 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {Navigate, Route, Routes} from 'react-router-dom';
import React from "react";
import {NotAuthorizedPage} from "@app/navigation/NotAuthorizedPage";
@@ -5,13 +21,19 @@ import {SystemPage} from "@features/system/SystemPage";
import {AccessPage} from "@features/access/AccessPage";
import {DocumentationPage} from "@features/documentation/DocumentationPage";
import {ROUTES} from "./Routes";
+import {AsyncPage} from "@features/landscape/AsyncPage";
import {ProtectedRoute} from "@app/navigation/ProtectedRoute";
-import {LoginPage} from "@app/login/LoginPage";
import {ProjectFunctionHook} from "@app/navigation/ProjectFunctionHook";
-import {ProjectProvider} from "@features/integration/ProjectContext";
-import {DeveloperManager} from "@features/integration/developer/DeveloperManager";
-import ProjectPage from "@features/integration/ProjectPage";
-import {IntegrationsPage} from "@features/integrations/IntegrationsPage";
+import {ProjectProvider} from "@features/project/ProjectContext";
+import {DeveloperManager} from "@features/project/developer/DeveloperManager";
+import ProjectPage from "@features/project/ProjectPage";
+import {ProjectsPage} from "@features/projects/ProjectsPage";
+import {SharedSchemasPage} from "@features/schemas/SharedSchemasPage";
+import {DashboardPage} from "@features/dashboard/DashboardPage";
+import {OpenApiPage} from "@features/apis/OpenApiPage";
+import {LoginPage} from "@app/login/LoginPage";
+import {useReadinessStore} from "@stores/ReadinessStore";
+import {SettingsPage} from "@features/settings/SettingsPage";
export function MainRoutes() {
@@ -22,32 +44,47 @@ export function MainRoutes() {
<LoginPage/>
</ProtectedRoute>}
/>
- <Route path={ROUTES.INTEGRATIONS} element={
+ <Route path={ROUTES.PROJECTS} element={
<ProtectedRoute>
<ProjectProvider useProjectHook={ProjectFunctionHook}>
- <IntegrationsPage key="integrations"/>
+ <ProjectsPage key="integrations"/>
</ProjectProvider>
</ProtectedRoute>
}/>
- <Route path={ROUTES.INTEGRATION_DETAIL} element={
+ <Route path={ROUTES.PROJECT_DETAIL} element={
<ProtectedRoute>
<ProjectProvider useProjectHook={ProjectFunctionHook}>
<ProjectPage key="project" developerManager={<DeveloperManager/>}/>
</ProjectProvider>
</ProtectedRoute>
}/>
- <Route path={ROUTES.INTEGRATION_FILE} element={
+ <Route path={ROUTES.PROJECT_FILE} element={
<ProtectedRoute>
<ProjectProvider useProjectHook={ProjectFunctionHook}>
<ProjectPage key="project" developerManager={<DeveloperManager/>}/>
</ProjectProvider>
</ProtectedRoute>
}/>
+ <Route path={ROUTES.SETTINGS} element={
+ <ProtectedRoute>
+ <ProjectProvider useProjectHook={ProjectFunctionHook}>
+ <SettingsPage/>
+ </ProjectProvider>
+ </ProtectedRoute>
+ }/>
+ <Route path={ROUTES.SETTINGS_FILE} element={
+ <ProtectedRoute>
+ <ProjectProvider useProjectHook={ProjectFunctionHook}>
+ <SettingsPage/>
+ </ProjectProvider>
+ </ProtectedRoute>
+ }/>
<Route path={ROUTES.SYSTEM} element={<ProtectedRoute><SystemPage/></ProtectedRoute>}/>
<Route path={ROUTES.DOCUMENTATION} element={<ProtectedRoute><DocumentationPage/></ProtectedRoute>}/>
<Route path={ROUTES.ACL} element={<ProtectedRoute><AccessPage/></ProtectedRoute>}/>
<Route path={ROUTES.FORBIDDEN} element={<NotAuthorizedPage/>}/>
- <Route path="*" element={<Navigate to={ROUTES.INTEGRATIONS} replace/>}/>
+ {/*{readiness?.environment === 'dev' && <Route path="*" element={<Navigate to={ROUTES.PROJECTS} replace/>}/>}*/}
+ <Route path="*" element={<Navigate to={ROUTES.DASHBOARD} replace/>}/>
</Routes>
)
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/NavigationMenu.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/NavigationMenu.tsx
index 7d47fb8a..6ee1f728 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/NavigationMenu.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/NavigationMenu.tsx
@@ -1,9 +1,24 @@
+/*
+ * 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 {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
import React from "react";
-import {CamelIcon} from "@features/integration/designer/icons/KaravanIcons";
import {SvgNavigationIcon} from "@shared/icons/SvgNavigationIcon";
-import {KubernetesIcon} from "@features/integration/designer/icons/ComponentIcons";
-import DockerIcon from "@patternfly/react-icons/dist/esm/icons/docker-icon";
+import {KubernetesIcon} from "@features/project/designer/icons/ComponentIcons";
+import {DockerIcon} from "@patternfly/react-icons";
export class MenuItem {
pageId: string = '';
@@ -17,26 +32,33 @@ export class MenuItem {
}
}
-export function getNavigationMenu(environment: string, infrastructure: string): MenuItem[] {
+export function getNavigationFirstMenu(): MenuItem[] {
+ return [
+ new MenuItem("projects", "Projects", SvgNavigationIcon({icon: 'apps'})),
+ new MenuItem("settings", "Settings", SvgNavigationIcon({icon: 'settings'})),
+ ]
+}
+
+
+export function getNavigationSecondMenu(environment: string, infrastructure: string): MenuItem[] {
const iconInfra = infrastructure === 'kubernetes' ? KubernetesIcon("infra-icon-k8s") : <DockerIcon className='infra-icon-docker'/>;
- const pages: MenuItem[] = [
- new MenuItem("integrations", "Integrations", <CamelIcon />),
- ]
- // if (environment === 'dev') {
- // pages.push(new MenuItem("services", "Services", <ServicesIcon/>))
- // }
+ const pages: MenuItem[] = []
+
+ if (environment === 'dev') {
+ pages.push(new MenuItem("documentation", "Learn", SvgNavigationIcon({icon: 'documentation'})));
+ }
if (getCurrentUser()?.roles?.includes('platform-admin')) {
pages.push(new MenuItem("system", "System", iconInfra));
}
if (AuthApi.authType === 'session') {
- pages.push(new MenuItem("acl", "Access", SvgNavigationIcon({icon: 'access', width: 24, height: 24})));
- }
- if (environment === 'dev') {
- pages.push(new MenuItem("documentation", "Docs", SvgNavigationIcon({icon: 'documentation', width: 24, height: 24})));
+ pages.push(new MenuItem("acl", "Access", SvgNavigationIcon({icon: 'access'})));
}
+
+ pages.push(new MenuItem("logout", "Logout", SvgNavigationIcon({icon: 'logout'})));
+
return pages;
}
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/NotAuthorizedPage.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/NotAuthorizedPage.tsx
index 33e01bd9..95db9777 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/NotAuthorizedPage.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/NotAuthorizedPage.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {useEffect} from "react";
import {Bullseye, EmptyState, EmptyStateBody, EmptyStateVariant} from "@patternfly/react-core";
import NotAuthorizedIcon from "@patternfly/react-icons/dist/esm/icons/user-secret-icon";
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
index 73acddf3..a5d0ce44 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.css
@@ -1,38 +1,74 @@
+/*
+ * 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.
+ */
+
.karavan .nav-buttons {
width: fit-content;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
- background-color: var(--pf-t--color--gray--95);
+ background: var(--pf-t--color--gray--95);
}
-.karavan .nav-buttons .nav-button-part-wrapper {
+
+.karavan .nav-buttons .nav-button-part-wrapper,
+.karavan .nav-buttons .nav-button-part-darkmode {
display: flex;
flex-direction: column;
align-items: center;
- height: 64px;
position: relative;
- .logo {
- margin-left: 3px;
- width: 48px;
- height: 48px;
- }
}
.karavan .nav-buttons .environment-wrapper {
display: flex;
- flex-direction: row;
+ flex-direction: column;
justify-content: center;
align-items: center;
- margin-bottom: 6px;
- margin-top: 6px;
+ margin-bottom: 16px;
+ gap: 3px;
+ color: var(--pf-t--color--blue--10);
+ /*margin-top: 6px;*/
+
.version {
color: var(--pf-t--color--gray--30);
}
+
.environment {
- border-color: var(--pf-t--color--gray--60);
- color: var(--pf-t--color--white);
- background-color: var(--pf-t--color--gray--60);
+ padding: 0 4px 0 4px;
+ border-color: #4bb9ecff;
+ color: var(--pf-t--color--gray--95);
+ background-color: #4bb9ecff;
+ font-weight: normal;
+ }
+
+ .environment-line {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+ align-items: center;
+ }
+
+ .login-logo {
+ width: 18px;
+ height: 18px;
+ }
+
+ .icon {
+ width: 16px;
+ height: 16px;
}
}
@@ -42,33 +78,21 @@
width: 32px;
height: 32px;
}
-.karavan .nav-buttons .pf-v6-c-button {
- padding: 0;
- /*width: fit-content;*/
- height: 64px;
- /*color: var(--pf-t-global--color--light-100);*/
-}
.karavan .nav-buttons .pf-v6-c-button svg {
- width: 24px;
- height: 24px;
- /*fill: var(--pf-t--color--white);*/
+ width: 16px;
+ height: 16px;
+ fill: #4bb9ec;
}
/* Adapt navigation for screens less than 800px */
@media screen and (max-height: 800px) {
- .karavan .nav-buttons .pf-v6-c-button {
- height: 50px;
- }
- .karavan .nav-buttons .pf-v6-c-button .pf-v6-c-button__icon {
- /*display: none;*/
+ .karavan .nav-buttons .nav-button {
+ /*padding: 16px 12px 16px 12px;*/
}
- .karavan .nav-buttons .pf-v6-c-button .nav-button-badge {
- top: 2px;
- right: 2px;
- }
- .karavan .nav-buttons .pf-v6-c-button .nav-button-badge .pf-v6-c-badge {
- font-size: 10px;
+
+ .karavan .nav-buttons .pf-v6-c-button {
+ font-size: 12px;
}
}
@@ -81,26 +105,38 @@
background-color: var(--pf-t--color--gray--60);
}
-.karavan .nav-buttons .nav-button-wrapper {
- .infra-icon-docker {
- fill: #1074FF;
- }
-}
.karavan .nav-buttons .nav-button {
- border-left-width: 3px;
- border-left-style: solid;
- border-left-color: transparent;
border-top-width: 1px;
border-top-style: solid;
border-top-color: var(--pf-t--color--gray--80);
border-radius: 0;
display: flex;
- flex-direction: column;
- justify-content: center;
+ flex-direction: row;
+ justify-content: flex-start;
align-items: center;
- gap: 0;
- padding: 0 9px 0 6px;
- color: var(--pf-t--color--white);
+ gap: 4px;
+ padding: 10px 10px 10px 10px;
+ color: var(--pf-t--color--blue--10);
+ &:hover {
+ background: color-mix(in srgb, var(--pf-t--color--blue--60) 50%, transparent);
+ }
+
+ .pf-v6-c-button__text {
+
+ }
+ .nav-button-badge {
+ position: absolute;
+ top: 3px;
+ right: 3px;
+ margin: 0;
+ .pf-v6-c-badge {
+ padding: 0 6px;
+ min-width: fit-content;
+ background-color: var(--pf-t--color--orange--40);
+ color: var(--pf-t--color--gray--95);
+ font-weight: normal;
+ }
+ }
}
.karavan .nav-buttons .nav-button .pf-v6-c-button__icon.pf-m-start {
@@ -114,21 +150,41 @@
}
.karavan .nav-button-selected .pf-v6-c-button {
- border-left-color: #ec7a08;
- background-color: var(--pf-t--color--gray--60);
-}
+ background: rgba(236, 122, 8, 0.25);
+ &:hover {
+ /*background: color-mix(in srgb, var(--pf-t--color--blue--60) 50%, transparent);*/
+ }
-.karavan .nav-buttons .nav-button-badge {
- position: absolute;
- top: 5px;
- right: 5px;
- margin: 0;
+ .nav-button-badge {
+ .pf-v6-c-badge {
+ padding: 0 6px;
+ min-width: fit-content;
+ color: var(--pf-t--color--orange--40);
+ background-color: var(--pf-t--color--gray--95);
+ font-weight: 500;
+ }
+ }
+
+ &::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ border-left: 2px solid rgba(236, 122, 8, 1);
+ pointer-events: none;
+ }
}
-.karavan .nav-buttons .nav-button-badge .pf-v6-c-badge {
- padding: 0 6px;
- min-width: fit-content;
- background-color: var(--pf-t--color--orange--30);
- color: var(--pf-t--color--gray--95);
- font-weight: normal;
+.karavan .nav-buttons {
+ .dark-mode-toggle {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ width: 100%;
+ padding: 12px;
+ border-top-width: 1px;
+ border-top-style: solid;
+ border-top-color: var(--pf-t--color--gray--80);
+ border-radius: 0;
+ }
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
index db6cae62..5a1a59bf 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PageNavigation.tsx
@@ -1,8 +1,23 @@
+/*
+ * 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, {useContext, useState} from 'react';
import {Badge, Button,} from '@patternfly/react-core';
import './PageNavigation.css';
-import LogoutIcon from "@patternfly/react-icons/dist/esm/icons/door-open-icon";
-import {useAppConfigStore, useDevModeStore, useFileStore, useProjectsStore, useStatusesStore} from "@stores/ProjectStore";
+import {useAppConfigStore, useDevModeStore, useFileStore} from "@stores/ProjectStore";
import {shallow} from "zustand/shallow";
import {useLocation, useNavigate} from "react-router-dom";
import {SsoApi} from "@api/auth/SsoApi";
@@ -10,29 +25,26 @@ import {UserPopupOidc} from "../login/UserPopupOidc";
import {BUILD_IN_PROJECTS} from "@models/ProjectModels";
import DarkModeToggle from "@app/theme/DarkModeToggle";
import {AuthApi} from "@api/auth/AuthApi";
-import {getNavigationMenu} from "@app/navigation/NavigationMenu";
+import {getNavigationFirstMenu, getNavigationSecondMenu, MenuItem} from "@app/navigation/NavigationMenu";
import {AuthContext} from "@api/auth/AuthProvider";
-import {KaravanIcon} from "@features/integration/designer/icons/KaravanIcons";
+import {PlatformLogoBase64} from "@app/navigation/PlatformLogo";
+import {PlatformVersions} from "@shared/ui/PlatformLogos";
-
-export function PageNavigation() {
+function PageNavigation() {
const [config] = useAppConfigStore((s) => [s.config], shallow)
- const menu = getNavigationMenu(config.environment, config.infrastructure);
+ const firstMenu = getNavigationFirstMenu();
+ const secondMenu = getNavigationSecondMenu(config.environment, config.infrastructure);
const [setFile] = useFileStore((state) => [state.setFile], shallow)
const [setStatus, setPodName] = useDevModeStore((state) => [state.setStatus, state.setPodName], shallow)
- const [projects] = useProjectsStore((s) => [s.projects], shallow)
- const [deployments, containers] = useStatusesStore((state) => [state.deployments, state.containers], shallow)
- const [pageId, setPageId] = useState<string>(menu?.at(0)?.pageId || 'integrations');
+ const [pageId, setPageId] = useState<string>();
const navigate = useNavigate();
const location = useLocation();
const {reload} = useContext(AuthContext);
- const projectCount = projects.filter(p => !BUILD_IN_PROJECTS.includes(p.projectId))?.length;
-
React.useEffect(() => {
var page = location.pathname?.split("/").filter(Boolean)[0];
- if (page === 'integrations') {
+ if (page === 'projects') {
var projectId = location.pathname?.split("/").filter(Boolean)[1];
if (BUILD_IN_PROJECTS.includes(projectId)) {
setPageId('settings');
@@ -41,66 +53,79 @@ export function PageNavigation() {
}
} else if (page !== undefined) {
setPageId(page);
+ } else if (config.environment === 'dev') {
+ setPageId('projects');
} else {
- setPageId('integrations');
+ setPageId('projects');
}
}, [location]);
+ function onClick(page: MenuItem) {
+ if (page.pageId === 'logout') {
+ if (AuthApi.authType === 'oidc') {
+ SsoApi.logout(() => {
+ });
+ } else if (AuthApi.authType === 'session') {
+ AuthApi.logout();
+ reload();
+ }
+ } else {
+ setFile('none', undefined);
+ setPodName(undefined);
+ setStatus("none");
+ setPageId(page.pageId);
+ navigate(page.pageId);
+ }
+ }
+
+ function getMenu(menu: MenuItem[]) {
+ return (
+ menu.map((page, index) => {
+ let className = "nav-button";
+ const isSelected = pageId === page.pageId;
+ className = className.concat(isSelected ? " nav-button-selected" : "");
+ return (
+ <div key={page.pageId} className={isSelected ? "nav-button-selected nav-button-wrapper" : "nav-button-wrapper"}>
+ <Button id={page.pageId}
+ style={{width: '100%'}}
+ variant={"link"}
+ className={className}
+ // countOptions={badge}
+ onClick={_ => onClick(page)}
+ >
+ <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '8px'}}>
+ {page.icon}
+ {page.name}
+ </div>
+ </Button>
+ </div>
+ )
+ })
+ )
+ }
return (
<div className="nav-buttons pf-v6-theme-dark">
<div className='nav-button-part-wrapper'>
- {KaravanIcon()}
+ <img src={PlatformLogoBase64()} className="logo" alt='logo'/>
</div>
<div style={{alignSelf: 'center'}} className='environment-wrapper'>
+ <Badge isRead className='environment'>{config.environment}</Badge>
</div>
- {menu.map((page, index) => {
- let className = "nav-button";
- className = className.concat(pageId === page.pageId ? " nav-button-selected" : "");
- className = className.concat((index === menu.length - 1) ? " nav-button-last" : "");
- return (
- <div key={page.pageId} className={pageId === page.pageId ? "nav-button-selected nav-button-wrapper" : "nav-button-wrapper"}>
- <Button id={page.pageId}
- style={{width: '100%'}}
- icon={page.icon}
- variant={"link"}
- className={className}
- onClick={event => {
- setFile('none', undefined);
- setPodName(undefined);
- setStatus("none");
- setPageId(page.pageId);
- navigate(page.pageId);
- }}
- >
- {page.name}
- </Button>
- </div>
- )
- })}
- <div className='nav-button-part-wrapper' style={{flexGrow: '2'}}/>
+ {getMenu(firstMenu)}
+ <div style={{flex: 2}}/>
+ {getMenu(secondMenu)}
{AuthApi.authType === 'oidc' &&
<div className='nav-button-part-wrapper'>
<UserPopupOidc/>
</div>
}
-
- <div className='nav-button-part-wrapper'>
+ <div className={"dark-mode-toggle"}>
<DarkModeToggle/>
</div>
- <div className='nav-button-part-wrapper'>
- <Button icon={<LogoutIcon/>} className={"nav-button"} style={{width: '100%'}} variant={"link"}
- onClick={event => {
- if (AuthApi.authType === 'oidc') {
- SsoApi.logout(() => {
- });
- } else if (AuthApi.authType === 'session') {
- AuthApi.logout();
- reload();
- }
- }}
- >Exit</Button>
- </div>
+ <PlatformVersions/>
</div>
)
-}
\ No newline at end of file
+}
+
+export default PageNavigation
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/Routes.ts b/karavan-app/src/main/webui/src/karavan/app/navigation/Routes.ts
index 807c6ce7..c9daa3e8 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/Routes.ts
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/Routes.ts
@@ -1,10 +1,27 @@
-// routes.ts
+/*
+ * 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.
+ */
+
export const ROUTES = {
- INTEGRATIONS: "/integrations",
- INTEGRATION_DETAIL: "/integrations/:projectId",
- INTEGRATION_FILE: "/integrations/:projectId/:fileName",
- SERVICES: "/services",
+ PROJECTS: "/projects",
+ PROJECT_DETAIL: "/projects/:projectId",
+ PROJECT_FILE: "/projects/:projectId/:fileName",
SYSTEM: "/system",
+ SETTINGS: "/settings",
+ SETTINGS_FILE: "/settings/:projectId/:fileName",
DOCUMENTATION: "/documentation",
FORBIDDEN: "/403",
ACL: "/acl",
diff --git a/karavan-app/src/main/webui/src/karavan/app/theme/DarkModeToggle.tsx b/karavan-app/src/main/webui/src/karavan/app/theme/DarkModeToggle.tsx
index ea4910fd..1a50f6c6 100644
--- a/karavan-app/src/main/webui/src/karavan/app/theme/DarkModeToggle.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/theme/DarkModeToggle.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
import { SunIcon, MoonIcon } from '@patternfly/react-icons';
import { useTheme } from './ThemeContext';
diff --git a/karavan-app/src/main/webui/src/karavan/app/theme/ThemeContext.tsx b/karavan-app/src/main/webui/src/karavan/app/theme/ThemeContext.tsx
index 0eec10e9..90fb6251 100644
--- a/karavan-app/src/main/webui/src/karavan/app/theme/ThemeContext.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/theme/ThemeContext.tsx
@@ -1,4 +1,20 @@
-import React, { createContext, useContext, useEffect, useState } from 'react';
+/*
+ * 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, {createContext, useContext, useEffect, useState} from 'react';
interface ThemeContextType {
isDark: boolean;
@@ -11,22 +27,27 @@ export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ childre
const [isDark, setIsDark] = useState(false);
useEffect(() => {
- const stored = localStorage.getItem('pf-theme');
- if (stored === 'dark') {
- setIsDark(true);
- document.documentElement.classList.add('pf-v6-theme-dark');
+ const storedTheme = localStorage.getItem('pf-theme');
+
+ let shouldUseDark = false;
+
+ if (storedTheme === 'dark') {
+ shouldUseDark = true;
+ } else if (storedTheme === 'light') {
+ shouldUseDark = false;
+ } else {
+ // No stored preference → use browser preference
+ shouldUseDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
+
+ setIsDark(shouldUseDark);
+ document.documentElement.classList.toggle('pf-v6-theme-dark', shouldUseDark);
}, []);
const toggleDarkMode = (checked: boolean) => {
setIsDark(checked);
- if (checked) {
- document.documentElement.classList.add('pf-v6-theme-dark');
- localStorage.setItem('pf-theme', 'dark');
- } else {
- document.documentElement.classList.remove('pf-v6-theme-dark');
- localStorage.setItem('pf-theme', 'light');
- }
+ document.documentElement.classList.toggle('pf-v6-theme-dark', checked);
+ localStorage.setItem('pf-theme', checked ? 'dark' : 'light');
};
return (
(camel-karavan) 08/33: Front-end Stores for 4.18.0
Posted by ma...@apache.org.
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 ea21116823e896e1a1bdd9bba18cbc60668866d4
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:22:37 2026 -0500
Front-end Stores for 4.18.0
---
.../main/webui/src/karavan/stores/AccessStore.ts | 16 +++
.../webui/src/karavan/stores/DeveloperStore.ts | 14 --
.../main/webui/src/karavan/stores/ProjectStore.ts | 157 ++++++++++++---------
.../main/webui/src/karavan/stores/SearchStore.ts | 18 ++-
.../main/webui/src/karavan/stores/SystemStore.ts | 16 +++
5 files changed, 140 insertions(+), 81 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/stores/AccessStore.ts b/karavan-app/src/main/webui/src/karavan/stores/AccessStore.ts
index f92b5071..38a73db9 100644
--- a/karavan-app/src/main/webui/src/karavan/stores/AccessStore.ts
+++ b/karavan-app/src/main/webui/src/karavan/stores/AccessStore.ts
@@ -1,3 +1,19 @@
+/*
+ * 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 {createWithEqualityFn} from "zustand/traditional";
import {shallow} from "zustand/shallow";
import {AccessRole, AccessUser, PLATFORM_ADMIN, PLATFORM_DEVELOPER} from "@models/AccessModels";
diff --git a/karavan-app/src/main/webui/src/karavan/stores/DeveloperStore.ts b/karavan-app/src/main/webui/src/karavan/stores/DeveloperStore.ts
deleted file mode 100644
index 6d25ebb4..00000000
--- a/karavan-app/src/main/webui/src/karavan/stores/DeveloperStore.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import {createWithEqualityFn} from "zustand/traditional";
-import {shallow} from "zustand/shallow";
-
-interface DeveloperState {
- loading: boolean;
- setLoading: (loading: boolean) => void;
-}
-
-export const useDeveloperStore = createWithEqualityFn<DeveloperState>((set) => ({
- loading: false,
- setLoading: (loading: boolean) => {
- set({loading: loading})
- },
-}), shallow)
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/stores/ProjectStore.ts b/karavan-app/src/main/webui/src/karavan/stores/ProjectStore.ts
index d1255970..6e0edfc7 100644
--- a/karavan-app/src/main/webui/src/karavan/stores/ProjectStore.ts
+++ b/karavan-app/src/main/webui/src/karavan/stores/ProjectStore.ts
@@ -18,19 +18,21 @@ import {
AppConfig,
CamelStatus,
ContainerImage,
- ContainerStatus,
DeploymentStatus,
DesignerTab,
FileOperation,
Project,
+ ProjectCommited,
ProjectFile,
+ ProjectFileCommited,
ProjectOperation,
ServiceStatus
} from "@models/ProjectModels";
-import {ProjectEventBus} from "@bus/ProjectEventBus";
-import {unstable_batchedUpdates} from "react-dom";
import {createWithEqualityFn} from "zustand/traditional";
import {shallow} from "zustand/shallow";
+import {KaravanApi} from "@api/KaravanApi";
+import {AxiosResponse} from "axios";
+import isEqual from "lodash/isEqual";
interface AppConfigState {
loading: boolean;
@@ -84,22 +86,43 @@ export const useAppConfigStore = createWithEqualityFn<AppConfigState>((set) => (
interface ProjectsState {
projects: Project[];
+ projectsCommited: ProjectCommited[];
setProjects: (projects: Project[]) => void;
upsertProject: (project: Project) => void;
+ fetchProjects: () => Promise<void>;
+ fetchProjectsCommited: () => Promise<void>;
filter: string;
setFilter: (filter: string) => void;
labels: any;
setLabels: (labels: any) => void;
}
-export const useProjectsStore = createWithEqualityFn<ProjectsState>((set) => ({
+export const useProjectsStore = createWithEqualityFn<ProjectsState>((set, get) => ({
projects: [],
+ projectsCommited: [],
labels: {},
setProjects: (ps: Project[]) => {
set((state: ProjectsState) => ({
projects: ps,
}));
},
+ fetchProjects: async (): Promise<void> => {
+ await new Promise<Project[]>((resolve) => {
+ KaravanApi.getProjects(resolve);
+ }).then(projects => {
+ set({ projects: projects });
+ })
+ },
+ fetchProjectsCommited: async (): Promise<void> => {
+ const currentProjectsCommited = get().projectsCommited;
+ await new Promise<ProjectCommited[]>((resolve) => {
+ KaravanApi.getProjectsCommited(resolve);
+ }).then(projectsCommited => {
+ if (!isEqual(currentProjectsCommited, projectsCommited)) {
+ set({ projectsCommited: projectsCommited });
+ }
+ })
+ },
setLabels: (labels: any) => {
set({labels: labels});
},
@@ -117,8 +140,8 @@ export const useProjectsStore = createWithEqualityFn<ProjectsState>((set) => ({
}), shallow)
-export const ProjectMenus = ['topology', 'files', 'readme', 'build', 'containers'] as const;
-export const ProjectRuntimeMenus = ['JVM', 'camel', 'log'] as const;
+export const ProjectMenus = ['topology', 'source','readme', 'build', 'containers'] as const;
+export const ProjectRuntimeMenus = ['pod', 'JVM', 'camel', 'log', 'tryout'] as const;
export type ProjectMenu = typeof ProjectMenus[number];
export type ProjectRuntimeMenu = typeof ProjectRuntimeMenus[number];
@@ -135,6 +158,7 @@ interface ProjectState {
setOperation: (o: ProjectOperation) => void;
camelStatuses: CamelStatus[],
setCamelStatuses: (camelStatuses: CamelStatus[]) => void;
+ fetchCamelStatuses: (projectId: string, env: string) => Promise<void>;
camelTraces: CamelStatus[],
setCamelTraces: (camelTraces: CamelStatus[]) => void;
refreshTrace: boolean
@@ -182,6 +206,14 @@ export const useProjectStore = createWithEqualityFn<ProjectState>((set) => ({
return {camelStatuses: camelStatuses};
});
},
+ fetchCamelStatuses: async (projectId: string, env: string): Promise<void> => {
+ await new Promise<AxiosResponse<CamelStatus[]>>((resolve) => {
+ KaravanApi.getProjectCamelStatuses(projectId, env, resolve);
+ }).then(response=> {
+ const statuses = response.status === 200 ? response.data : [];
+ set({camelStatuses: statuses});
+ })
+ },
camelTraces: [],
setCamelTraces: (camelTraces: CamelStatus[]) => {
set((state: ProjectState) => {
@@ -194,26 +226,66 @@ export const useProjectStore = createWithEqualityFn<ProjectState>((set) => ({
},
}), shallow)
+
+export type FilesSideBarType = 'create' | 'upload' | 'library'
+
interface FilesState {
files: ProjectFile[];
+ commitedFiles: ProjectFileCommited[];
diff: any;
setFiles: (files: ProjectFile[]) => void;
+ fetchFiles: (projectId: string) => Promise<ProjectFile[]>;
+ fetchCommitedFiles: (projectId: string) => Promise<any>;
upsertFile: (file: ProjectFile) => void;
selectedFileNames: string[];
setSelectedFileNames: (selectedFileNames: string[]) => void;
selectFile: (filename: string) => void;
unselectFile: (filename: string) => void;
+ selector: 'files' | 'commits';
+ setSelector: (selector: 'files' | 'commits') => void;
+ showSideBar: FilesSideBarType;
+ setShowSideBar: (showSideBar: FilesSideBarType) => void;
+ title: string;
+ setTitle: (title: string) => void;
}
-export const useFilesStore = createWithEqualityFn<FilesState>((set) => ({
+export const useFilesStore = createWithEqualityFn<FilesState>((set, get) => ({
files: [],
+ commitedFiles: [],
diff: {},
selectedFileNames: [],
+ selector: 'files',
+ showSideBar: null,
+ setShowSideBar: (showSideBar: FilesSideBarType) => {
+ set({showSideBar: showSideBar});
+ },
+ title: null,
+ setTitle: (title: string) => {
+ set({ title: title });
+ },
setFiles: (files: ProjectFile[]) => {
set((state: FilesState) => ({
files: files
}));
},
+ fetchFiles: async (projectId: string): Promise<any> => {
+ return await new Promise<ProjectFile[]>((resolve) => {
+ KaravanApi.getFiles(projectId, resolve);
+ }).then(files => {
+ set({ files: files });
+ return files;
+ })
+ },
+ fetchCommitedFiles: async (projectId: string): Promise<any> => {
+ const currentCommitedFiles = get().commitedFiles;
+ await new Promise<ProjectFileCommited[]>((resolve) => {
+ KaravanApi.getCommitedFiles(projectId, resolve);
+ }).then(files => {
+ if (!isEqual(currentCommitedFiles, files)) {
+ set({ commitedFiles: files });
+ }
+ })
+ },
upsertFile: (file: ProjectFile) => {
set((state: FilesState) => ({
files: state.files.find(f => f.name === file.name) === undefined
@@ -240,6 +312,9 @@ export const useFilesStore = createWithEqualityFn<FilesState>((set) => ({
const names = [...state.selectedFileNames.filter(f => f !== filename)];
return ({selectedFileNames: names})
});
+ },
+ setSelector: (selector: 'files' | 'commits') => {
+ set({selector: selector});
}
}), shallow)
@@ -301,7 +376,6 @@ export const useDevModeStore = createWithEqualityFn<DevModeState>((set) => ({
interface StatusesState {
deployments: DeploymentStatus[];
services: ServiceStatus[];
- containers: ContainerStatus[];
camelContexts: CamelStatus[];
routes: CamelStatus[];
setRoutes: (routes: CamelStatus[]) => void;
@@ -311,14 +385,14 @@ interface StatusesState {
setProcessors: (processors: CamelStatus[]) => void;
setDeployments: (d: DeploymentStatus[]) => void;
setServices: (s: ServiceStatus[]) => void;
- setContainers: (c: ContainerStatus[]) => void;
setCamelContexts: (camelContexts: CamelStatus[]) => void;
+ camels: CamelStatus[];
+ setCamels: (c: CamelStatus[]) => void;
}
-export const useStatusesStore = createWithEqualityFn<StatusesState>((set) => ({
+export const useStatusesStore = createWithEqualityFn<StatusesState>((set, get) => ({
deployments: [],
services: [],
- containers: [],
camelContexts: [],
routes: [],
consumers: [],
@@ -333,11 +407,6 @@ export const useStatusesStore = createWithEqualityFn<StatusesState>((set) => ({
services: s,
}));
},
- setContainers: (c: ContainerStatus[]) => {
- set((state: StatusesState) => ({
- containers: c,
- }));
- },
setCamelContexts: (c: CamelStatus[]) => {
set((state: StatusesState) => ({
camelContexts: c,
@@ -354,42 +423,15 @@ export const useStatusesStore = createWithEqualityFn<StatusesState>((set) => ({
setProcessors: (processors: CamelStatus[]) => {
set({processors})
},
-}), shallow)
-
-interface LogState {
- podName?: string,
- data: string;
- setData: (data: string) => void;
- addData: (data: string) => void;
- addDataAsync: (data: string) => void;
- currentLine: number;
- setCurrentLine: (currentLine: number) => void;
-}
-
-export const useLogStore = createWithEqualityFn<LogState>((set) => ({
- podName: undefined,
- data: '',
- setData: (data: string) => {
- set({data: data})
- },
- addData: (data: string) => {
- set((state: LogState) => {
- const delimiter = state.data.endsWith('\n') ? '' : '\n';
- return ({data: state.data.concat(delimiter, data)})
- })
- },
- addDataAsync: async (data: string) => {
- set((state: LogState) => {
- const delimiter = state.data.endsWith('\n') ? '' : '\n';
- return ({data: state.data.concat(delimiter, data)})
- })
- },
- currentLine: 0,
- setCurrentLine: (currentLine: number) => {
- set((state: LogState) => ({currentLine: currentLine}))
+ camels: [],
+ setCamels: (c: CamelStatus[]) => {
+ set((state: StatusesState) => ({
+ camels: c,
+ }));
},
}), shallow)
+
interface SelectedContainerState {
selectedContainerName?: string;
setSelectedContainerName: (selectedContainerName?: string) => void;
@@ -400,20 +442,3 @@ export const useSelectedContainerStore = createWithEqualityFn<SelectedContainerS
set({selectedContainerName: selectedContainerName })
},
}), shallow)
-
-
-const sub = ProjectEventBus.onLog()?.subscribe((result: ["add" | "set", string]) => {
- if (result[0] === 'add') {
- unstable_batchedUpdates(() => {
- useLogStore.setState((state: LogState) => {
- const delimiter = state.data.endsWith('\n') ? '' : '\n';
- const newData = state.data ? state.data.concat(delimiter, result[1]) : result[1]
- return ({data: newData, currentLine: state.currentLine + 1});
- })
- })
- } else if (result[0] === 'set') {
- unstable_batchedUpdates(() => {
- useLogStore.setState({data: result[1], currentLine: 0});
- })
- }
-});
diff --git a/karavan-app/src/main/webui/src/karavan/stores/SearchStore.ts b/karavan-app/src/main/webui/src/karavan/stores/SearchStore.ts
index 14a6c0da..8e533874 100644
--- a/karavan-app/src/main/webui/src/karavan/stores/SearchStore.ts
+++ b/karavan-app/src/main/webui/src/karavan/stores/SearchStore.ts
@@ -1,6 +1,22 @@
+/*
+ * 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 {createWithEqualityFn} from "zustand/traditional";
import {shallow} from "zustand/shallow";
-import {SearchResult} from "../models/SearchModels";
+import {SearchResult} from "@models/SearchModels";
interface SearchState {
search: string;
diff --git a/karavan-app/src/main/webui/src/karavan/stores/SystemStore.ts b/karavan-app/src/main/webui/src/karavan/stores/SystemStore.ts
index bd3ea094..0b374a99 100644
--- a/karavan-app/src/main/webui/src/karavan/stores/SystemStore.ts
+++ b/karavan-app/src/main/webui/src/karavan/stores/SystemStore.ts
@@ -1,3 +1,19 @@
+/*
+ * 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 {createWithEqualityFn} from "zustand/traditional";
import {shallow} from "zustand/shallow";
import {KubernetesConfigMap, KubernetesSecret} from "@models/SystemModels";
(camel-karavan) 11/33: Front-end Shared UI for 4.18.0
Posted by ma...@apache.org.
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 20f173dc8e2a0f25e53567f8ea2484877d9ca0e3
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:25:43 2026 -0500
Front-end Shared UI for 4.18.0
---
.../main/webui/src/karavan/shared/monaco-setup.ts | 33 ++++----
.../src/karavan/shared/ui/ContainerButton.tsx | 4 +-
.../webui/src/karavan/shared/ui/MainToolbar.css | 25 ++++++
.../webui/src/karavan/shared/ui/MainToolbar.tsx | 13 ++-
.../src/karavan/shared/ui/ModalConfirmation.tsx | 29 +++++--
.../webui/src/karavan/shared/ui/PlatformLogos.css | 37 +++++++++
.../webui/src/karavan/shared/ui/PlatformLogos.tsx | 95 ++++++++++++++++++++++
.../webui/src/karavan/shared/ui/RightPanel.css | 6 +-
.../webui/src/karavan/shared/ui/RightPanel.tsx | 2 +-
.../src/karavan/shared/ui/SideBarFormWrapper.tsx | 84 +++++++++++++++++++
10 files changed, 300 insertions(+), 28 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/shared/monaco-setup.ts b/karavan-app/src/main/webui/src/karavan/shared/monaco-setup.ts
index 0b2c167c..397a93f3 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/monaco-setup.ts
+++ b/karavan-app/src/main/webui/src/karavan/shared/monaco-setup.ts
@@ -1,18 +1,23 @@
-// Core API only (no full bundle)
-import 'monaco-editor/esm/vs/editor/editor.api';
+import {loader} from '@monaco-editor/react';
+import * as monaco from 'monaco-editor';
+import {type IRange, Position, Range} from 'monaco-editor';
+import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
+import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
+import YamlWorker from 'monaco-yaml/yaml.worker.js?worker';
-// Language services
-import 'monaco-editor/esm/vs/language/json/monaco.contribution';
+self.MonacoEnvironment = {
+ getWorker(_, label) {
+ if (label === 'json') {
+ return new jsonWorker();
+ }
+ if (label === 'yaml' ) {
+ return new YamlWorker()
+ }
+ return new editorWorker();
+ },
+};
-// Basic languages you need
-import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution';
-import 'monaco-editor/esm/vs/basic-languages/java/java.contribution';
-import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution';
-import 'monaco-editor/esm/vs/basic-languages/ini/ini.contribution';
-import 'monaco-editor/esm/vs/basic-languages/markdown/markdown.contribution';
-import 'monaco-editor/esm/vs/basic-languages/xml/xml.contribution';
+loader.config({ monaco });
-import {IRange, Position, Range} from "monaco-editor/esm/vs/editor/editor.api";
-// (Optional) If you want YAML schema validation instead of just syntax:
-export {Range, Position};
+export { Range, Position };
export type { IRange };
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/ContainerButton.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/ContainerButton.tsx
index 072fcf29..608540c8 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/ContainerButton.tsx
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/ContainerButton.tsx
@@ -23,7 +23,7 @@ import {useSelectedContainerStore} from "@stores/ProjectStore";
import {ContainerStatus, ContainerType} from '@models/ProjectModels';
import DevIcon from "@patternfly/react-icons/dist/esm/icons/dev-icon";
import './ContainerButton.css'
-import {BuildIcon, LockIcon, PackageIcon, ServiceIcon, UnknownIcon} from '@patternfly/react-icons';
+import {BuildIcon, LockIcon, PackageIcon, UnknownIcon} from '@patternfly/react-icons';
interface Props {
container: ContainerStatus,
@@ -41,7 +41,6 @@ export function ContainerButton(props: Props) {
const typeIconColor = isRunning ? 'var(--pf-t--global--color--status--success--100)' : 'var(--pf-v6-c-button--m-control--Color)';
const iconMap: Record<ContainerType, ReactElement> = {
devmode: <DevIcon color={typeIconColor}/>,
- devservice: <ServiceIcon color={typeIconColor}/>,
packaged: <PackageIcon color={typeIconColor}/>,
internal: <LockIcon color={typeIconColor}/>,
build: <BuildIcon color={typeIconColor}/>,
@@ -49,7 +48,6 @@ export function ContainerButton(props: Props) {
};
const typeMap: Record<ContainerType, string> = {
devmode: 'container',
- devservice: 'devservice',
packaged: 'container',
internal: 'internal',
build: 'build',
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.css b/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.css
index a0906587..fff0a110 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.css
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.css
@@ -23,6 +23,31 @@
flex-direction: row;
justify-content: flex-start;
align-items: center;
+
+ .logo {
+ width: 32px;
+ height: 32px;
+ }
+
+ .pf-v6-c-nav {
+ .pf-v6-c-nav__item {
+ .pf-m-current {
+ position: relative;
+ background: rgba(236, 122, 8, 0.25);
+ &::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ border: 1px solid rgba(236, 122, 8, 0.66);
+ pointer-events: none;
+ }
+ }
+ }
+ .pf-v6-c-nav__link:hover {
+ background: color-mix(in srgb, var(--pf-t--color--blue--60) 50%, transparent);
+ }
+ }
}
.karavan .main-toolbar h2 {
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.tsx
index 29105e3b..0479e77c 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.tsx
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/MainToolbar.tsx
@@ -16,27 +16,32 @@
*/
import React from 'react';
-import './MainToolbar.css';
+import '@shared/ui/MainToolbar.css';
+import {useAppConfigStore} from "@stores/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {PlatformVersionWithName} from "@shared/ui/PlatformLogos";
interface Props {
title: React.ReactNode;
toolsStart?: React.ReactNode;
- tools: React.ReactNode;
+ tools?: React.ReactNode;
}
export function MainToolbar(props: Props) {
const { title, toolsStart, tools } = props;
+ const [config] = useAppConfigStore((s) => [s.config], shallow)
+ const titleSvg = config?.advanced.titleSvg ? config?.advanced.titleSvg : undefined;
return (
<div className="main-toolbar dark-toolbar">
- {title}
+ {/*{title}*/}
{toolsStart &&
<div style={{flex: 2}}>
{toolsStart}
</div>
}
- {tools}
+ {tools || PlatformVersionWithName(titleSvg)}
</div>
)
}
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/ModalConfirmation.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/ModalConfirmation.tsx
index 3f35df58..c873965b 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/ModalConfirmation.tsx
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/ModalConfirmation.tsx
@@ -6,7 +6,7 @@
* (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
+ * 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,
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import React from 'react';
+import React, {useEffect, useRef} from 'react';
import {Button, Modal, ModalBody, ModalFooter, ModalHeader} from '@patternfly/react-core';
export interface ModalConfirmationProps {
@@ -34,9 +34,23 @@ export interface ModalConfirmationProps {
export function ModalConfirmation(props: ModalConfirmationProps) {
const {title, isOpen, message, onConfirm, onCancel, btnConfirm, btnCancel, btnConfirmVariant, btnCancelVariant, variant} = props;
+
+ // 1. Create a ref for the button
+ const confirmBtnRef = useRef<HTMLButtonElement>(null);
+
+ // 2. Focus the button when the modal opens
+ useEffect(() => {
+ if (isOpen) {
+ // A small timeout ensures the modal DOM is ready before focusing
+ const timer = setTimeout(() => {
+ confirmBtnRef.current?.focus();
+ }, 100);
+ return () => clearTimeout(timer);
+ }
+ }, [isOpen]);
+
return (
<Modal
- // className="modal-confirm"
variant={variant ?? "small"}
isOpen={isOpen}
onClose={() => onCancel()}
@@ -46,7 +60,12 @@ export function ModalConfirmation(props: ModalConfirmationProps) {
{message}
</ModalBody>
<ModalFooter>
- <Button key="confirm" variant={btnConfirmVariant || 'primary'} onClick={event => onConfirm()}>
+ <Button
+ ref={confirmBtnRef} // 3. Attach the ref here
+ key="confirm"
+ variant={btnConfirmVariant || 'primary'}
+ onClick={event => onConfirm()}
+ >
{btnConfirm || 'Confirm'}
</Button>
<Button key="cancel" variant={btnCancelVariant || 'secondary'} onClick={e => onCancel()}>
@@ -55,4 +74,4 @@ export function ModalConfirmation(props: ModalConfirmationProps) {
</ModalFooter>
</Modal>
)
-}
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.css b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.css
new file mode 100644
index 00000000..9c38a052
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.css
@@ -0,0 +1,37 @@
+.platform-versions {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ align-items: center;
+
+ .pf-v6-c-label {
+ padding: 4px;
+ }
+}
+
+.platform-versions {
+
+}
+
+.platform-versions-item {
+ display: flex;
+ flex-direction: row;
+ gap: 3px;
+ align-items: center;
+
+ .platform-version {
+ font-size: var(--pf-t--global--font--size--body--sm);
+ line-height: var(--pf-t--global--font--size--body--sm);
+ color: var(--pf-t--color--gray--30);
+ }
+
+ .platform-small-logo {
+ width: 12px;
+ height: 12px;
+ }
+
+ .icon {
+ width: 12px;
+ height: 12px;
+ }
+}
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
new file mode 100644
index 00000000..b6805abe
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/PlatformLogos.tsx
@@ -0,0 +1,95 @@
+import React from "react";
+import {Badge, Label} from "@patternfly/react-core";
+import PlatformLogo from "@app/navigation/PlatformLogo";
+import './PlatformLogos.css'
+
+export const KARAVAN_PLATFORM_VERSION = "4.18.0";
+
+interface PlatformVersionProps {
+ environment: string
+ short?: boolean
+}
+
+export function PlatformVersion(props: PlatformVersionProps) {
+ const {environment, short} = props;
+ const full = short !== true;
+ const badgeClassName = environment === 'dev' ? 'environment-dev'
+ : (environment === 'prod' ? 'environment-prod' : 'var(environment-default)');
+
+ return (
+ <div className="platform-versions">
+ <Label variant='outline' color='blue'>
+ <div className='platform-versions-item'>
+ {full && PlatformLogo("platform-small-logo")}
+ <p className='platform-version'>{KARAVAN_PLATFORM_VERSION}</p>
+ <Badge className={badgeClassName}>{environment || ''}</Badge>
+ </div>
+ </Label>
+ </div>
+ )
+}
+
+export function PlatformVersions() {
+ return (
+ <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'center', alignItems: "center", gap: 6, paddingBottom: 6}}>
+ <div className='platform-versions-item'>
+ {PlatformLogo("platform-small-logo")}
+ <p style={{fontSize: '12px', color: 'var(--pf-t--color--gray--30)'}}>{KARAVAN_PLATFORM_VERSION}</p>
+ </div>
+ </div>
+ )
+}
+
+export function PlatformVersionWithName() {
+ const brand = (
+ <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8}}>
+ <div>
+ {PlatformName(20)}
+ </div>
+ </div>
+ )
+
+ return (<div style={{
+ padding: '0',
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'end',
+ }}>
+ {brand}
+ </div>)
+}
+
+export function PlatformNameForToolbar() {
+ return (<div style={{
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ gap: '3px',
+ }}>
+ {PlatformName()}
+ </div>)
+}
+
+export const PlatformName = (height: number | string = 20, width: number | string = 292.797) => (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width={width}
+ height={height}
+ preserveAspectRatio="xMidYMid"
+ viewBox="0 0 292 20"
+ >
+ <path
+ d="M44.653 161.954V26.52H0V3.287h114.694V26.52H70.04v135.434Zm68.34 0L174.647 3.287h27.54l63.24 158.667h-28.673l-14.62-37.853h-67.207l-14.054 37.853zm48.507-59.727h53.834l-27.427-69.133Zm126.934 59.727V3.287h25.386v135.32h69.134v23.347zm123.307 0V3.287h25.386v158.667Zm118.433 3.4q-16.433 0-32.186-4.647-15.64-4.76-26.407-13.6l12.467-19.38q5.666 4.874 13.146 8.387 7.594 3.513 16.094 5.44 8.5 1.813 17 1.813 15.526 0 25.046-5.893 9.634-5.893 9.634-17.227 0-8.5-6.574-14.393-6.46-5 [...]
+ aria-label="KARAVAN"
+ style={{
+ fill: "#06c",
+ strokeWidth: 5.3487,
+ }}
+ transform="scale(.12095)"
+ />
+ </svg>
+)
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.css b/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.css
index e97f422c..c870c98b 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.css
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.css
@@ -5,7 +5,7 @@
flex-direction: column;
justify-content: stretch;
overflow: hidden;
- background-color: var(--pf-t--color--gray--95);
+ background: var(--pf-t--color--gray--95);
}
.karavan .right-panel .right-panel-top {
height: 64px; /* or whatever fixed height you want */
@@ -21,6 +21,10 @@
border-top-left-radius: var(--pf-t--global--border--radius--300);
}
+.pf-v6-theme-dark .karavan .right-panel .right-panel-wrapper {
+ background: var(--pf-t--color--gray--90);
+}
+
.karavan .right-panel .right-panel-wrapper .right-panel-card {
height: 100%;
display: flex;
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.tsx
index d6805fc8..5b8c4157 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.tsx
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/RightPanel.tsx
@@ -6,7 +6,7 @@ import {ErrorBoundaryWrapper} from "@shared/ui/ErrorBoundaryWrapper";
interface Props {
title: React.ReactNode;
toolsStart?: React.ReactNode;
- tools: React.ReactNode;
+ tools?: React.ReactNode;
mainPanel: React.ReactNode;
}
diff --git a/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx b/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx
new file mode 100644
index 00000000..257610a3
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/shared/ui/SideBarFormWrapper.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import {Button, Form} from "@patternfly/react-core";
+import {UseFormReturn} from "react-hook-form";
+
+interface AsyncFormWrapperProps {
+ children: React.ReactNode;
+ formContext: UseFormReturn<any>; // Accepts any form context
+ selectedId: string | null;
+ onSave?: (data: any) => void;
+ onCancel?: () => void;
+ onDelete?: () => void;
+ showDelete?: boolean;
+ isSubmitDisabled?: boolean;
+ footer?: React.ReactNode;
+}
+
+export function SideBarFormWrapper({
+ children,
+ formContext,
+ selectedId,
+ onSave,
+ onCancel,
+ onDelete,
+ showDelete = false,
+ isSubmitDisabled = false,
+ footer
+ }: AsyncFormWrapperProps) {
+
+ const {formState: {errors}, handleSubmit, getValues} = formContext;
+
+ function onKeyDown(event: React.KeyboardEvent<HTMLFormElement>): void {
+ event.stopPropagation();
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ handleSubmit(onSave)();
+ }
+ }
+
+ // Common Footer Logic
+ function getFooter() {
+ const isDisabled = Object.getOwnPropertyNames(errors).length > 0 || isSubmitDisabled;
+ return (
+ <div style={{display: "flex", flexDirection: "row", gap: 8, justifyContent: "space-between", marginTop: 16}}>
+ <div style={{flexGrow: 1}}>
+ {showDelete &&
+ <Button
+ key="delete"
+ variant={"danger"}
+ isDanger
+ isDisabled={isDisabled}
+ onClick={onDelete}
+ >
+ Delete
+ </Button>
+ }
+ </div>
+ <Button
+ key="confirm"
+ variant={"primary"}
+ isDisabled={isDisabled}
+ onClick={handleSubmit(onSave)}
+ >
+ Save
+ </Button>
+ <Button
+ key="cancel"
+ variant="link" // Standardized to "link" or "secondary" as you prefer
+ onClick={onCancel}
+ >
+ Cancel
+ </Button>
+ </div>
+ )
+ }
+
+ return (
+ <Form isHorizontal={true} autoComplete="off" noValidate onKeyDown={onKeyDown}>
+ <div style={{display: "flex", flexDirection: "column", gap: 16}}>
+ {children}
+ </div>
+ {footer || getFooter()}
+ </Form>
+ );
+}
\ No newline at end of file
(camel-karavan) 17/33: Front-end Fix for 4.18.0
Posted by ma...@apache.org.
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 c8490c42366248a094f99f183c3566ab4c6fecb0
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 17:23:22 2026 -0500
Front-end Fix for 4.18.0
---
karavan-app/src/main/webui/public/logo.svg | 178 +++++++++++++++++++++
.../src/main/webui/public/silent-check-sso.html | 8 +
.../src/main/webui/src/karavan/api/AccessApi.tsx | 16 ++
.../src/main/webui/src/karavan/api/KaravanApi.tsx | 12 --
.../webui/src/karavan/app/login/OrbitLines.tsx | 68 ++++++++
.../src/karavan/app/navigation/MainRoutes.tsx | 7 +-
.../src/karavan/app/navigation/PlatformLogo.tsx | 28 ++++
.../karavan/app/navigation/ProjectFunctionHook.tsx | 124 +++++++++++---
8 files changed, 399 insertions(+), 42 deletions(-)
diff --git a/karavan-app/src/main/webui/public/logo.svg b/karavan-app/src/main/webui/public/logo.svg
new file mode 100644
index 00000000..4452ba66
--- /dev/null
+++ b/karavan-app/src/main/webui/public/logo.svg
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="360.13885"
+ height="360.13885"
+ viewBox="0 0 360.13885 360.13885"
+ version="1.1"
+ preserveAspectRatio="xMidYMid"
+ id="svg50"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg">
+ <defs
+ id="defs31">
+ <linearGradient
+ id="linearGradient1351">
+ <stop
+ style="stop-color:#dcffff;stop-opacity:1"
+ offset="0"
+ id="stop1347" />
+ <stop
+ style="stop-color:#96d2e6;stop-opacity:1"
+ offset="1"
+ id="stop1349" />
+ </linearGradient>
+ <circle
+ id="path-1"
+ cx="128"
+ cy="128.00015"
+ r="128" />
+ <linearGradient
+ x1="-26.051073"
+ y1="271.33054"
+ x2="254.31573"
+ y2="0.047514945"
+ id="linearGradient-3"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ stop-color="#F69923"
+ offset="0%"
+ id="stop10"
+ style="stop-color:#4790bb;stop-opacity:1" />
+ <stop
+ stop-color="#F79A23"
+ offset="10.996%"
+ id="stop12"
+ style="stop-color:#64b7db;stop-opacity:1" />
+ <stop
+ stop-color="#E97826"
+ offset="94.502%"
+ id="stop14"
+ style="stop-color:#326ea0;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ x1="-32.163429"
+ y1="277.02905"
+ x2="259.33835"
+ y2="-5.0281582"
+ id="linearGradient-4"
+ gradientUnits="userSpaceOnUse">
+ <stop
+ stop-color="#F69923"
+ offset="0%"
+ id="stop17" />
+ <stop
+ stop-color="#F79A23"
+ offset="8.0478%"
+ id="stop19" />
+ <stop
+ stop-color="#E97826"
+ offset="41.874%"
+ id="stop21" />
+ </linearGradient>
+ <linearGradient
+ x1="217.94496"
+ y1="67.504837"
+ x2="99.458817"
+ y2="247.00549"
+ id="linearGradient-5"
+ gradientTransform="scale(0.96441978,1.0368929)"
+ gradientUnits="userSpaceOnUse"
+ xlink:href="#linearGradient-4">
+ <stop
+ stop-color="#F6E423"
+ offset="0%"
+ id="stop24"
+ style="stop-color:#92d6d5;stop-opacity:1" />
+ <stop
+ stop-color="#F79A23"
+ offset="41.191%"
+ id="stop26"
+ style="stop-color:#79b7cc;stop-opacity:1" />
+ <stop
+ stop-color="#E97826"
+ offset="73.271%"
+ id="stop28"
+ style="stop-color:#5891c5;stop-opacity:1" />
+ </linearGradient>
+ <mask
+ id="mask-2"
+ fill="#ffffff">
+ <use
+ xlink:href="#path-1"
+ id="use33"
+ x="0"
+ y="0"
+ width="100%"
+ height="100%" />
+ </mask>
+ <mask
+ id="mask-2-7"
+ fill="#ffffff">
+ <use
+ xlink:href="#path-1"
+ id="use137"
+ x="0"
+ y="0"
+ width="100%"
+ height="100%" />
+ </mask>
+ <linearGradient
+ xlink:href="#linearGradient1351"
+ id="linearGradient1345"
+ x1="233.12198"
+ y1="56.01545"
+ x2="2.2396212"
+ y2="242.78015"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <g
+ id="g36"
+ transform="translate(45.104634,56.041665)" />
+ <circle
+ fill="url(#linearGradient-3)"
+ fill-rule="nonzero"
+ mask="url(#mask-2)"
+ cx="127.99429"
+ cy="127.99429"
+ r="123.11053"
+ id="circle38"
+ style="fill:url(#linearGradient-3)"
+ transform="translate(45.104634,56.041665)" />
+ <g
+ id="g2266"
+ transform="translate(45.104634,56.041665)">
+ <path
+ d="m 98.043695,75.516752 c -1.750682,-0.002 -3.524167,0.0098 -5.292059,0.06144 -2.05519,0.06065 -4.816316,0.713182 -7.999625,1.784532 53.775199,40.834016 73.108199,114.497516 39.875049,178.514206 1.12865,0.0293 2.24876,0.12307 3.38456,0.12307 60.7361,0 111.49261,-42.32269 124.60904,-99.07129 C 214.07872,111.75077 161.80794,75.61511 98.043301,75.516654 Z"
+ fill="url(#linearGradient-5)"
+ fill-rule="nonzero"
+ opacity="0.75"
+ mask="url(#mask-2)"
+ id="path42"
+ style="fill:url(#linearGradient-5);fill-opacity:1" />
+ </g>
+ <path
+ d="M 84.752011,77.367742 C 66.89547,83.377158 32.82977,104.54579 0.07906091,132.8108 2.5662796,200.14549 57.107277,254.12351 124.62706,255.88195 157.86021,191.86526 138.528,118.20176 84.752011,77.367742 Z"
+ fill="#28170b"
+ fill-rule="nonzero"
+ opacity="0.75"
+ mask="url(#mask-2)"
+ id="path44"
+ style="fill:#1e4b7b;fill-opacity:1"
+ transform="translate(45.104634,56.041665)" />
+ <path
+ d="m 128.74719,54.004528 c -10.98485,5.495372 0,27.466068 0,27.466068 -32.973011,27.483724 -25.9672,74.429124 -64.435392,74.429124 -20.970343,0 -42.242226,-24.0768 -64.23273709,-38.82804 -0.28309669,3.47897 -0.78535974,6.97247 -0.78535974,10.52442 0,48.09504 26.26287383,89.92436 65.41967783,111.89721 10.952683,-1.3796 22.838636,-4.11444 31.050991,-9.59255 43.14527,-28.76482 53.85703,-83.49096 71.48633,-109.92509 10.97897,-16.492 62.43429,-15.06102 65.90679,-22.01013 5.50126,-10 [...]
+ fill="#ffffff"
+ fill-rule="nonzero"
+ mask="url(#mask-2-7)"
+ id="path150"
+ transform="translate(44.335601,55.908568)"
+ style="fill:url(#linearGradient1345);fill-opacity:1" />
+ <path
+ d="M 128,256 C 57.307552,256 0,198.69245 0,128 0,57.307552 57.307552,0 128,0 c 70.69245,0 128,57.307552 128,128 0,70.69245 -57.30755,128 -128,128 z m 0,-9.76795 C 193.29776,246.23205 246.23205,193.29776 246.23205,128 246.23205,62.702243 193.29776,9.7679529 128,9.7679529 62.702243,9.7679529 9.7679529,62.702243 9.7679529,128 9.7679529,193.29776 62.702243,246.23205 128,246.23205 Z"
+ fill="url(#linearGradient-4)"
+ fill-rule="nonzero"
+ mask="url(#mask-2)"
+ id="path40"
+ style="fill:#2d4150;fill-opacity:1"
+ transform="matrix(1.020345,0,0,1.020345,41.979634,53.958328)" />
+</svg>
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/public/silent-check-sso.html b/karavan-app/src/main/webui/public/silent-check-sso.html
new file mode 100644
index 00000000..f1156265
--- /dev/null
+++ b/karavan-app/src/main/webui/public/silent-check-sso.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+<body>
+<script>
+ parent.postMessage(location.href, location.origin);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx b/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
index dbc1dd71..e6cd1812 100644
--- a/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/AccessApi.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 axios, {AxiosResponse} from "axios";
import {AccessPassword, AccessRole, AccessUser} from "../models/AccessModels";
import {ErrorEventBus} from "@bus/ErrorEventBus";
diff --git a/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx b/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
index 845c33c5..1d7c437e 100644
--- a/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/karavan/api/KaravanApi.tsx
@@ -34,7 +34,6 @@ import {Buffer} from 'buffer';
import {EventBus} from "@features/project/designer/utils/EventBus";
import {ErrorEventBus} from "@bus/ErrorEventBus";
import {AuthApi, getCurrentUser} from "@api/auth/AuthApi";
-import {ProjectFolderCommit} from "@stores/CommitsStore";
const instance = AuthApi.getInstance();
@@ -213,17 +212,6 @@ export class KaravanApi {
});
}
- static async getProjectCommits(projectId: string, after: (commits: ProjectFolderCommit[]) => void) {
- instance.get(`/ui/git/commits/${projectId}`)
- .then(res => {
- if (res.status === 200) {
- after(res.data);
- }
- }).catch(err => {
- ErrorEventBus.sendApiError(err);
- });
- }
-
static async loadProjectCommits(projectId: string, after: (res: any) => void) {
instance.post(`/ui/git/commits/${projectId}`)
.then(res => {
diff --git a/karavan-app/src/main/webui/src/karavan/app/login/OrbitLines.tsx b/karavan-app/src/main/webui/src/karavan/app/login/OrbitLines.tsx
new file mode 100644
index 00000000..544466a1
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/app/login/OrbitLines.tsx
@@ -0,0 +1,68 @@
+/*
+ * 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';
+
+const OrbitLines = () => {
+ return (
+ <svg
+ className="orbit-lines-svg"
+ viewBox="0 0 400 400"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <defs>
+ {/* The Magic Gradient: Orange to Transparent to Blue */}
+ <linearGradient id="orbit-grad" x1="0%" y1="0%" x2="100%" y2="100%">
+ <stop offset="0%" stopColor="#ec7a08" stopOpacity="1" />
+ <stop offset="50%" stopColor="#f97316" stopOpacity="0.5" />
+ <stop offset="100%" stopColor="#0066cc" stopOpacity="1" />
+ </linearGradient>
+
+ {/* The Glow Effect */}
+ <filter id="glow">
+ <feGaussianBlur stdDeviation="2.5" result="coloredBlur" />
+ <feMerge>
+ <feMergeNode in="coloredBlur" />
+ <feMergeNode in="SourceGraphic" />
+ </feMerge>
+ </filter>
+ </defs>
+
+ {/* Outer Ring (Matches your icon radius of 150px) */}
+ <circle
+ cx="200" cy="200" r="170"
+ fill="none"
+ stroke="url(#orbit-grad)"
+ strokeWidth="2"
+ filter="url(#glow)"
+ opacity="1"
+ />
+
+ {/* Inner Decorative Ring (Smaller, thinner) */}
+ <circle
+ cx="200" cy="200" r="130"
+ fill="none"
+ stroke="url(#orbit-grad)"
+ strokeWidth="1"
+ strokeDasharray="10 10" /* Makes it dashed/techy */
+ filter="url(#glow)"
+ opacity="0.5"
+ />
+ </svg>
+ );
+};
+
+export default OrbitLines;
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
index 799d4293..504a2a7d 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/MainRoutes.tsx
@@ -21,18 +21,13 @@ import {SystemPage} from "@features/system/SystemPage";
import {AccessPage} from "@features/access/AccessPage";
import {DocumentationPage} from "@features/documentation/DocumentationPage";
import {ROUTES} from "./Routes";
-import {AsyncPage} from "@features/landscape/AsyncPage";
import {ProtectedRoute} from "@app/navigation/ProtectedRoute";
import {ProjectFunctionHook} from "@app/navigation/ProjectFunctionHook";
import {ProjectProvider} from "@features/project/ProjectContext";
import {DeveloperManager} from "@features/project/developer/DeveloperManager";
import ProjectPage from "@features/project/ProjectPage";
import {ProjectsPage} from "@features/projects/ProjectsPage";
-import {SharedSchemasPage} from "@features/schemas/SharedSchemasPage";
-import {DashboardPage} from "@features/dashboard/DashboardPage";
-import {OpenApiPage} from "@features/apis/OpenApiPage";
import {LoginPage} from "@app/login/LoginPage";
-import {useReadinessStore} from "@stores/ReadinessStore";
import {SettingsPage} from "@features/settings/SettingsPage";
export function MainRoutes() {
@@ -84,7 +79,7 @@ export function MainRoutes() {
<Route path={ROUTES.ACL} element={<ProtectedRoute><AccessPage/></ProtectedRoute>}/>
<Route path={ROUTES.FORBIDDEN} element={<NotAuthorizedPage/>}/>
{/*{readiness?.environment === 'dev' && <Route path="*" element={<Navigate to={ROUTES.PROJECTS} replace/>}/>}*/}
- <Route path="*" element={<Navigate to={ROUTES.DASHBOARD} replace/>}/>
+ <Route path="*" element={<Navigate to={ROUTES.PROJECTS} replace/>}/>
</Routes>
)
}
\ No newline at end of file
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
new file mode 100644
index 00000000..3a116817
--- /dev/null
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/PlatformLogo.tsx
@@ -0,0 +1,28 @@
+/*
+ * 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 {KaravanIcon} from "@features/project/designer/icons/KaravanIcons";
+
+export function PlatformLogoBase64() {
+
+ return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgICAgICB3aWR0aD0iMzYwLjEzODg1IgogICAgICAgIGhlaWdodD0iMzYwLjEzODg1IgogICAgICAgIHZpZXdCb3g9IjAgMCAzNjAuMTM4ODUgMzYwLjEzODg1IgogICAgICAgIHZlcnNpb249IjEuMSIKICAgICAgICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCIKICAgICAgICBpZD0ic3ZnNTAiCiAgICAgICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgICAgICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogIC [...]
+}
+
+export function PlatformLogo(classNames?: string) {
+ return KaravanIcon()
+}
+
+export default PlatformLogo;
diff --git a/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx b/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
index 7759312b..5e2d14c4 100644
--- a/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
+++ b/karavan-app/src/main/webui/src/karavan/app/navigation/ProjectFunctionHook.tsx
@@ -1,20 +1,39 @@
-import {EventBus} from "@features/integration/designer/utils/EventBus";
+/*
+ * 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 {EventBus} from "@features/project/designer/utils/EventBus";
import {ProjectFile} from "@models/ProjectModels";
-import {DslMetaModel} from "@features/integration/designer/utils/DslMetaModel";
+import {DslMetaModel} from "@features/project/designer/utils/DslMetaModel";
import {v4 as uuidv4} from "uuid";
-import {CamelUi} from "@features/integration/designer/utils/CamelUi";
+import {CamelUi} from "@features/project/designer/utils/CamelUi";
import {KaravanApi} from "@api/KaravanApi";
import {Integration} from "@karavan-core/model/IntegrationDefinition";
-import {ASYNCAPI_FILE_NAME_JSON, FILE_WORDS_SEPARATOR, KARAVAN_DOT_EXTENSION, KARAVAN_FILENAME, OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
-import {FromDefinition, RouteConfigurationDefinition} from "@karavan-core/model/CamelDefinition";
+import {FILE_WORDS_SEPARATOR, KARAVAN_DOT_EXTENSION, KARAVAN_FILENAME, OPENAPI_FILE_NAME_JSON} from "@karavan-core/contants";
+import {RouteConfigurationDefinition} from "@karavan-core/model/CamelDefinition";
import {CamelDefinitionApiExt} from "@karavan-core/api/CamelDefinitionApiExt";
import {CamelDefinitionYaml} from "@karavan-core/api/CamelDefinitionYaml";
import {CamelDefinitionApi} from "@karavan-core/api/CamelDefinitionApi";
-import {useDesignerStore, useSelectorStore} from "@features/integration/designer/DesignerStore";
+import {useDesignerStore, useSelectorStore} from "@features/project/designer/DesignerStore";
import {shallow} from "zustand/shallow";
import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore, useWizardStore} from "@stores/ProjectStore";
-import {toSpecialRouteId} from "@features/integration/designer/utils/ValidatorUtils";
+import {toSpecialRouteId} from "@features/project/designer/utils/ValidatorUtils";
import {ProjectService} from "@services/ProjectService";
+import {useTemplatesStore} from "@stores/SettingsStore";
+import {useContainerStatusesStore} from "@stores/ContainerStatusesStore";
export function ProjectFunctionHook() {
@@ -24,8 +43,10 @@ export function ProjectFunctionHook() {
const [setFile] = useFileStore((s) => [s.setFile], shallow);
const [setShowWizard] = useWizardStore((s) => [s.setShowWizard], shallow)
const [setDesignerSwitch] = useDesignerStore((s) => [s.setDesignerSwitch], shallow)
- const [project, tabIndex, setTabIndex, refreshTrace] =
- useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex, s.refreshTrace], shallow);
+ const [project, tabIndex, setTabIndex, refreshTrace, fetchCamelStatuses] =
+ useProjectStore((s) => [s.project, s.tabIndex, s.setTabIndex, s.refreshTrace, s.fetchCamelStatuses], shallow);
+ const {fetchTemplateFiles} = useTemplatesStore();
+ const { fetchContainers } = useContainerStatusesStore();
function createRouteConfiguration() {
const integration = Integration.createNew(KARAVAN_FILENAME.ROUTE_CONFIGURATION);
@@ -60,11 +81,14 @@ export function ProjectFunctionHook() {
const integration = Integration.createNew(fName);
let i;
if (isRouteTemplate) {
- const route = CamelDefinitionApi.createRouteDefinition({
- from: new FromDefinition({uri: dsl.uri}),
- nodePrefixId: `route${FILE_WORDS_SEPARATOR}${fullUri}`
- });
- const routeTemplate = CamelDefinitionApi.createRouteTemplateDefinition({route: route});
+ const keys = dsl.properties ? Object.keys(dsl.properties) : [];
+ const key = keys.at(0);
+ const routeId = dsl.properties?.[key] + "Route";
+ const templateId = dsl.properties?.[key] + "RouteTemplate";
+ const route = CamelUi.createRouteFromComponent(dsl.uri, dsl.properties, '');
+ route.id = routeId
+ route.nodePrefixId = routeId
+ const routeTemplate = CamelDefinitionApi.createRouteTemplateDefinition({id: templateId, route: route});
i = CamelDefinitionApiExt.addRouteTemplateToIntegration(integration, routeTemplate);
} else {
i = CamelDefinitionApiExt.addStepToIntegration(integration, route, '');
@@ -168,19 +192,71 @@ export function ProjectFunctionHook() {
})
}
- function isOpenApiExists(): boolean {
- const openApiFile = files.filter(f => f.name === OPENAPI_FILE_NAME_JSON)?.at(0);
- return openApiFile !== undefined
+ async function saveFiles(projectId: string, filesToSave: ProjectFile[], afterSuccess?: () => void) {
+
+ // 1. Fetch all existing files for the project once
+ KaravanApi.getFiles(projectId, async (existingFiles: ProjectFile[]) => {
+ const existingNames = new Set(existingFiles.map(f => f.name));
+
+ // 2. Map each file to a Promise (Update if exists, Create if not)
+ const savePromises = filesToSave.map(file => {
+ return new Promise<boolean>((resolve) => {
+ const alreadyExists = existingNames.has(file.name);
+
+ if (alreadyExists) {
+ KaravanApi.putProjectFile(file, (result) => resolve(!!result));
+ } else {
+ KaravanApi.saveProjectFile(file, (result) => resolve(!!result));
+ }
+ });
+ });
+
+ try {
+ // 3. Wait for all individual save/put operations to finish
+ const results = await Promise.all(savePromises);
+ const allSuccessful = results.every(res => res === true);
+
+ // 4. Final actions after all operations complete
+ if (allSuccessful) {
+ afterSuccess?.();
+ EventBus.sendAlert("Success", `All ${filesToSave.length} files processed`, "success");
+ } else {
+ const failCount = results.filter(r => !r).length;
+ EventBus.sendAlert("Warning", `${failCount} files failed to save`, "danger");
+ }
+ } catch (error) {
+ EventBus.sendAlert("Error", "A critical error occurred during the batch save", "danger");
+ }
+ });
}
- function isAsyncApiExists(): boolean {
- const asyncApiFile = files.filter(f => f.name === ASYNCAPI_FILE_NAME_JSON)?.at(0);
- return asyncApiFile !== undefined
+ function saveFile(file: ProjectFile, afterSuccess?: () => void) {
+ KaravanApi.getProjectFilesByName(file.projectId, file.name, found => {
+ if (found) {
+ KaravanApi.putProjectFile(file, (result) => {
+ if (result) {
+ afterSuccess?.();
+ EventBus.sendAlert("Success", `File ${file.name} successfully updated`, "success");
+ } else {
+ EventBus.sendAlert("Error updating file", file.name, "danger");
+ }
+ })
+ } else {
+ KaravanApi.saveProjectFile(file, (result, fileRes) => {
+ if (result) {
+ afterSuccess?.();
+ EventBus.sendAlert("Success", `File ${file.name} successfully created`, "success");
+ } else {
+ EventBus.sendAlert("Error creating file", fileRes?.response?.data, "danger");
+ }
+ })
+ }
+ })
}
function refreshData() {
- ProjectService.refreshAllContainerStatuses();
- ProjectService.refreshCamelStatus(project.projectId, config.environment);
+ fetchCamelStatuses(project.projectId, config.environment);
+ fetchContainers();
if (tabIndex === "build") {
ProjectService.refreshAllDeploymentStatuses();
ProjectService.refreshImages(project.projectId);
@@ -191,9 +267,9 @@ export function ProjectFunctionHook() {
}
function refreshSharedData() {
-
+ fetchTemplateFiles();
}
return {createNewRouteFile, createOpenApiRestFile, createNewBean, createNewKamelet, createRouteConfiguration, refreshSharedData,
- createAsyncApi, isOpenApiExists, createNewRestFile, refreshData, isAsyncApiExists, createOpenApi, project}
+ project, createNewRestFile, refreshData, createAsyncApi, createOpenApi}
}
(camel-karavan) 12/33: Front-end Poller for 4.18.0
Posted by ma...@apache.org.
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 2c4df962daeb9438bc8ea73d9ff5d359741afd0c
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Feb 27 16:25:57 2026 -0500
Front-end Poller for 4.18.0
---
.../src/karavan/shared/polling/useDataPolling.ts | 48 ++++++++++++----------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/karavan-app/src/main/webui/src/karavan/shared/polling/useDataPolling.ts b/karavan-app/src/main/webui/src/karavan/shared/polling/useDataPolling.ts
index a1502ee5..fc868018 100644
--- a/karavan-app/src/main/webui/src/karavan/shared/polling/useDataPolling.ts
+++ b/karavan-app/src/main/webui/src/karavan/shared/polling/useDataPolling.ts
@@ -1,34 +1,40 @@
-// useDataPolling.ts
+import {useEffect, useMemo, useRef} from "react";
+import {startPolling, stopPolling} from "./PollingManager";
-import {useCallback, useEffect, useMemo} from 'react';
-import {startPolling, stopPolling} from './PollingManager'; // Assuming PollingManager has been implemented
-
-/**
- * Custom hook to manage periodic data fetching with a DYNAMIC interval.
- * @param pollingKey A unique string identifier (e.g., 'metrics').
- * @param fetchAction The function that performs the data fetch.
- * @param interval The current polling interval in milliseconds (can change).
- */
export const useDataPolling = (
pollingKey: string,
fetchAction: () => void,
- interval: number
+ interval: number,
+ dependencies: any[] = []
): void => {
-
- // The polling ID remains constant, based only on the key.
const pollingId = useMemo(() => pollingKey, [pollingKey]);
- const stableFetchAction = useCallback(fetchAction, [fetchAction]);
+ // 1. Store the fetchAction in a mutable ref.
+ // This allows the timer to always call the latest version of the action
+ // without being listed as a dependency in the useEffect below.
+ const fetchRef = useRef(fetchAction);
+
+ // 2. Update the ref every time the component renders with a new fetchAction.
+ useEffect(() => {
+ fetchRef.current = fetchAction;
+ }, [fetchAction]);
+
+ // 3. Manage the PollingManager lifecycle.
useEffect(() => {
- // Start polling (or restart if interval has changed)
- startPolling(pollingId, stableFetchAction, interval);
+ // We create a wrapper that points to the current ref value.
+ // This wrapper is what the PollingManager's setInterval will execute.
+ const timerRunner = () => {
+ fetchRef.current();
+ };
- // Cleanup: Runs when the component unmounts OR if dependencies change.
+ // Start (or increment reference count)
+ startPolling(pollingId, timerRunner, interval);
+
+ // Stop (or decrement reference count)
return () => {
- // When dependencies (like interval) change, the OLD timer is stopped
- // and the NEW one is started immediately in the next step.
stopPolling(pollingId);
};
-
- }, [pollingId, stableFetchAction, interval]); // Interval is now a dependency
+ }, [pollingId, interval, ...dependencies]);
+ // 🌟 NOTICE: fetchAction is NOT a dependency here.
+ // This prevents the "constant start/stop" cycle.
};
\ No newline at end of file