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 2023/12/14 01:32:36 UTC
(camel-karavan) branch main updated: Fixes for demo
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push:
new 812f39bd Fixes for demo
812f39bd is described below
commit 812f39bd40acada7660749a2d5d6ffb6bb5b1bd4
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Dec 13 20:32:29 2023 -0500
Fixes for demo
---
.../apache/camel/karavan/api/BuildResource.java | 56 +++++++++
.../camel/karavan/api/ContainerResource.java | 2 +-
.../apache/camel/karavan/api/DevModeResource.java | 2 +-
.../org/apache/camel/karavan/code/CodeService.java | 9 +-
.../org/apache/camel/karavan/git/GitService.java | 2 +
.../karavan/infinispan/InfinispanService.java | 6 +-
.../karavan/kubernetes/KubernetesService.java | 100 +++++++++++-----
.../camel/karavan/kubernetes/PodEventHandler.java | 13 ++-
.../apache/camel/karavan/service/CamelService.java | 46 +++++---
.../karavan/service/ContainerStatusService.java | 1 +
.../camel/karavan/service/ProjectService.java | 17 +--
.../org/apache/camel/karavan/shared/Constants.java | 5 +
.../src/main/webui/src/api/KaravanApi.tsx | 11 ++
.../designer/route/element/DslElementHeader.tsx | 5 +-
.../route/property/ComponentParameterField.tsx | 5 +-
.../designer/route/property/DslPropertyField.tsx | 3 +-
.../src/designer/route/useRouteDesignerHook.tsx | 20 +++-
.../webui/src/project/{file => }/FileEditor.tsx | 21 ++--
.../src/main/webui/src/project/ProjectPage.tsx | 2 +-
.../webui/src/project/file/PropertiesPanel.tsx | 61 ----------
.../webui/src/project/file/PropertiesTable.tsx | 126 ---------------------
.../webui/src/project/file/PropertiesToolbar.tsx | 63 -----------
.../main/webui/src/project/file/PropertyField.tsx | 73 ------------
.../main/webui/src/project/files/FilesToolbar.tsx | 26 ++++-
24 files changed, 268 insertions(+), 407 deletions(-)
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/BuildResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/BuildResource.java
new file mode 100644
index 00000000..ace9fa8c
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/BuildResource.java
@@ -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.
+ */
+package org.apache.camel.karavan.api;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+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.code.CodeService;
+import org.apache.camel.karavan.infinispan.InfinispanService;
+import org.apache.camel.karavan.kubernetes.KubernetesService;
+
+@Path("/api/build")
+public class BuildResource {
+
+ @Inject
+ InfinispanService infinispanService;
+
+ @Inject
+ KubernetesService kubernetesService;
+
+ @Inject
+ CodeService codeService;
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Path("/update-config-map")
+ public Response updateConfigMaps() {
+ if (infinispanService.isReady()) {
+ String script = codeService.getBuilderScript();
+ kubernetesService.createBuildScriptConfigmap(script, true);
+ return Response.ok().build();
+ } else {
+ return Response.noContent().build();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
index 8effafe0..bfcae002 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
@@ -156,7 +156,7 @@ public class ContainerResource {
status = ContainerStatus.createByType(projectId, environment, ContainerStatus.ContainerType.valueOf(type));
}
status.setInTransit(true);
- eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(status));
+ eventBus.publish(CONTAINER_STATUS, JsonObject.mapFrom(status));
}
@GET
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
index 1a8fe8ad..14bbc5a6 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
@@ -114,7 +114,7 @@ public class DevModeResource {
status = ContainerStatus.createByType(name, environment, ContainerStatus.ContainerType.valueOf(type));
}
status.setInTransit(true);
- eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(status));
+ eventBus.publish(CONTAINER_STATUS, JsonObject.mapFrom(status));
}
@GET
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
index cab3a77e..6bd42fec 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/code/CodeService.java
@@ -40,6 +40,7 @@ import org.apache.camel.karavan.infinispan.model.Project;
import org.apache.camel.karavan.infinispan.model.ProjectFile;
import org.apache.camel.karavan.kubernetes.KubernetesService;
import org.apache.camel.karavan.service.ConfigService;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
@@ -58,12 +59,16 @@ public class CodeService {
public static final String BUILD_SCRIPT_FILENAME = "build.sh";
public static final String DEV_SERVICES_FILENAME = "devservices.yaml";
public static final String PROJECT_COMPOSE_FILENAME = "docker-compose.yaml";
+ public static final String MARKDOWN_EXTENSION = ".md";
public static final String PROJECT_JKUBE_EXTENSION = ".jkube.yaml";
public static final String PROJECT_DEPLOYMENT_JKUBE_FILENAME = "deployment" + PROJECT_JKUBE_EXTENSION;
private static final String SNIPPETS_PATH = "/snippets/";
private static final String DATA_FOLDER = System.getProperty("user.dir") + File.separator + "data";
private static final int INTERNAL_PORT = 8080;
+ @ConfigProperty(name = "karavan.environment")
+ String environment;
+
@Inject
KubernetesService kubernetesService;
@@ -91,6 +96,7 @@ public class CodeService {
public Map<String, String> getProjectFilesForDevMode(String projectId, Boolean withKamelets) {
Map<String, String> files = infinispanService.getProjectFiles(projectId).stream()
+ .filter(f -> !f.getName().endsWith(MARKDOWN_EXTENSION))
.filter(f -> !Objects.equals(f.getName(), PROJECT_COMPOSE_FILENAME))
.filter(f -> !f.getName().endsWith(PROJECT_JKUBE_EXTENSION))
.collect(Collectors.toMap(ProjectFile::getName, ProjectFile::getCode));
@@ -142,7 +148,8 @@ public class CodeService {
? (kubernetesService.isOpenshift() ? "openshift" : "kubernetes")
: "docker";
String templateName = target + "-" + BUILD_SCRIPT_FILENAME;
- return getTemplateText(templateName);
+ String envTemplate = getTemplateText(environment + "." + templateName);
+ return envTemplate != null ? envTemplate : getTemplateText(templateName);
}
public String getTemplateText(String fileName) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
index 779e0edb..c07496b0 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
@@ -457,6 +457,8 @@ public class GitService {
String folder = vertx.fileSystem().createTempDirectoryBlocking(uuid);
try (Git git = clone(folder, gitConfig.getUri(), gitConfig.getBranch(), cred)) {
LOGGER.info("Git is ready");
+ } catch (Exception e) {
+ LOGGER.info("Error connecting git: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage()));
}
return true;
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
index 109781e3..a2f4c6fe 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
@@ -255,7 +255,11 @@ public class InfinispanService implements HealthCheck {
}
public ContainerStatus getContainerStatus(String projectId, String env, String containerName) {
- return containerStatuses.get(GroupedKey.create(projectId, env, containerName));
+ return getContainerStatus(GroupedKey.create(projectId, env, containerName));
+ }
+
+ public ContainerStatus getContainerStatus(GroupedKey key) {
+ return containerStatuses.get(key);
}
public ContainerStatus getDevModeContainerStatus(String projectId, String env) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
index 5b2459ab..d3123d13 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
@@ -18,8 +18,8 @@ package org.apache.camel.karavan.kubernetes;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.dsl.LogWatch;
import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
import io.fabric8.openshift.api.model.ImageStream;
@@ -43,6 +43,7 @@ import org.eclipse.microprofile.health.Readiness;
import org.jboss.logging.Logger;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
@@ -62,11 +63,14 @@ public class KubernetesService implements HealthCheck {
@Inject
InfinispanService infinispanService;
+ @Inject
+ CodeService codeService;
+
private String namespace;
@Produces
public KubernetesClient kubernetesClient() {
- return new DefaultKubernetesClient();
+ return new KubernetesClientBuilder().build();
}
@Produces
@@ -77,6 +81,12 @@ public class KubernetesService implements HealthCheck {
@ConfigProperty(name = "karavan.environment")
public String environment;
+ @ConfigProperty(name = "karavan.devmode.image")
+ public String devmodeImage;
+
+ @ConfigProperty(name = "karavan.devmode.create-pvc")
+ public Boolean devmodePVC;
+
@ConfigProperty(name = "karavan.version")
String version;
@@ -131,19 +141,27 @@ public class KubernetesService implements HealthCheck {
informers.clear();
}
+ public void createBuildScriptConfigmap(String script, boolean overwrite) {
+ try (KubernetesClient client = kubernetesClient()) {
+ ConfigMap configMap = client.configMaps().inNamespace(getNamespace()).withName(BUILD_CONFIG_MAP).get();
+ if (configMap == null) {
+ configMap = getConfigMapForBuilder(BUILD_CONFIG_MAP, getPartOfLabels());
+ configMap.setData(Map.of("build.sh", script));
+ client.resource(configMap).create();
+ } else if (overwrite) {
+ configMap.setData(Map.of("build.sh", script));
+ client.resource(configMap).patch();
+ }
+ } catch (Exception e) {
+ LOGGER.error("Error starting informers: " + e.getMessage());
+ }
+ }
public void runBuildProject(Project project, String script, List<String> env, String tag) {
try (KubernetesClient client = kubernetesClient()) {
String containerName = project.getProjectId() + BUILDER_SUFFIX;
Map<String, String> labels = getLabels(containerName, project, ContainerStatus.ContainerType.build);
// createPVC(containerName, labels);
-
- // create script configMap
- ConfigMap configMap = client.configMaps().inNamespace(getNamespace()).withName(containerName).get();
- if (configMap == null) {
- configMap = getConfigMapForBuilder(containerName, labels);
- }
- configMap.setData(Map.of("build.sh", script));
- client.resource(configMap).serverSideApply();
+ createBuildScriptConfigmap(script, false);
// Delete old build pod
Pod old = client.pods().inNamespace(getNamespace()).withName(containerName).get();
@@ -151,9 +169,11 @@ public class KubernetesService implements HealthCheck {
client.resource(old).delete();
}
Pod pod = getBuilderPod(containerName, env, labels);
- Pod result = client.resource(pod).serverSideApply();
+ Pod result = client.resource(pod).create();
LOGGER.info("Created pod " + result.getMetadata().getName());
+ } catch (Exception e) {
+ LOGGER.error("Error creating build container: " + e.getMessage());
}
}
@@ -166,6 +186,9 @@ public class KubernetesService implements HealthCheck {
if (type != null) {
labels.put(LABEL_TYPE, type.name());
}
+ if (Objects.equals(type, ContainerStatus.ContainerType.devmode)) {
+ labels.put(LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue());
+ }
return labels;
}
@@ -238,13 +261,13 @@ public class KubernetesService implements HealthCheck {
Container container = new ContainerBuilder()
.withName(name)
- .withImage("ghcr.io/apache/camel-karavan-devmode:" + version)
+ .withImage(devmodeImage)
.withPorts(port)
.withImagePullPolicy("Always")
.withEnv(envVars)
.withCommand("/bin/sh", "-c", "/karavan/builder/build.sh")
.withVolumeMounts(
- new VolumeMountBuilder().withName("builder").withMountPath("/karavan/builder").withReadOnly(true).build()
+ new VolumeMountBuilder().withName(BUILD_CONFIG_MAP).withMountPath("/karavan/builder").withReadOnly(true).build()
)
.build();
@@ -254,14 +277,15 @@ public class KubernetesService implements HealthCheck {
.withRestartPolicy("Never")
.withServiceAccount(KARAVAN_SERVICE_ACCOUNT)
.withVolumes(
- new VolumeBuilder().withName("builder")
- .withConfigMap(new ConfigMapVolumeSourceBuilder().withName(name).withItems(
+ new VolumeBuilder().withName(BUILD_CONFIG_MAP)
+ .withConfigMap(new ConfigMapVolumeSourceBuilder().withName(BUILD_CONFIG_MAP).withItems(
new KeyToPathBuilder().withKey("build.sh").withPath("build.sh").build()
).withDefaultMode(511).build()).build()
// new VolumeBuilder().withName("maven-settings")
// .withConfigMap(new ConfigMapVolumeSourceBuilder()
// .withName("karavan").build()).build()
- ).build();
+ )
+ .build();
return new PodBuilder()
.withMetadata(meta)
@@ -363,22 +387,38 @@ public class KubernetesService implements HealthCheck {
return result;
}
- public void runDevModeContainer(Project project, String jBangOptions) {
+ public void runDevModeContainer(Project project, String jBangOptions, Map<String, String> files) {
String name = project.getProjectId();
Map<String, String> labels = getLabels(name, project, ContainerStatus.ContainerType.devmode);
+
try (KubernetesClient client = kubernetesClient()) {
- createPVC(name, labels);
+ if (devmodePVC) {
+ createPVC(name, labels);
+ }
Pod old = client.pods().inNamespace(getNamespace()).withName(name).get();
if (old == null) {
Map<String, String> containerResources = CodeService.DEFAULT_CONTAINER_RESOURCES;
Pod pod = getDevModePod(name, jBangOptions, containerResources, labels);
Pod result = client.resource(pod).createOrReplace();
+ copyFilesToContainer(result, files, "/karavan/code");
LOGGER.info("Created pod " + result.getMetadata().getName());
}
}
createService(name, labels);
}
+ private void copyFilesToContainer(Pod pod, Map<String, String> files, String dirName) {
+ try (KubernetesClient client = kubernetesClient()) {
+ String temp = codeService.saveProjectFilesInTemp(files);
+ client.pods().inNamespace(getNamespace())
+ .withName(pod.getMetadata().getName())
+ .dir(dirName)
+ .upload(Paths.get(temp));
+ } catch (Exception e) {
+ LOGGER.info("Error copying filed to devmode pod: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage()));
+ }
+ }
+
public void deleteDevModePod(String name, boolean deletePVC) {
try (KubernetesClient client = kubernetesClient()) {
LOGGER.info("Delete devmode pod: " + name + " in the namespace: " + getNamespace());
@@ -418,27 +458,29 @@ public class KubernetesService implements HealthCheck {
Container container = new ContainerBuilder()
.withName(name)
- .withImage("ghcr.io/apache/camel-karavan-devmode:" + version)
+ .withImage(devmodeImage)
.withPorts(port)
.withResources(resources)
.withImagePullPolicy("Always")
.withEnv(new EnvVarBuilder().withName(ENV_VAR_JBANG_OPTIONS).withValue(jbangOptions).build())
-// .withVolumeMounts(
-// new VolumeMountBuilder().withName("maven-settings").withSubPath("maven-settings.xml")
-// .withMountPath("/karavan-config-map/maven-settings.xml").build()
-// )
.build();
+
+ List<Volume> volumes = new ArrayList<>();
+ volumes.add(new VolumeBuilder().withName("maven-settings")
+ .withConfigMap(new ConfigMapVolumeSourceBuilder()
+ .withName("karavan").build()).build());
+
+ if (devmodePVC) {
+ volumes.add(new VolumeBuilder().withName(name)
+ .withNewPersistentVolumeClaim(name, false).build());
+ }
+
PodSpec spec = new PodSpecBuilder()
.withTerminationGracePeriodSeconds(0L)
.withContainers(container)
.withRestartPolicy("Never")
- .withVolumes(
- new VolumeBuilder().withName(name)
- .withNewPersistentVolumeClaim(name, false).build(),
- new VolumeBuilder().withName("maven-settings")
- .withConfigMap(new ConfigMapVolumeSourceBuilder()
- .withName("karavan").build()).build())
+ .withVolumes(volumes)
.build();
return new PodBuilder()
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
index 0af91999..937cb2f2 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
@@ -33,8 +33,7 @@ import java.util.Objects;
import static org.apache.camel.karavan.code.CodeService.DEFAULT_CONTAINER_RESOURCES;
import static org.apache.camel.karavan.service.ContainerStatusService.CONTAINER_STATUS;
-import static org.apache.camel.karavan.shared.Constants.LABEL_PROJECT_ID;
-import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE;
+import static org.apache.camel.karavan.shared.Constants.*;
public class PodEventHandler implements ResourceEventHandler<Pod> {
@@ -55,7 +54,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
LOGGER.info("onAdd " + pod.getMetadata().getName());
ContainerStatus ps = getPodStatus(pod);
if (ps != null) {
- eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
+ eventBus.publish(CONTAINER_STATUS, JsonObject.mapFrom(ps));
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e.getCause());
@@ -69,7 +68,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
if (!newPod.isMarkedForDeletion() && newPod.getMetadata().getDeletionTimestamp() == null) {
ContainerStatus ps = getPodStatus(newPod);
if (ps != null) {
- eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(ps));
+ eventBus.publish(CONTAINER_STATUS, JsonObject.mapFrom(ps));
}
}
} catch (Exception e) {
@@ -94,6 +93,8 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
public ContainerStatus getPodStatus(Pod pod) {
String deployment = pod.getMetadata().getLabels().get("app");
String projectId = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_PROJECT_ID);
+ String camel = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_KUBERNETES_RUNTIME);
+ String runtime = deployment != null ? deployment : pod.getMetadata().getLabels().get(LABEL_CAMEL_RUNTIME);
String type = pod.getMetadata().getLabels().get(LABEL_TYPE);
ContainerStatus.ContainerType containerType = deployment != null
? ContainerStatus.ContainerType.project
@@ -125,7 +126,8 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
status.setContainerId(pod.getMetadata().getName());
status.setPhase(pod.getStatus().getPhase());
status.setPodIP(pod.getStatus().getPodIP());
- if (ready) {
+ status.setCamelRuntime(runtime != null ? runtime : (camel != null ? CamelRuntime.CAMEL_MAIN.getValue() : ""));
+ if (running) {
status.setState(ContainerStatus.State.running.name());
} else if (failed) {
status.setState(ContainerStatus.State.dead.name());
@@ -136,6 +138,7 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
}
return status;
} catch (Exception ex) {
+ ex.printStackTrace();
LOGGER.error(ex.getMessage(), ex.getCause());
return null;
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
index 134b41fe..0923251a 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
@@ -79,6 +79,7 @@ public class CamelService {
@Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
public void collectCamelStatuses() {
+ LOGGER.info("Collect Camel Statuses");
if (infinispanService.isReady()) {
infinispanService.getContainerStatuses(environment).stream()
.filter(cs ->
@@ -98,12 +99,13 @@ public class CamelService {
public void reloadProjectCode(String projectId) {
LOGGER.info("Reload project code " + projectId);
try {
+ deleteRequest(projectId);
Map<String, String> files = codeService.getProjectFilesForDevMode(projectId, true);
files.forEach((name, code) -> putRequest(projectId, name, code, 1000));
reloadRequest(projectId);
ContainerStatus containerStatus = infinispanService.getDevModeContainerStatus(projectId, environment);
containerStatus.setCodeLoaded(true);
- eventBus.send(ContainerStatusService.CONTAINER_STATUS, JsonObject.mapFrom(containerStatus));
+ eventBus.publish(ContainerStatusService.CONTAINER_STATUS, JsonObject.mapFrom(containerStatus));
} catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
@@ -122,10 +124,20 @@ public class CamelService {
return false;
}
+ public String deleteRequest(String containerName) {
+ String url = getContainerAddressForReload(containerName) + "/q/upload/*";
+ try {
+ return deleteResult(url, 1000);
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error(e.getMessage());
+ }
+ return null;
+ }
+
public String reloadRequest(String containerName) {
String url = getContainerAddressForReload(containerName) + "/q/dev/reload?reload=true";
try {
- return result(url, 1000);
+ return getResult(url, 1000);
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(e.getMessage());
}
@@ -158,7 +170,7 @@ public class CamelService {
public String getCamelStatus(ContainerStatus containerStatus, CamelStatusValue.Name statusName) {
String url = getContainerAddressForStatus(containerStatus) + "/q/dev/" + statusName.name();
try {
- return result(url, 500);
+ return getResult(url, 500);
} catch (InterruptedException | ExecutionException e) {
LOGGER.error(e.getMessage());
}
@@ -169,6 +181,7 @@ public class CamelService {
public void collectCamelStatuses(JsonObject data) {
CamelStatusRequest dms = data.getJsonObject("camelStatusRequest").mapTo(CamelStatusRequest.class);
ContainerStatus containerStatus = data.getJsonObject("containerStatus").mapTo(ContainerStatus.class);
+ LOGGER.info("Collect Camel Status for " + containerStatus.getContainerName());
String projectId = dms.getProjectId();
String containerName = dms.getContainerName();
List<CamelStatusValue> statuses = new ArrayList<>();
@@ -176,27 +189,14 @@ public class CamelService {
String status = getCamelStatus(containerStatus, statusName);
if (status != null) {
statuses.add(new CamelStatusValue(statusName, status));
- if (ConfigService.inKubernetes() && Objects.equals(statusName, CamelStatusValue.Name.context)) {
- checkReloadRequired(containerStatus);
- }
}
});
CamelStatus cs = new CamelStatus(projectId, containerName, statuses, environment);
infinispanService.saveCamelStatus(cs);
}
- private void checkReloadRequired(ContainerStatus cs) {
- if (ConfigService.inKubernetes()) {
- if (!Objects.equals(cs.getCodeLoaded(), true)
- && Objects.equals(cs.getState(), ContainerStatus.State.running.name())
- && Objects.equals(cs.getType(), ContainerStatus.ContainerType.devmode)) {
- eventBus.publish(RELOAD_PROJECT_CODE, cs.getProjectId());
- }
- }
- }
-
@CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 1000)
- public String result(String url, int timeout) throws InterruptedException, ExecutionException {
+ public String getResult(String url, int timeout) throws InterruptedException, ExecutionException {
try {
HttpResponse<Buffer> result = getWebClient().getAbs(url).putHeader("Accept", "application/json")
.timeout(timeout).send().subscribeAsCompletionStage().toCompletableFuture().get();
@@ -210,6 +210,18 @@ public class CamelService {
return null;
}
+ public String deleteResult(String url, int timeout) throws InterruptedException, ExecutionException {
+ try {
+ HttpResponse<Buffer> result = getWebClient().deleteAbs(url)
+ .timeout(timeout).send().subscribeAsCompletionStage().toCompletableFuture().get();
+ JsonObject res = result.bodyAsJsonObject();
+ return res.encodePrettily();
+ } catch (Exception e) {
+ LOGGER.info(e.getMessage());
+ }
+ return null;
+ }
+
public static class CamelStatusRequest {
private String projectId;
private String containerName;
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
index 9909b20b..712eb638 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
@@ -103,6 +103,7 @@ public class ContainerStatusService {
if (infinispanService.isReady()) {
ContainerStatus newStatus = data.mapTo(ContainerStatus.class);
ContainerStatus oldStatus = infinispanService.getContainerStatus(newStatus.getProjectId(), newStatus.getEnv(), newStatus.getContainerName());
+
if (oldStatus == null) {
infinispanService.saveContainerStatus(newStatus);
} else if (Objects.equals(oldStatus.getInTransit(), Boolean.FALSE)) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 3634fee3..75d0f004 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -34,6 +34,7 @@ import org.apache.camel.karavan.infinispan.model.Project;
import org.apache.camel.karavan.infinispan.model.ProjectFile;
import org.apache.camel.karavan.kubernetes.KubernetesService;
import org.apache.camel.karavan.registry.RegistryService;
+import org.apache.camel.karavan.shared.Constants;
import org.apache.camel.karavan.shared.Property;
import org.apache.camel.karavan.shared.exception.ProjectExistsException;
import org.apache.commons.lang3.StringUtils;
@@ -99,16 +100,14 @@ public class ProjectService implements HealthCheck {
if (status == null) {
status = ContainerStatus.createDevMode(project.getProjectId(), environment);
}
-
if (!Objects.equals(status.getState(), ContainerStatus.State.running.name())) {
status.setInTransit(true);
- eventBus.send(ContainerStatusService.CONTAINER_STATUS, JsonObject.mapFrom(status));
+ eventBus.publish(ContainerStatusService.CONTAINER_STATUS, JsonObject.mapFrom(status));
+ Map<String, String> files = codeService.getProjectFilesForDevMode(project.getProjectId(), true);
if (ConfigService.inKubernetes()) {
- kubernetesService.runDevModeContainer(project, jBangOptions);
+ kubernetesService.runDevModeContainer(project, jBangOptions, files);
} else {
- Map<String, String> files = codeService.getProjectFilesForDevMode(project.getProjectId(), true);
-
DockerComposeService dcs = codeService.getDockerComposeService(project.getProjectId());
dockerForKaravan.runProjectInDevMode(project.getProjectId(), jBangOptions, dcs.getPortsMap(), files);
}
@@ -260,9 +259,11 @@ public class ProjectService implements HealthCheck {
if (infinispanService.getProjects().isEmpty()) {
importAllProjects();
}
- addKameletsProject();
- addTemplatesProject();
- addServicesProject();
+ if (Objects.equals(environment, Constants.DEV_ENV)) {
+ addKameletsProject();
+ addTemplatesProject();
+ addServicesProject();
+ }
ready.set(true);
} else {
LOGGER.info("Projects are not ready");
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
index 8b633ed0..72ea919d 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
@@ -18,12 +18,14 @@ package org.apache.camel.karavan.shared;
public class Constants {
+ public static final String DEV_ENV = "dev";
public static final String ENV_VAR_JBANG_OPTIONS = "JBANG_OPTIONS";
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_CAMEL_RUNTIME = "org.apache.camel.karavan/runtime";
+ public static final String LABEL_KUBERNETES_RUNTIME = "app.kubernetes.io/runtime";
public static final String LABEL_TAG = "org.apache.camel.karavan/tag";
public static final String BUILDER_SUFFIX = "-builder";
@@ -36,6 +38,9 @@ public class Constants {
public static final String M2_CACHE_SUFFIX = "m2-cache";
public static final String PVC_MAVEN_SETTINGS = "maven-settings";
+ public static final String BUILD_CONFIG_MAP = "build-config-map";
+ public static final String BUILD_SCRIPT_FILENAME_SUFFIX = "-build.sh";
+
public enum CamelRuntime {
CAMEL_MAIN("camel-main"),
QUARKUS("quarkus"),
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 5c01bd6f..0d07f0da 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -273,6 +273,17 @@ export class KaravanApi {
});
}
+ static async updateBuildConfigMap(after: (res: AxiosResponse<any>) => void) {
+ instance.post('/api/build/update-config-map', "{}")
+ .then(res => {
+ if (res.status === 200) {
+ after(res.data);
+ }
+ }).catch(err => {
+ console.log(err);
+ });
+ }
+
static async getFiles(projectId: string, after: (files: ProjectFile[]) => void) {
instance.get('/api/file/' + projectId)
.then(res => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
index d201d105..c850e514 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
@@ -147,8 +147,9 @@ export function DslElementHeader(props: Props) {
classes.push(isElementSelected() ? 'header-bottom-selected' : 'header-bottom-not-selected')
} else if (step.dslName === 'RouteConfigurationDefinition') {
classes.push('header-route')
- if (hasElements(step)) classes.push('header-bottom-line')
- classes.push(isElementSelected() ? 'header-bottom-selected' : 'header-bottom-not-selected')
+ if (hasElements(step)) {
+ classes.push(isElementSelected() ? 'header-bottom-selected' : 'header-bottom-not-selected')
+ }
} else {
classes.push('header')
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
index f80c3e75..49eb2f6a 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
@@ -297,13 +297,14 @@ export function ComponentParameterField(props: Props) {
}
function getSwitch(property: ComponentProperty, value: any) {
+ const isChecked = value !== undefined ? Boolean(value) : (property.defaultValue !== undefined && ['true', true].includes(property.defaultValue))
return (
<Switch
id={id} name={id}
value={value?.toString()}
aria-label={id}
- isChecked={value !== undefined ? Boolean(value) : property.defaultValue !== undefined && property.defaultValue === 'true'}
- onChange={e => parametersChanged(property.name, !Boolean(value))}/>
+ isChecked={isChecked}
+ onChange={(e, checked) => parametersChanged(property.name, checked)}/>
)
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
index 77974d13..a7feb03c 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
@@ -171,7 +171,8 @@ export function DslPropertyField(props: Props) {
function isUriReadOnly(property: PropertyMeta): boolean {
const dslName: string = props.element?.dslName || '';
- return property.name === 'uri' && !['ToDynamicDefinition', 'WireTapDefinition', 'InterceptFromDefinition'].includes(dslName)
+ return property.name === 'uri'
+ && !['ToDynamicDefinition', 'WireTapDefinition', 'InterceptFromDefinition', 'InterceptSendToEndpointDefinition'].includes(dslName)
}
function selectInfrastructure(value: string) {
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
index 1457adba..51b97e20 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/useRouteDesignerHook.tsx
@@ -18,7 +18,14 @@ import React from 'react';
import '../karavan.css';
import {DslMetaModel} from "../utils/DslMetaModel";
import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {ChoiceDefinition, FromDefinition, LogDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {
+ ChoiceDefinition,
+ FromDefinition, JsonDataFormat,
+ LogDefinition,
+ MarshalDefinition,
+ RouteConfigurationDefinition,
+ RouteDefinition, UnmarshalDefinition
+} from "karavan-core/lib/model/CamelDefinition";
import {CamelElement, MetadataLabels} from "karavan-core/lib/model/IntegrationDefinition";
import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
@@ -247,6 +254,7 @@ export function useRouteDesignerHook () {
default:
const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
const augmentedStep = setDslDefaults(step);
+ console.log(step, augmentedStep)
addStep(augmentedStep, parentId, position)
break;
}
@@ -261,6 +269,16 @@ export function useRouteDesignerHook () {
(step as ChoiceDefinition).when?.push(CamelDefinitionApi.createStep('WhenDefinition', undefined));
(step as ChoiceDefinition).otherwise = CamelDefinitionApi.createStep('OtherwiseDefinition', undefined);
}
+ if (step.dslName === 'MarshalDefinition') {
+ if (CamelDefinitionApiExt.getDataFormat(step) === undefined) {
+ (step as MarshalDefinition).json = new JsonDataFormat()
+ }
+ }
+ if (step.dslName === 'UnmarshalDefinition') {
+ if (CamelDefinitionApiExt.getDataFormat(step) === undefined) {
+ (step as UnmarshalDefinition).json = new JsonDataFormat()
+ }
+ }
return step;
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx b/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx
similarity index 82%
rename from karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx
rename to karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx
index b5bf2fdc..b98285eb 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/FileEditor.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx
@@ -15,18 +15,14 @@
* limitations under the License.
*/
import React from 'react';
-import '../../designer/karavan.css';
+import '../designer/karavan.css';
import Editor from "@monaco-editor/react";
import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import {ProjectFile} from "../../api/ProjectModels";
-import {useFilesStore, useFileStore} from "../../api/ProjectStore";
-import {KaravanDesigner} from "../../designer/KaravanDesigner";
-import {ProjectService} from "../../api/ProjectService";
-import {PropertiesTable} from "./PropertiesTable";
+import {ProjectFile} from "../api/ProjectModels";
+import {useFilesStore, useFileStore} from "../api/ProjectStore";
+import {KaravanDesigner} from "../designer/KaravanDesigner";
+import {ProjectService} from "../api/ProjectService";
import {shallow} from "zustand/shallow";
-import {PropertiesToolbar} from "./PropertiesToolbar";
-import {Card, Panel} from "@patternfly/react-core";
-import {PropertiesPanel} from "./PropertiesPanel";
interface Props {
projectId: string
@@ -34,7 +30,8 @@ interface Props {
const languages = new Map<string, string>([
['sh', 'shell'],
- ['md', 'markdown']
+ ['md', 'markdown'],
+ ['properties', 'ini']
])
export function FileEditor (props: Props) {
@@ -93,14 +90,12 @@ export function FileEditor (props: Props) {
const isCamelYaml = file !== undefined && file.name.endsWith(".camel.yaml");
const isKameletYaml = file !== undefined && file.name.endsWith(".kamelet.yaml");
const isIntegration = isCamelYaml && file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code);
- const isProperties = file !== undefined && file.name.endsWith("properties");
const showDesigner = (isCamelYaml && isIntegration) || isKameletYaml;
- const showEditor = !showDesigner && !isProperties;
+ const showEditor = !showDesigner;
return (
<>
{showDesigner && getDesigner()}
{showEditor && getEditor()}
- {isProperties && file !== undefined && <PropertiesPanel/>}
</>
)
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index 39c4ff1e..59950bb6 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -29,7 +29,7 @@ import {useAppConfigStore, useFilesStore, useFileStore, useProjectsStore, usePro
import {MainToolbar} from "../designer/MainToolbar";
import {ProjectTitle} from "./ProjectTitle";
import {ProjectPanel} from "./ProjectPanel";
-import {FileEditor} from "./file/FileEditor";
+import {FileEditor} from "./FileEditor";
import {shallow} from "zustand/shallow";
import {useParams} from "react-router-dom";
import {KaravanApi} from "../api/KaravanApi";
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesPanel.tsx
deleted file mode 100644
index db4e290c..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesPanel.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 {
- PageSection, PanelHeader, Panel
-} from '@patternfly/react-core';
-import '../../designer/karavan.css';
-import { useProjectStore} from "../../api/ProjectStore";
-import { ProjectFileTypes} from "../../api/ProjectModels";
-import {shallow} from "zustand/shallow";
-import {PropertiesToolbar} from "./PropertiesToolbar";
-import {PropertiesTable} from "./PropertiesTable";
-
-export function PropertiesPanel () {
-
- const [project] = useProjectStore((s) => [s.project], shallow);
-
- function isBuildIn(): boolean {
- return ['kamelets', 'templates', 'services'].includes(project.projectId);
- }
-
- function canDeleteFiles(): boolean {
- return !['templates', 'services'].includes(project.projectId);
- }
-
- function isKameletsProject(): boolean {
- return project.projectId === 'kamelets';
- }
-
- const types = isBuildIn()
- ? (isKameletsProject() ? ['KAMELET'] : ['CODE', 'PROPERTIES'])
- : ProjectFileTypes.filter(p => !['PROPERTIES', 'LOG', 'KAMELET'].includes(p.name)).map(p => p.name);
-
- return (
- <PageSection padding={{default: 'noPadding'}} className="scrollable-out">
- <PageSection isFilled padding={{default: 'padding'}} className="scrollable-in">
- <Panel>
- <PanelHeader>
- <PropertiesToolbar/>
- </PanelHeader>
- </Panel>
- <PropertiesTable/>
- </PageSection>
- </PageSection>
- )
-}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesTable.tsx b/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesTable.tsx
deleted file mode 100644
index 71357cbb..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesTable.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, {useEffect, useState} from 'react';
-import {
- Button,
- Modal,
-} from '@patternfly/react-core';
-import '../../designer/karavan.css';
-import {
- Tbody,
- Th,
- Thead,
- Tr
-} from '@patternfly/react-table';
-import {
- Table
-} from '@patternfly/react-table/deprecated';
-
-import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel";
-import {useFileStore} from "../../api/ProjectStore";
-import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
-import {shallow} from "zustand/shallow"
-import {PropertyField} from "./PropertyField";
-import {ProjectService} from "../../api/ProjectService";
-
-export function PropertiesTable() {
-
- const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
- const [deleteId, setDeleteId] = useState<string | undefined>(undefined);
- const [key, setKey] = useState<string | undefined>(undefined);
- const [properties, setProperties] = useState<ProjectProperty[]>([]);
- const [file, editAdvancedProperties, addProperty, setAddProperty] = useFileStore((state) =>
- [state.file, state.editAdvancedProperties, state.addProperty, state.setAddProperty], shallow)
-
- useEffect(() => {
- setProperties(getProjectModel().properties)
- }, [addProperty,setDeleteId]);
-
- function save(props: ProjectProperty[]) {
- if (file) {
- file.code = ProjectModelApi.propertiesToString(props);
- ProjectService.saveFile(file, true);
- }
- }
-
- function getProjectModel(): ProjectModel {
- return file ? ProjectModelApi.propertiesToProject(file?.code) : ProjectModel.createNew()
- }
-
- function changeProperty(property: ProjectProperty) {
- const props = properties.map(prop => prop.id === property.id ? property : prop);
- save(props);
- }
-
- function startDelete(id: string) {
- setShowDeleteConfirmation(true);
- setDeleteId(id);
- }
-
- function confirmDelete() {
- const props = properties.filter(p => p.id !== deleteId);
- save(props);
- setShowDeleteConfirmation(false);
- setDeleteId(undefined);
- setAddProperty(Math.random().toString());
- }
-
- function getDeleteConfirmation() {
- return (<Modal
- className="modal-delete"
- title="Confirmation"
- isOpen={showDeleteConfirmation}
- onClose={() => setShowDeleteConfirmation(false)}
- actions={[
- <Button key="confirm" variant="primary" onClick={e => confirmDelete()}>Delete</Button>,
- <Button key="cancel" variant="link"
- onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
- ]}
- onEscapePress={e => setShowDeleteConfirmation(false)}>
- <div>Delete property?</div>
- </Modal>)
- }
-
- return (
- <>
- {properties.length > 0 &&
- <Table aria-label="Property table" variant='compact' borders={false}
- className="project-properties">
- <Thead>
- <Tr>
- <Th key='name'>Name</Th>
- <Th key='value'>Value</Th>
- <Th></Th>
- </Tr>
- </Thead>
- <Tbody>
- {properties.map((property, idx: number) => {
- const readOnly = (property.key.startsWith("camel.jbang") || property.key.startsWith("camel.karavan")) && !editAdvancedProperties;
- return (
- <PropertyField key={idx + property.key}
- property={property}
- readOnly={readOnly}
- changeProperty={changeProperty}
- onDelete={startDelete}/>
- )
- })}
- </Tbody>
- </Table>}
- {showDeleteConfirmation && getDeleteConfirmation()}
- </>
- )
-}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesToolbar.tsx
deleted file mode 100644
index 598dc95e..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertiesToolbar.tsx
+++ /dev/null
@@ -1,63 +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, Checkbox,
- Flex,
- FlexItem
-} from '@patternfly/react-core';
-import '../../designer/karavan.css';
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {useFileStore} from "../../api/ProjectStore";
-import {shallow} from "zustand/shallow";
-import {ProjectService} from "../../api/ProjectService";
-import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
-import {ProjectModel, ProjectProperty} from "karavan-core/lib/model/ProjectModel";
-
-export function PropertiesToolbar () {
-
- const [file, editAdvancedProperties, setEditAdvancedProperties, setAddProperty] = useFileStore((state) =>
- [state.file, state.editAdvancedProperties, state.setEditAdvancedProperties, state.setAddProperty], shallow )
-
-
- function addProperty() {
- if (file) {
- const project = file ? ProjectModelApi.propertiesToProject(file?.code) : ProjectModel.createNew();
- const props = project.properties;
- props.push(ProjectProperty.createNew("", ""));
- file.code = ProjectModelApi.propertiesToString(props);
- ProjectService.saveFile(file, true);
- setAddProperty(Math.random().toString());
- }
- }
-
- return (
- <Flex className="toolbar" direction={{default: "row"}} justifyContent={{default: "justifyContentFlexEnd"}}>
- <FlexItem>
- <Checkbox
- id="advanced"
- label="Edit advanced"
- isChecked={editAdvancedProperties}
- onChange={(_, checked) => setEditAdvancedProperties(checked)}
- />
- </FlexItem>
- <FlexItem>
- <Button size="sm" variant="primary" icon={<PlusIcon/>} onClick={e => addProperty()}>Add property</Button>
- </FlexItem>
- </Flex>
- )
-}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertyField.tsx b/karavan-web/karavan-app/src/main/webui/src/project/file/PropertyField.tsx
deleted file mode 100644
index 2393164d..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/project/file/PropertyField.tsx
+++ /dev/null
@@ -1,73 +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,
- TextInput
-} from '@patternfly/react-core';
-import '../../designer/karavan.css';
-import {ProjectProperty} from "karavan-core/lib/model/ProjectModel";
-import {Td, Tr} from "@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
-
-interface Props {
- property: ProjectProperty,
- readOnly: boolean,
- changeProperty: (p: ProjectProperty) => void
- onDelete: (id: string) => void
-}
-
-export function PropertyField (props: Props) {
-
- const [key, setKey] = useState<string | undefined>(props.property.key);
- const [value, setValue] = useState<string | undefined>(props.property.value);
-
- useEffect(() => {
- }, []);
-
- return (
- <Tr key={props.property.id}>
- <Td noPadding width={10} dataLabel="key">
- <TextInput isDisabled={props.readOnly} isRequired={true} className="text-field" type={"text"}
- id={"key-" + props.property.id}
- value={key}
- onChange={(e, val) => {
- e.preventDefault();
- setKey(val)
- props.changeProperty(new ProjectProperty({id: props.property.id, key: val, value: value}));
- }}/>
- </Td>
- <Td noPadding width={20} dataLabel="value">
- <TextInput isDisabled={props.readOnly} isRequired={true} className="text-field" type={"text"}
- id={"value-" + props.property.id}
- value={value }
- onChange={(e, val) => {
- e.preventDefault();
- setValue(val);
- props.changeProperty(new ProjectProperty({id: props.property.id, key: key, value: val}));
- }}/>
- </Td>
- <Td noPadding isActionCell dataLabel="delete" className="delete-cell">
- {!props.readOnly && <Button variant={"plain"} icon={<DeleteIcon/>} className={"delete-button"}
- onClick={event => {
- props.onDelete(props.property.id)
- }}/>}
- </Td>
- </Tr>
-
- )
-}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
index 2b22b917..033ad6e0 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
@@ -33,14 +33,19 @@ import {
import '../../designer/karavan.css';
import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {useFilesStore, useFileStore, useProjectStore} from "../../api/ProjectStore";
+import {useAppConfigStore, useFilesStore, useFileStore, useProjectStore} from "../../api/ProjectStore";
import {shallow} from "zustand/shallow";
import {ProjectService} from "../../api/ProjectService";
import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
+import UpdateIcon from "@patternfly/react-icons/dist/esm/icons/cog-icon";
import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
+import {ProjectType} from "../../api/ProjectModels";
+import {KaravanApi} from "../../api/KaravanApi";
+import {EventBus} from "../../designer/utils/EventBus";
export function FileToolbar () {
+ const {config} = useAppConfigStore();
const [commitMessageIsOpen, setCommitMessageIsOpen] = useState(false);
const [pullIsOpen, setPullIsOpen] = useState(false);
const [commitMessage, setCommitMessage] = useState('');
@@ -58,6 +63,12 @@ export function FileToolbar () {
ProjectService.pushProject(project, commitMessage);
}
+ function updateScripts () {
+ KaravanApi.updateBuildConfigMap(res => {
+ EventBus.sendAlert("Success", "Script updated!", "info")
+ })
+ }
+
function pull () {
setPullIsOpen(false);
ProjectService.pullProject(project.projectId);
@@ -67,6 +78,10 @@ export function FileToolbar () {
return !['templates', 'services'].includes(project.projectId);
}
+ function isTemplates(): boolean {
+ return project.projectId === 'templates' && project.type === ProjectType.templates;
+ }
+
function getCommitModal() {
return (
<Modal
@@ -198,6 +213,15 @@ export function FileToolbar () {
</Button>
</Tooltip>
</FlexItem>
+ {isTemplates() && config.infrastructure === 'kubernetes' && <FlexItem>
+ <Tooltip content="Update Build Script in Config Maps" position={"bottom-end"}>
+ <Button size="sm" variant={"primary"} icon={<UpdateIcon/>}
+ onClick={e => updateScripts()}
+ >
+ Update Script
+ </Button>
+ </Tooltip>
+ </FlexItem>}
{canAddFiles() && <FlexItem>
<Button size="sm" variant={"primary"} icon={<PlusIcon/>}
onClick={e => setFile("create")}>Create</Button>