Erweiterungen
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
/* Breite des linken Menüs (Drawer) */
|
||||||
|
vaadin-app-layout {
|
||||||
|
--vaadin-app-layout-drawer-width: 286px;
|
||||||
|
}
|
||||||
@@ -114,10 +114,14 @@ public class MessageController {
|
|||||||
*/
|
*/
|
||||||
public void handleGetAssignedJobs(String appUserId) {
|
public void handleGetAssignedJobs(String appUserId) {
|
||||||
if (appUserId == null || appUserId.isBlank()) {
|
if (appUserId == null || appUserId.isBlank()) {
|
||||||
|
log.warn("[JOBS] appUserId is null or blank, cannot retrieve jobs");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("[JOBS] Retrieving assigned jobs for appUserId: {}", appUserId);
|
||||||
|
|
||||||
List<Job> assignedJobs = jobRepository.findByAppUser(appUserId);
|
List<Job> assignedJobs = jobRepository.findByAppUser(appUserId);
|
||||||
|
log.info("[JOBS] Found {} jobs for appUserId: {}", assignedJobs.size(), appUserId);
|
||||||
|
|
||||||
List<JobWithRelatedDataDTO> jobsWithRelatedData = assignedJobs.stream().map(job -> {
|
List<JobWithRelatedDataDTO> jobsWithRelatedData = assignedJobs.stream().map(job -> {
|
||||||
List<CargoItem> cargoItems = cargoItemRepository.findByJobId(job.getId());
|
List<CargoItem> cargoItems = cargoItemRepository.findByJobId(job.getId());
|
||||||
@@ -125,7 +129,9 @@ public class MessageController {
|
|||||||
return new JobWithRelatedDataDTO(job, cargoItems, tasks);
|
return new JobWithRelatedDataDTO(job, cargoItems, tasks);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
log.info("[JOBS] Publishing {} jobs to client {} on topic /client/jobs", jobsWithRelatedData.size(), appUserId);
|
||||||
messagingPublisher.publishAsJson(appUserId, "jobs", jobsWithRelatedData);
|
messagingPublisher.publishAsJson(appUserId, "jobs", jobsWithRelatedData);
|
||||||
|
log.info("[JOBS] Jobs published successfully for client {}", appUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -109,26 +109,35 @@ public class MessagingConfig {
|
|||||||
|
|
||||||
if (response.isSuccess()) {
|
if (response.isSuccess()) {
|
||||||
String appUserId = response.getAppUserId();
|
String appUserId = response.getAppUserId();
|
||||||
|
log.info("[Messaging] Login successful for appUserId: {}", appUserId);
|
||||||
|
|
||||||
webSocketService.registerAuthenticatedSession(wsSessionId, appUserId);
|
webSocketService.registerAuthenticatedSession(wsSessionId, appUserId);
|
||||||
|
|
||||||
// Send success response to the now-authenticated session
|
// Send success response to the now-authenticated session
|
||||||
// locationTrackingEnabled: true = client should send position updates
|
// locationTrackingEnabled: true = client should send position updates
|
||||||
Map<String, Object> authResponse = Map.of("success", true, "message", response.getMessage(),
|
// appUserId: wird an den Client gesendet für Referenz
|
||||||
"locationTrackingEnabled", true);
|
Map<String, Object> authResponse = Map.of(
|
||||||
|
"success", true,
|
||||||
|
"message", response.getMessage(),
|
||||||
|
"locationTrackingEnabled", true,
|
||||||
|
"appUserId", appUserId
|
||||||
|
);
|
||||||
byte[] responseBytes = objectMapper.writeValueAsBytes(authResponse);
|
byte[] responseBytes = objectMapper.writeValueAsBytes(authResponse);
|
||||||
|
log.info("[Messaging] Sending auth response to appUserId: {}", appUserId);
|
||||||
webSocketService.sendToClient(appUserId, "auth", responseBytes);
|
webSocketService.sendToClient(appUserId, "auth", responseBytes);
|
||||||
|
|
||||||
// Register client - pending messages and jobs will be sent after
|
// Register client - pending messages and jobs will be sent after
|
||||||
// client confirms buffer_flushed
|
// client confirms buffer_flushed
|
||||||
clientConnectionService.registerClient(appUserId);
|
clientConnectionService.registerClient(appUserId);
|
||||||
} else {
|
} else {
|
||||||
|
log.warn("[Messaging] Login failed: {}", response.getMessage());
|
||||||
// Send failure response to the pending session
|
// Send failure response to the pending session
|
||||||
Map<String, Object> authResponse = Map.of("success", false, "message", response.getMessage());
|
Map<String, Object> authResponse = Map.of("success", false, "message", response.getMessage());
|
||||||
byte[] responseBytes = objectMapper.writeValueAsBytes(authResponse);
|
byte[] responseBytes = objectMapper.writeValueAsBytes(authResponse);
|
||||||
webSocketService.sendToSessionById(wsSessionId, "/client/auth", responseBytes);
|
webSocketService.sendToSessionById(wsSessionId, "/client/auth", responseBytes);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[Messaging] Login handling error: {}", e.getMessage());
|
log.error("[Messaging] Login handling error: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,16 +28,29 @@ class MessagingPublisherImpl implements MessagingPublisher {
|
|||||||
@Override
|
@Override
|
||||||
public void publishAsJson(String clientId, String messageType, Object payload) {
|
public void publishAsJson(String clientId, String messageType, Object payload) {
|
||||||
try {
|
try {
|
||||||
|
// Prüfen ob Client verbunden ist
|
||||||
|
boolean isConnected = webSocketService.isClientConnected(clientId);
|
||||||
|
log.debug("[Messaging] Publishing to {}/{} - connected: {}", clientId, messageType, isConnected);
|
||||||
|
|
||||||
|
if (!isConnected) {
|
||||||
|
log.warn("[Messaging] Client {} is not connected, cannot send {}", clientId, messageType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String json = objectMapper.writeValueAsString(payload);
|
String json = objectMapper.writeValueAsString(payload);
|
||||||
byte[] data = json.getBytes(StandardCharsets.UTF_8);
|
byte[] data = json.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
webSocketService.sendToClient(clientId, messageType, data).exceptionally(ex -> {
|
webSocketService.sendToClient(clientId, messageType, data)
|
||||||
log.error("[Messaging] Failed to deliver to {}/{}: {}", clientId, messageType, ex.getMessage());
|
.thenRun(() -> {
|
||||||
return null;
|
log.debug("[Messaging] Successfully sent {}/{} to client {}", messageType, clientId);
|
||||||
});
|
})
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
log.error("[Messaging] Failed to deliver to {}/{}: {}", clientId, messageType, ex.getMessage(), ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[Messaging] Failed to publish to {}/{}: {}", clientId, messageType, e.getMessage());
|
log.error("[Messaging] Failed to publish to {}/{}: {}", clientId, messageType, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,9 +129,19 @@ public class WebSocketService extends TextWebSocketHandler {
|
|||||||
|
|
||||||
public CompletableFuture<Void> sendToClient(String clientId, String messageType, byte[] payload) {
|
public CompletableFuture<Void> sendToClient(String clientId, String messageType, byte[] payload) {
|
||||||
WebSocketSession session = clientSessions.get(clientId);
|
WebSocketSession session = clientSessions.get(clientId);
|
||||||
if (session == null || !session.isOpen()) {
|
if (session == null) {
|
||||||
|
log.warn("[WebSocket] No session found for client {}", clientId);
|
||||||
return CompletableFuture
|
return CompletableFuture
|
||||||
.failedFuture(new IOException("No active WebSocket session for client: " + clientId));
|
.failedFuture(new IOException("No WebSocket session for client: " + clientId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session.isOpen()) {
|
||||||
|
log.warn("[WebSocket] Session for client {} is closed", clientId);
|
||||||
|
// Session aus der Map entfernen
|
||||||
|
clientSessions.remove(clientId);
|
||||||
|
sessionToClient.remove(session.getId());
|
||||||
|
return CompletableFuture
|
||||||
|
.failedFuture(new IOException("WebSocket session closed for client: " + clientId));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -143,12 +153,13 @@ public class WebSocketService extends TextWebSocketHandler {
|
|||||||
wireMessage.set("payload", objectMapper.readTree(payloadJson));
|
wireMessage.set("payload", objectMapper.readTree(payloadJson));
|
||||||
|
|
||||||
String wireJson = objectMapper.writeValueAsString(wireMessage);
|
String wireJson = objectMapper.writeValueAsString(wireMessage);
|
||||||
log.info("[WebSocket OUT] {} -> {}", topic, wireJson);
|
log.info("[WebSocket OUT] {} to client {} (session open: {})", topic, clientId, session.isOpen());
|
||||||
|
|
||||||
sendToSession(session, wireJson);
|
sendToSession(session, wireJson);
|
||||||
|
log.debug("[WebSocket] Message sent successfully to client {}", clientId);
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[WebSocket] Failed to send to client {}: {}", clientId, e.getMessage());
|
log.error("[WebSocket] Failed to send to client {}: {}", clientId, e.getMessage(), e);
|
||||||
return CompletableFuture.failedFuture(new IOException("Failed to send WebSocket message", e));
|
return CompletableFuture.failedFuture(new IOException("Failed to send WebSocket message", e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import de.assecutor.votianlt.pages.service.UserInvoiceDataService;
|
|||||||
import de.assecutor.votianlt.pages.view.EditProfileView;
|
import de.assecutor.votianlt.pages.view.EditProfileView;
|
||||||
import de.assecutor.votianlt.model.Language;
|
import de.assecutor.votianlt.model.Language;
|
||||||
import de.assecutor.votianlt.security.SecurityService;
|
import de.assecutor.votianlt.security.SecurityService;
|
||||||
import de.assecutor.votianlt.service.LanguageService;
|
|
||||||
import de.assecutor.votianlt.service.MessageBadgeUpdateService;
|
import de.assecutor.votianlt.service.MessageBadgeUpdateService;
|
||||||
import de.assecutor.votianlt.service.MessageService;
|
import de.assecutor.votianlt.service.MessageService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -51,7 +50,6 @@ public final class MainLayout extends AppLayout {
|
|||||||
private final MessageService messageService;
|
private final MessageService messageService;
|
||||||
private final MessageBadgeUpdateService messageBadgeUpdateService;
|
private final MessageBadgeUpdateService messageBadgeUpdateService;
|
||||||
private final AppUserService appUserService;
|
private final AppUserService appUserService;
|
||||||
private final LanguageService languageService;
|
|
||||||
private Div headerRef;
|
private Div headerRef;
|
||||||
private Scroller navRef;
|
private Scroller navRef;
|
||||||
private Component userMenuRef;
|
private Component userMenuRef;
|
||||||
@@ -61,22 +59,29 @@ public final class MainLayout extends AppLayout {
|
|||||||
|
|
||||||
public MainLayout(SecurityService securityService, UserInvoiceDataService userInvoiceDataService,
|
public MainLayout(SecurityService securityService, UserInvoiceDataService userInvoiceDataService,
|
||||||
MessageService messageService, MessageBadgeUpdateService messageBadgeUpdateService,
|
MessageService messageService, MessageBadgeUpdateService messageBadgeUpdateService,
|
||||||
AppUserService appUserService, LanguageService languageService) {
|
AppUserService appUserService) {
|
||||||
this.securityService = securityService;
|
this.securityService = securityService;
|
||||||
this.userInvoiceDataService = userInvoiceDataService;
|
this.userInvoiceDataService = userInvoiceDataService;
|
||||||
this.messageService = messageService;
|
this.messageService = messageService;
|
||||||
this.messageBadgeUpdateService = messageBadgeUpdateService;
|
this.messageBadgeUpdateService = messageBadgeUpdateService;
|
||||||
this.appUserService = appUserService;
|
this.appUserService = appUserService;
|
||||||
this.languageService = languageService;
|
|
||||||
setPrimarySection(Section.DRAWER);
|
setPrimarySection(Section.DRAWER);
|
||||||
|
|
||||||
|
// Drawer Styles für volle Höhe
|
||||||
|
getStyle().set("--vaadin-app-layout-drawer-width", "286px");
|
||||||
|
|
||||||
// Always build the drawer; keep references and toggle visibility on attach and
|
// Always build the drawer; keep references and toggle visibility on attach and
|
||||||
// after navigation
|
// after navigation
|
||||||
headerRef = createHeader();
|
headerRef = createHeader();
|
||||||
navRef = new Scroller(createSideNav());
|
|
||||||
|
// Scroller für Navigation mit maximaler Höhe
|
||||||
|
Component sideNav = createSideNav();
|
||||||
|
navRef = new Scroller(sideNav);
|
||||||
|
|
||||||
userMenuRef = createUserMenu();
|
userMenuRef = createUserMenu();
|
||||||
addToDrawer(headerRef, navRef, userMenuRef);
|
addToDrawer(headerRef, navRef, userMenuRef);
|
||||||
|
|
||||||
|
|
||||||
updateDrawerVisibility();
|
updateDrawerVisibility();
|
||||||
|
|
||||||
// Re-check on attach (new UI/session) and on every navigation cycle
|
// Re-check on attach (new UI/session) and on every navigation cycle
|
||||||
@@ -128,6 +133,8 @@ public final class MainLayout extends AppLayout {
|
|||||||
treeData.addItem(null, benutzerItem);
|
treeData.addItem(null, benutzerItem);
|
||||||
|
|
||||||
// Add children to "Verwaltung"
|
// Add children to "Verwaltung"
|
||||||
|
treeData.addItem(verwaltungItem,
|
||||||
|
new MenuTreeItem(getTranslation("nav.jobs"), "jobs", VaadinIcon.CLIPBOARD_TEXT));
|
||||||
treeData.addItem(verwaltungItem,
|
treeData.addItem(verwaltungItem,
|
||||||
new MenuTreeItem(getTranslation("nav.customers"), "customers", VaadinIcon.USERS));
|
new MenuTreeItem(getTranslation("nav.customers"), "customers", VaadinIcon.USERS));
|
||||||
treeData.addItem(verwaltungItem,
|
treeData.addItem(verwaltungItem,
|
||||||
@@ -153,6 +160,7 @@ public final class MainLayout extends AppLayout {
|
|||||||
tree = new TreeGrid<>();
|
tree = new TreeGrid<>();
|
||||||
tree.setDataProvider(new TreeDataProvider<>(treeData));
|
tree.setDataProvider(new TreeDataProvider<>(treeData));
|
||||||
tree.addClassNames(Margin.Horizontal.MEDIUM);
|
tree.addClassNames(Margin.Horizontal.MEDIUM);
|
||||||
|
tree.setHeight("435px");
|
||||||
|
|
||||||
// Custom item renderer to show icon and label with badge
|
// Custom item renderer to show icon and label with badge
|
||||||
tree.addComponentHierarchyColumn(item -> {
|
tree.addComponentHierarchyColumn(item -> {
|
||||||
@@ -350,6 +358,25 @@ public final class MainLayout extends AppLayout {
|
|||||||
super.onAttach(attachEvent);
|
super.onAttach(attachEvent);
|
||||||
UI ui = attachEvent.getUI();
|
UI ui = attachEvent.getUI();
|
||||||
|
|
||||||
|
// Drawer-Layout anpassen nach kurzer Verzögerung
|
||||||
|
ui.access(() -> {
|
||||||
|
getElement().executeJs(
|
||||||
|
"setTimeout(() => {" +
|
||||||
|
" const drawer = this.shadowRoot?.querySelector('[part=drawer]');" +
|
||||||
|
" if (drawer) {" +
|
||||||
|
" drawer.style.display = 'flex';" +
|
||||||
|
" drawer.style.flexDirection = 'column';" +
|
||||||
|
" drawer.style.height = '100vh';" +
|
||||||
|
" const scroller = drawer.querySelector('vaadin-scroller');" +
|
||||||
|
" if (scroller) {" +
|
||||||
|
" scroller.style.flex = '1 1 auto';" +
|
||||||
|
" scroller.style.minHeight = '0';" +
|
||||||
|
" }" +
|
||||||
|
" }" +
|
||||||
|
"}, 100);"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Apply user's preferred language immediately after login
|
// Apply user's preferred language immediately after login
|
||||||
applyUserLanguagePreference();
|
applyUserLanguagePreference();
|
||||||
|
|
||||||
|
|||||||
@@ -102,10 +102,11 @@ public class ClientConnectionService {
|
|||||||
*/
|
*/
|
||||||
private void sendAssignedJobs(String appUserId) {
|
private void sendAssignedJobs(String appUserId) {
|
||||||
try {
|
try {
|
||||||
|
log.info("[CLIENT] Sending assigned jobs to appUserId: {}", appUserId);
|
||||||
messageController.handleGetAssignedJobs(appUserId);
|
messageController.handleGetAssignedJobs(appUserId);
|
||||||
log.debug("[CLIENT] Sent assigned jobs to {}", appUserId);
|
log.info("[CLIENT] Assigned jobs sent successfully to {}", appUserId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[CLIENT] Error sending assigned jobs to {}: {}", appUserId, e.getMessage());
|
log.error("[CLIENT] Error sending assigned jobs to {}: {}", appUserId, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user