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 2024/02/10 23:13:55 UTC
(camel-karavan) 03/03: Fix #564
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 024e8723a8b241e9cb1eb09ff17a581913a05b01
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Sat Feb 10 18:13:42 2024 -0500
Fix #564
---
.../apache/camel/karavan/api/ImagesResource.java | 9 +--
.../camel/karavan/api/NotificationResource.java | 50 ++++++++------
.../camel/karavan/api/ProjectGitResource.java | 13 +++-
.../camel/karavan/service/KaravanService.java | 3 -
.../camel/karavan/service/NotificationService.java | 50 ++++++++++++++
.../camel/karavan/service/ProjectService.java | 32 +++++++--
.../org/apache/camel/karavan/shared/Constants.java | 7 ++
.../exception/ExceptionToResponseMapper.java | 66 -------------------
.../src/main/webui/src/api/KaravanApi.tsx | 19 +++++-
.../src/main/webui/src/api/NotificationApi.tsx | 77 +++++++++++++++-------
.../src/main/webui/src/api/NotificationService.ts | 57 ++++++++++++++++
.../src/main/webui/src/api/ProjectEventBus.ts | 34 +---------
.../src/main/webui/src/api/ProjectService.ts | 9 ++-
.../karavan-app/src/main/webui/src/main/Main.tsx | 22 +++++--
.../main/webui/src/project/files/FilesToolbar.tsx | 16 ++++-
.../main/webui/src/project/log/ProjectLogPanel.tsx | 2 -
16 files changed, 286 insertions(+), 180 deletions(-)
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
index 6bbe60f5..0170918b 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
@@ -65,11 +65,8 @@ public class ImagesResource {
@Path("/{projectId}")
public Response build(JsonObject data, @PathParam("projectId") String projectId) throws Exception {
try {
- String imageName = data.getString("imageName");
- boolean commit = data.getBoolean("commit");
- String message = data.getString("message");
- projectService.setProjectImage(projectId, imageName, commit, message);
- return Response.ok().entity(imageName).build();
+ projectService.setProjectImage(projectId, data);
+ return Response.ok().entity(data.getString("imageName")).build();
} catch (Exception e) {
return Response.serverError().entity(e.getMessage()).build();
}
@@ -78,7 +75,7 @@ public class ImagesResource {
@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Path("/{imageName}")
- public Response deleteImage(@HeaderParam("username") String username, @PathParam("imageName") String imageName) {
+ public Response deleteImage(@PathParam("imageName") String imageName) {
imageName= new String(Base64.decode(imageName));
if (ConfigService.inKubernetes()) {
return Response.ok().build();
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/NotificationResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/NotificationResource.java
index 4ad4de25..d7f2deb7 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/NotificationResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/NotificationResource.java
@@ -16,48 +16,56 @@
*/
package org.apache.camel.karavan.api;
-import io.quarkus.runtime.StartupEvent;
import io.smallrye.mutiny.Multi;
import io.vertx.core.json.JsonObject;
-import io.vertx.mutiny.core.Vertx;
import io.vertx.mutiny.core.eventbus.EventBus;
-import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
-import org.jboss.logging.Logger;
+import jakarta.ws.rs.sse.OutboundSseEvent;
+import jakarta.ws.rs.sse.Sse;
import org.jboss.resteasy.reactive.RestStreamElementType;
-import java.util.Date;
+import static org.apache.camel.karavan.shared.Constants.*;
@Path("/api/notification")
public class NotificationResource {
- private static final Logger LOGGER = Logger.getLogger(NotificationResource.class.getName());
-
- void onStart(@Observes StartupEvent ev) throws Exception {
- System.out.println("STARTING!!!!!");
- vertx.setPeriodic(1000,
- aLong -> {
- vertx.eventBus().publish("test0", new JsonObject().put("user", "test0").put("date", new Date().toString()));
- vertx.eventBus().publish("test1", new JsonObject().put("user", "test1").put("date", new Date().toString()));
- });
- }
-
- @Inject
- Vertx vertx;
@Inject
EventBus bus;
+ @GET
+ @Path("/system")
+ @Produces(MediaType.SERVER_SENT_EVENTS)
+ @RestStreamElementType(MediaType.TEXT_PLAIN)
+ public Multi<OutboundSseEvent> karavanStream(
+ @Context Sse sse
+ ) {
+ return bus.<JsonObject>consumer(NOTIFICATION_ADDRESS_SYSTEM).toMulti()
+ .map(m -> sse.newEventBuilder()
+ .id(m.headers().get(NOTIFICATION_HEADER_EVENT_ID))
+ .name(m.headers().get(NOTIFICATION_HEADER_EVENT_NAME) + ":" + m.headers().get(NOTIFICATION_HEADER_CLASS_NAME))
+ .data(m.body())
+ .build());
+ }
@GET
- @Path("{name}")
+ @Path("/user/{id}")
@Produces(MediaType.SERVER_SENT_EVENTS)
@RestStreamElementType(MediaType.TEXT_PLAIN)
- public Multi<String> greetingStream(@PathParam("name") String name) {
- return bus.<String>consumer(name).bodyStream().toMulti();
+ public Multi<OutboundSseEvent> userStream(
+ @PathParam("id") String id,
+ @Context Sse sse
+ ) {
+ return bus.<JsonObject>consumer(id).toMulti()
+ .map(m -> sse.newEventBuilder()
+ .id(m.headers().get(NOTIFICATION_HEADER_EVENT_ID))
+ .name(m.headers().get(NOTIFICATION_HEADER_EVENT_NAME) + ":" + m.headers().get(NOTIFICATION_HEADER_CLASS_NAME))
+ .data(m.body())
+ .build());
}
}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectGitResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectGitResource.java
index aea987ea..b617f7b0 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectGitResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectGitResource.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.karavan.api;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
@@ -25,6 +27,9 @@ import org.apache.camel.karavan.service.ProjectService;
import org.jboss.logging.Logger;
import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.camel.karavan.service.ProjectService.PUSH_PROJECT;
@Path("/api/git")
public class ProjectGitResource {
@@ -34,11 +39,15 @@ public class ProjectGitResource {
@Inject
ProjectService projectService;
+ @Inject
+ EventBus eventBus;
+
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
- public Project push(HashMap<String, String> params) throws Exception {
- return projectService.commitAndPushProject(params.get("projectId"), params.get("message"));
+ public HashMap<String, String> push(HashMap<String, String> params) throws Exception {
+ eventBus.publish(PUSH_PROJECT, JsonObject.mapFrom(params));
+ return params;
}
@PUT
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 9d22d1c1..fe2df760 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -64,9 +64,6 @@ public class KaravanService implements HealthCheck {
@Inject
DockerForRegistry dockerForRegistry;
- @Inject
- KaravanCacheService karavanCacheService;
-
@Inject
EventBus eventBus;
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/NotificationService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/NotificationService.java
new file mode 100644
index 00000000..b73e9d78
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/NotificationService.java
@@ -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.
+ */
+package org.apache.camel.karavan.service;
+
+import io.vertx.core.eventbus.DeliveryOptions;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import java.util.UUID;
+
+import static org.apache.camel.karavan.shared.Constants.*;
+
+@ApplicationScoped
+public class NotificationService {
+
+ @Inject
+ EventBus eventBus;
+
+ public void send(String userId, String eventId, String evenName, String className, JsonObject data) {
+ eventBus.publish(userId, data, new DeliveryOptions()
+ .addHeader(NOTIFICATION_HEADER_EVENT_ID, eventId != null ? eventId : UUID.randomUUID().toString())
+ .addHeader(NOTIFICATION_HEADER_EVENT_NAME, evenName)
+ .addHeader(NOTIFICATION_HEADER_CLASS_NAME, className)
+ );
+ }
+
+ public void sendSystem(String eventId, String evenName, String className, JsonObject data) {
+ eventBus.publish(NOTIFICATION_ADDRESS_SYSTEM, data, new DeliveryOptions()
+ .addHeader(NOTIFICATION_HEADER_EVENT_ID, eventId != null ? eventId : UUID.randomUUID().toString())
+ .addHeader(NOTIFICATION_HEADER_EVENT_NAME, evenName)
+ .addHeader(NOTIFICATION_HEADER_CLASS_NAME, className)
+ );
+ }
+}
\ No newline at end of file
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 e3f2aa1a..a17044fd 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
@@ -16,6 +16,7 @@
*/
package org.apache.camel.karavan.service;
+import io.quarkus.vertx.ConsumeEvent;
import io.smallrye.mutiny.tuples.Tuple2;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
@@ -53,6 +54,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static org.apache.camel.karavan.code.CodeService.*;
+import static org.apache.camel.karavan.shared.Constants.NOTIFICATION_EVENT_COMMIT;
@Default
@Readiness
@@ -61,6 +63,8 @@ public class ProjectService implements HealthCheck {
private static final Logger LOGGER = Logger.getLogger(ProjectService.class.getName());
+ public static final String PUSH_PROJECT = "PUSH_PROJECT";
+
@ConfigProperty(name = "karavan.environment")
String environment;
@@ -71,6 +75,9 @@ public class ProjectService implements HealthCheck {
@Inject
KaravanCacheService karavanCacheService;
+ @Inject
+ NotificationService notificationService;
+
@Inject
KubernetesService kubernetesService;
@@ -348,7 +355,13 @@ public class ProjectService implements HealthCheck {
}
- public Project commitAndPushProject(String projectId, String message) throws Exception {
+ @ConsumeEvent(value = PUSH_PROJECT, blocking = true, ordered = true)
+ void commitAndPushProject(JsonObject event) throws Exception {
+ LOGGER.info("Commit: " + event.encodePrettily());
+ String projectId = event.getString("projectId");
+ String message = event.getString("message");
+ String userId = event.getString("userId");
+ String eventId = event.getString("eventId");
Project p = karavanCacheService.getProject(projectId);
List<ProjectFile> files = karavanCacheService.getProjectFiles(projectId);
RevCommit commit = gitService.commitAndPushProject(p, files, message);
@@ -357,7 +370,9 @@ public class ProjectService implements HealthCheck {
p.setLastCommit(commitId);
p.setLastCommitTimestamp(lastUpdate);
karavanCacheService.saveProject(p);
- return p;
+ if (userId != null) {
+ notificationService.sendSystem(eventId, NOTIFICATION_EVENT_COMMIT, Project.class.getSimpleName(), JsonObject.mapFrom(p));
+ }
}
void addKameletsProject() {
@@ -367,7 +382,7 @@ public class ProjectService implements HealthCheck {
if (kamelets == null) {
kamelets = new Project(Project.Type.kamelets.name(), "Custom Kamelets", "Custom Kamelets", "", Instant.now().toEpochMilli(), Project.Type.kamelets);
karavanCacheService.saveProject(kamelets);
- commitAndPushProject(Project.Type.kamelets.name(), "Add custom kamelets");
+ commitAndPushProject(JsonObject.of("projectId", Project.Type.kamelets.name(), "message", "Add custom kamelets"));
}
} catch (Exception e) {
LOGGER.error("Error during custom kamelets project creation", e);
@@ -386,7 +401,7 @@ public class ProjectService implements HealthCheck {
ProjectFile file = new ProjectFile(name, value, Project.Type.templates.name(), Instant.now().toEpochMilli());
karavanCacheService.saveProjectFile(file);
});
- commitAndPushProject(Project.Type.templates.name(), "Add default templates");
+ commitAndPushProject(JsonObject.of("projectId", Project.Type.templates.name(), "message", "Add custom templates"));
} else {
LOGGER.info("Add new templates if any");
codeService.getTemplates().forEach((name, value) -> {
@@ -414,7 +429,7 @@ public class ProjectService implements HealthCheck {
ProjectFile file = new ProjectFile(name, value, Project.Type.services.name(), Instant.now().toEpochMilli());
karavanCacheService.saveProjectFile(file);
});
- commitAndPushProject(Project.Type.services.name(), "Add services");
+ commitAndPushProject(JsonObject.of("projectId", Project.Type.services.name(), "message", "Add services"));
}
} catch (Exception e) {
LOGGER.error("Error during services project creation", e);
@@ -427,10 +442,13 @@ public class ProjectService implements HealthCheck {
return file.orElse(new ProjectFile()).getCode();
}
- public void setProjectImage(String projectId, String imageName, boolean commit, String message) throws Exception {
+ public void setProjectImage(String projectId, JsonObject data) throws Exception {
+ String imageName = data.getString("imageName");
+ boolean commit = data.getBoolean("commit");
+ data.put("projectId", projectId);
codeService.updateDockerComposeImage(projectId, imageName);
if (commit) {
- commitAndPushProject(projectId, message);
+ eventBus.publish(PUSH_PROJECT, data);
}
}
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 28f01ce8..ff6152d9 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
@@ -42,6 +42,13 @@ public class Constants {
public static final String KNOWN_HOSTS_SECRET_KEY = "known-hosts";
public static final String BUILD_SCRIPT_FILENAME_SUFFIX = "-build.sh";
+ public static final String NOTIFICATION_ADDRESS_SYSTEM = "karavanSystem";
+ public static final String NOTIFICATION_HEADER_EVENT_ID = "id";
+ public static final String NOTIFICATION_HEADER_EVENT_NAME = "eventName";
+ public static final String NOTIFICATION_HEADER_CLASS_NAME = "className";
+
+ public static final String NOTIFICATION_EVENT_COMMIT = "commit";
+
public enum CamelRuntime {
CAMEL_MAIN("camel-main"),
QUARKUS("quarkus"),
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/exception/ExceptionToResponseMapper.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/exception/ExceptionToResponseMapper.java
deleted file mode 100644
index b26b49fc..00000000
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/exception/ExceptionToResponseMapper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.camel.karavan.shared.exception;
-
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.camel.karavan.shared.error.Error;
-import org.apache.camel.karavan.shared.error.ErrorResponse;
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.reactive.RestResponse;
-import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
-
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-
-public class ExceptionToResponseMapper {
- private static final Logger LOGGER = Logger.getLogger(ExceptionToResponseMapper.class.getName());
-
- @ServerExceptionMapper
- public RestResponse<Object> validationException(ValidationException exception) {
- List<Error> errors = (exception).getErrors()
- .stream()
- .map(fieldError -> new Error(fieldError.getField(), fieldError.getMessage()))
- .toList();
-
- return logAndBuildResponse(
- exception,
- Response.Status.BAD_REQUEST.getStatusCode(),
- Response.Status.BAD_REQUEST.getReasonPhrase(),
- errors
- );
- }
-
- private RestResponse<Object> logAndBuildResponse(
- Throwable exception,
- int status,
- String reasonPhrase,
- Collection<Error> errors
- ) {
- LOGGER.error("Error occurred", exception);
-
- String cause = (exception.getCause() != null) ? exception.getCause().getMessage() : null;
- String message = (cause != null) ? exception.getMessage() + ", caused by: " + cause : exception.getMessage();
-
- if (message == null) {
- message = exception.getClass().toString();
- }
-
- // Hide errors array if there are no errors and leave just error message
- if (errors != null && errors.isEmpty()) {
- errors = null;
- }
-
- ErrorResponse responseBody = new ErrorResponse(
- status,
- reasonPhrase,
- message,
- errors
- );
-
- return RestResponse.ResponseBuilder
- .create(status)
- .entity(responseBody)
- .type(MediaType.APPLICATION_JSON)
- .build();
- }
-}
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 2efbeeb6..78239239 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
@@ -26,9 +26,9 @@ import {
} from "./ProjectModels";
import {Buffer} from 'buffer';
import {SsoApi} from "./SsoApi";
-import {EventStreamContentType, fetchEventSource} from "@microsoft/fetch-event-source";
-import {ProjectEventBus} from "./ProjectEventBus";
+import {v4 as uuidv4} from "uuid";
+const USER_ID_KEY = 'KARAVAN_USER_ID';
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.common['Content-Type'] = 'application/json';
const instance = axios.create();
@@ -43,6 +43,21 @@ export class KaravanApi {
return instance;
}
+ static getUserId(): string {
+ if (KaravanApi.me?.userName !== undefined) {
+ return KaravanApi.me?.userName;
+ } else {
+ const userId = localStorage.getItem(USER_ID_KEY);
+ if (userId !== null && userId !== undefined) {
+ return userId;
+ } else {
+ const newId = uuidv4().toString();
+ localStorage.setItem(USER_ID_KEY, newId);
+ return newId;
+ }
+ }
+ }
+
static setAuthType(authType: string) {
KaravanApi.authType = authType;
switch (authType){
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/NotificationApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/NotificationApi.tsx
index 20ea0c1f..cabf1c9e 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/NotificationApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/NotificationApi.tsx
@@ -18,40 +18,69 @@
import {SsoApi} from "./SsoApi";
import {EventStreamContentType, fetchEventSource} from "@microsoft/fetch-event-source";
import {KaravanApi} from "./KaravanApi";
+import {EventBus} from "../designer/utils/EventBus";
+import {EventSourceMessage} from "@microsoft/fetch-event-source/lib/cjs/parse";
+import {KaravanEvent, NotificationEventBus} from "./NotificationService";
export class NotificationApi {
+ static getKaravanEvent (ev: EventSourceMessage, type: 'system' | 'user') {
+ const eventParts = ev.event?.split(':');
+ const event = eventParts?.length > 1 ? eventParts[0] : undefined;
+ const className = eventParts?.length > 1 ? eventParts[1] : undefined;
+ return new KaravanEvent({id: ev.id, event: event, type: type, className: className, data: JSON.parse(ev.data)});
+ }
+
+ static onSystemMessage (ev: EventSourceMessage) {
+ const ke = NotificationApi.getKaravanEvent(ev, 'system');
+ NotificationEventBus.sendEvent(ke);
+ }
+
+ static onUserMessage (ev: EventSourceMessage) {
+ const ke = NotificationApi.getKaravanEvent(ev, 'user');
+ NotificationEventBus.sendEvent(ke);
+ }
+
static async notification(controller: AbortController) {
const fetchData = async () => {
const headers: any = { Accept: "text/event-stream" };
if (KaravanApi.authType === 'oidc') {
headers.Authorization = "Bearer " + SsoApi.keycloak?.token
}
- await fetchEventSource("/api/notification", {
- method: "GET",
- headers: headers,
- signal: controller.signal,
- async onopen(response) {
- if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
- return; // everything's good
- } else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
- // client-side errors are usually non-retriable:
- console.log("Server side error ", response);
- } else {
- console.log("Error ", response);
- }
- },
- onmessage(event) {
- console.log(event)
- },
- onclose() {
- console.log("Connection closed by the server");
- },
- onerror(err) {
- console.log("There was an error from server", err);
- },
- });
+ NotificationApi.fetch('/api/notification/system', controller, headers,
+ ev => NotificationApi.onSystemMessage(ev));
+ NotificationApi.fetch('/api/notification/user/' + KaravanApi.getUserId(), controller, headers,
+ ev => NotificationApi.onUserMessage(ev));
};
return fetchData();
+ };
+
+ static async fetch(input: string, controller: AbortController, headers: any, onmessage: (ev: EventSourceMessage) => void) {
+ fetchEventSource(input, {
+ method: "GET",
+ headers: headers,
+ signal: controller.signal,
+ async onopen(response) {
+ if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
+ return; // everything's good
+ } else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
+ // client-side errors are usually non-retriable:
+ console.log("Server side error ", response);
+ EventBus.sendAlert("Error fetching", `${input} : ${response.statusText}`, "danger");
+ } else {
+ console.log("Error ", response);
+ EventBus.sendAlert("Error fetching", `${input} : ${response.statusText}`, "danger");
+ }
+ },
+ onmessage(event) {
+ onmessage(event);
+ },
+ onclose() {
+ console.log("Connection closed by the server");
+ },
+ onerror(err) {
+ console.log("There was an error from server", err);
+ },
+ });
}
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/NotificationService.ts b/karavan-web/karavan-app/src/main/webui/src/api/NotificationService.ts
new file mode 100644
index 00000000..2008c652
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/src/api/NotificationService.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 {Subject} from "rxjs";
+import {ProjectEventBus} from "./ProjectEventBus";
+import {unstable_batchedUpdates} from "react-dom";
+import {useLogStore, useProjectStore} from "./ProjectStore";
+import {ProjectService} from "./ProjectService";
+
+export class KaravanEvent {
+ id: string = '';
+ type: 'system' | 'user' = 'system';
+ event: string = '';
+ className: string = '';
+ data: any = {};
+
+ public constructor(init?: Partial<KaravanEvent>) {
+ Object.assign(this, init);
+ }
+}
+
+const karavanEvents = new Subject<KaravanEvent>();
+
+export const NotificationEventBus = {
+ sendEvent: (event: KaravanEvent) => karavanEvents.next(event),
+ onEvent: () => karavanEvents.asObservable(),
+}
+
+console.log("Start Notification subscriber");
+const sub = NotificationEventBus.onEvent()?.subscribe((event: KaravanEvent) => {
+ // console.log('KaravanEvent', event);
+ if (event.event === 'commit' && event.className === 'Project') {
+ const projectId = event.data?.projectId;
+ if (useProjectStore.getState().project?.projectId === projectId) {
+ unstable_batchedUpdates(() => {
+ useProjectStore.setState({isPushing: false});
+ ProjectService.refreshProject(projectId);
+ ProjectService.refreshProjectData(projectId);
+ });
+ }
+ }
+});
+
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectEventBus.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectEventBus.ts
index dcbc6c6e..84e458e7 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectEventBus.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectEventBus.ts
@@ -14,44 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {BehaviorSubject, Subject} from 'rxjs';
-import {Project} from "./ProjectModels";
+import {Subject} from 'rxjs';
-const selectedProject = new BehaviorSubject<Project | undefined>(undefined);
-const currentFile = new BehaviorSubject<string | undefined>(undefined);
-const mode = new BehaviorSubject<"design" | "code">("design");
const log = new Subject<["add" | "set", string]>();
-export class ShowLogCommand {
- name: string
- environment: string
- show: boolean
-
- constructor(name: string, environment: string, show: boolean) {
- this.name = name;
- this.environment = environment;
- this.show = show;
- }
-}
-
-export class ShowTraceCommand {
- name: string
- show: boolean
-
- constructor(name: string, show: boolean) {
- this.name = name;
- this.show = show;
- }
-}
export const ProjectEventBus = {
- selectProject: (project: Project) => selectedProject.next(project),
- onSelectProject: () => selectedProject.asObservable(),
-
- setMode: (m: 'design' | 'code') => mode.next(m),
- onSetMode: () => mode.asObservable(),
-
sendLog: (type: "add" | "set", m: string) => log.next([type, m]),
onLog: () => log.asObservable(),
-
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
index 9f9891f4..9a1b5f21 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectService.ts
@@ -96,19 +96,18 @@ export class ProjectService {
}
public static pushProject(project: Project, commitMessage: string) {
- useProjectStore.setState({isPushing: true})
const params = {
'projectId': project.projectId,
- 'message': commitMessage
+ 'message': commitMessage,
+ 'userId': KaravanApi.getUserId()
};
KaravanApi.push(params, res => {
if (res.status === 200 || res.status === 201) {
- ProjectService.refreshProject(project.projectId);
- ProjectService.refreshProjectData(project.projectId);
+ // ProjectService.refreshProject(project.projectId);
+ // ProjectService.refreshProjectData(project.projectId);
} else {
EventBus.sendAlert("Error pushing", (res as any)?.response?.data, 'danger')
}
- useProjectStore.setState({isPushing: false})
});
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index 00fc6ff5..d08f5dc8 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -30,16 +30,28 @@ import {useMainHook} from "./useMainHook";
import {Notification} from "../designer/utils/Notification";
import {MainLoader} from "./MainLoader";
import {MainRoutes} from "./MainRoutes";
+import {NotificationApi} from "../api/NotificationApi";
export function Main() {
const [readiness, setReadiness] = useAppConfigStore((s) => [s.readiness, s.setReadiness], shallow)
- const {getData, getStatuses} = useMainHook();
+ const {getData} = useMainHook();
- const initialized = useRef(false)
+ const initialized = useRef(false);
+
+ useEffect(() => {
+ if (showMain()) {
+ console.log("Start Notification fetcher");
+ const controller = new AbortController();
+ NotificationApi.notification(controller);
+ return () => {
+ console.log("Stop Notification fetcher");
+ controller.abort();
+ };
+ }
+ }, [readiness]);
useEffect(() => {
- console.log("Main");
if (!initialized.current) {
initialized.current = true
effect()
@@ -55,7 +67,6 @@ export function Main() {
}, [])
function effect() {
- console.log("Main effect start");
KaravanApi.getAuthType((authType: string) => {
console.log("authType", authType);
if (authType === 'oidc') {
@@ -67,9 +78,6 @@ export function Main() {
}
getData();
});
- return () => {
- console.log("Main effect end");
- };
}
function showSpinner() {
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 5f4216e3..166bdaaf 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
@@ -41,7 +41,8 @@ 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";
+import {DslPosition, EventBus} from "../../designer/utils/EventBus";
+import {KaravanEvent, NotificationEventBus} from "../../api/NotificationService";
export function FileToolbar () {
@@ -49,17 +50,28 @@ export function FileToolbar () {
const [commitMessageIsOpen, setCommitMessageIsOpen] = useState(false);
const [pullIsOpen, setPullIsOpen] = useState(false);
const [commitMessage, setCommitMessage] = useState('');
- const [project, isPushing, isPulling] = useProjectStore((s) => [s.project, s.isPushing, s.isPulling], shallow )
+ const [project, isPushing, isPulling] =
+ useProjectStore((s) => [s.project, s.isPushing, s.isPulling], shallow )
const {files} = useFilesStore();
const [file, editAdvancedProperties, setEditAdvancedProperties, setAddProperty, setFile] = useFileStore((s) =>
[s.file, s.editAdvancedProperties, s.setEditAdvancedProperties, s.setAddProperty, s.setFile], shallow )
+ // useEffect(() => {
+ // const sub1 = NotificationEventBus.onEvent()?.subscribe((evt: KaravanEvent) => {
+ // console.log(evt);
+ // setIsPushing(false);
+ // });
+ // return () => {
+ // sub1?.unsubscribe();
+ // };
+ // });
useEffect(() => {
}, [project, file]);
function push () {
setCommitMessageIsOpen(false);
+ useProjectStore.setState({isPushing: true});
ProjectService.pushProject(project, commitMessage);
}
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
index 99d62b43..6e7de890 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
@@ -48,11 +48,9 @@ export function ProjectLogPanel () {
const f = LogWatchApi.fetchData(type, podName, controller).then(value => {
console.log("Fetch Started for: " + podName)
});
- console.log("new fetch")
setFetch(f);
}
return () => {
- console.log("end");
controller.abort();
};
}, [showLog, type, podName]);