Skip to content

Commit

Permalink
switch to notificatino factory
Browse files Browse the repository at this point in the history
  • Loading branch information
KochTobi committed Sep 2, 2024
1 parent bd65c7d commit a6372b3
Show file tree
Hide file tree
Showing 26 changed files with 287 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import static life.qbic.logging.service.LoggerFactory.logger;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import life.qbic.application.commons.Result;
import life.qbic.logging.api.Logger;
Expand All @@ -13,7 +11,6 @@
import life.qbic.projectmanagement.application.batch.SampleUpdateRequest;
import life.qbic.projectmanagement.domain.model.project.ProjectId;
import life.qbic.projectmanagement.domain.model.sample.Sample;
import life.qbic.projectmanagement.domain.model.sample.SampleCode;
import life.qbic.projectmanagement.domain.model.sample.SampleRegistrationRequest;
import life.qbic.projectmanagement.domain.service.SampleDomainService;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.vaadin.flow.component.html.Span;
import life.qbic.datamanager.views.notifications.NotificationDialog;
import life.qbic.datamanager.views.notifications.NotificationLevel;

/**
* Warns the user that the personal access token will be deleted and cannot be used
Expand All @@ -11,7 +12,7 @@
public class AccessTokenDeletionConfirmationNotification extends NotificationDialog {

public AccessTokenDeletionConfirmationNotification() {
super(Type.WARNING);
super(NotificationLevel.WARNING);
withTitle("Personal Access Token will be deleted");
withContent(new Span(
"Deleting this Personal Access Token will make it unusable. Proceed?"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import life.qbic.datamanager.views.account.PersonalAccessTokenComponent.DeleteTokenEvent;
import life.qbic.datamanager.views.account.PersonalAccessTokenComponent.PersonalAccessTokenFrontendBean;
import life.qbic.datamanager.views.general.Main;
import life.qbic.datamanager.views.notifications.toasts.MessageSourceToastFactory;
import life.qbic.datamanager.views.notifications.toasts.Toast;
import life.qbic.datamanager.views.notifications.MessageSourceNotificationFactory;
import life.qbic.datamanager.views.notifications.Toast;
import life.qbic.identity.api.PersonalAccessToken;
import life.qbic.identity.api.PersonalAccessTokenService;
import life.qbic.identity.api.RawToken;
Expand Down Expand Up @@ -48,18 +48,18 @@ public class PersonalAccessTokenMain extends Main implements BeforeEnterObserver
private final PersonalAccessTokenComponent personalAccessTokenComponent;
private final PersonalAccessTokenService personalAccessTokenService;
private final AuthenticationToUserIdTranslationService userIdTranslator;
private final life.qbic.datamanager.views.notifications.toasts.MessageSourceToastFactory messageSourceToastFactory;
private final MessageSourceNotificationFactory messageSourceNotificationFactory;

public PersonalAccessTokenMain(PersonalAccessTokenService personalAccessTokenService,
PersonalAccessTokenComponent personalAccessTokenComponent,
AuthenticationToUserIdTranslationService userIdTranslator,
MessageSourceToastFactory messageSourceToastFactory) {
MessageSourceNotificationFactory messageSourceNotificationFactory) {
this.personalAccessTokenService = requireNonNull(personalAccessTokenService,
"personalAccessTokenService must not be null");
this.personalAccessTokenComponent = requireNonNull(personalAccessTokenComponent,
"personalAccessTokenComponent must not be null");
this.userIdTranslator = requireNonNull(userIdTranslator, "userIdTranslator must not be null");
this.messageSourceToastFactory = requireNonNull(messageSourceToastFactory,
this.messageSourceNotificationFactory = requireNonNull(messageSourceNotificationFactory,
"messageSourceToastFactory must not be null");

addClassName("personal-access-token");
Expand Down Expand Up @@ -103,7 +103,7 @@ private void onAddTokenClicked(AddTokenEvent addTokenEvent) {
.tokenDescription(), event.personalAccessTokenDTO().expirationDate());
personalAccessTokenComponent.showCreatedToken(createdToken);
event.getSource().close();
Toast toast = messageSourceToastFactory.create("personal-access-token.created.success",
Toast toast = messageSourceNotificationFactory.toast("personal-access-token.created.success",
new Object[]{event.personalAccessTokenDTO().tokenDescription()}, getLocale());
toast.open();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import life.qbic.datamanager.security.UserPermissions;
import life.qbic.datamanager.views.AppRoutes.Projects;
import life.qbic.datamanager.views.Context;
import life.qbic.datamanager.views.notifications.toasts.MessageSourceToastFactory;
import life.qbic.datamanager.views.notifications.toasts.Toast;
import life.qbic.datamanager.views.notifications.MessageSourceNotificationFactory;
import life.qbic.datamanager.views.notifications.Toast;
import life.qbic.datamanager.views.projects.overview.ProjectOverviewMain;
import life.qbic.datamanager.views.projects.project.ProjectMainLayout;
import life.qbic.datamanager.views.projects.project.experiments.ExperimentInformationMain;
Expand Down Expand Up @@ -76,7 +76,7 @@ public class ProjectSideNavigationComponent extends Div implements
private final transient ExperimentInformationService experimentInformationService;
private final AddExperimentToProjectService addExperimentToProjectService;
private final transient UserPermissions userPermissions;
private final MessageSourceToastFactory messageSourceToastFactory;
private final MessageSourceNotificationFactory messageSourceNotificationFactory;
private final TerminologyService terminologyService;
private final SpeciesLookupService speciesLookupService;
private Context context = new Context();
Expand All @@ -88,13 +88,13 @@ public ProjectSideNavigationComponent(
UserPermissions userPermissions,
SpeciesLookupService speciesLookupService,
TerminologyService terminologyService,
MessageSourceToastFactory messageSourceToastFactory) {
MessageSourceNotificationFactory messageSourceNotificationFactory) {
content = new Div();
requireNonNull(projectInformationService);
requireNonNull(experimentInformationService);
requireNonNull(addExperimentToProjectService);
this.messageSourceToastFactory = requireNonNull(messageSourceToastFactory,
"messageSourceToastFactory must not be null");
this.messageSourceNotificationFactory = requireNonNull(messageSourceNotificationFactory,
"messageSourceNotificationFactory must not be null");
this.speciesLookupService = speciesLookupService;
this.addExperimentToProjectService = addExperimentToProjectService;
this.userPermissions = requireNonNull(userPermissions, "userPermissions must not be null");
Expand Down Expand Up @@ -361,7 +361,7 @@ private ExperimentId createExperiment(ProjectId projectId,
}

private void displayExperimentCreationSuccess(String experimentName) {
Toast toast = messageSourceToastFactory.create("experiment.created.success",
Toast toast = messageSourceNotificationFactory.toast("experiment.created.success",
new Object[]{experimentName}, getLocale());
toast.open();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package life.qbic.datamanager.views.notifications;

import static java.util.Objects.isNull;
import static life.qbic.logging.service.LoggerFactory.logger;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.router.RouteParameters;
import com.vaadin.flow.spring.annotation.SpringComponent;
import java.time.Duration;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.Optional;
import life.qbic.logging.api.Logger;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;

/**
* TODO!
* <b>short description</b>
*
* <p>detailed description</p>
*
* @since <version tag>
*/
@SpringComponent
public class MessageSourceNotificationFactory {

private static final Logger log = logger(MessageSourceNotificationFactory.class);
public static final Object[] EMPTY_PARAMETERS = new Object[]{};
private static final String DEFAULT_CONFIRM_TEXT = "Okay";
private final MessageSource messageSource;

public MessageSourceNotificationFactory(MessageSource messageSource) {
this.messageSource = messageSource;
}

public Toast toast(String key, Object[] parameters, Locale locale) {
MessageType type = parseMessageType(key, locale);
String messageText = parseMessage(key, parameters, locale);

Component content = switch (type) {
case HTML -> new Html("<div style=\"display:contents\">%s</div>".formatted(messageText));
case TEXT -> new Span(messageText);
};

NotificationLevel level = parseLevel(key, locale);
Duration duration = parseDuration(key, locale).orElse(Toast.DEFAULT_OPEN_DURATION);

Toast toast = new Toast(level);
toast.withContent(content);
toast.setDuration(duration);

return toast;
}

public Toast routingToast(String key, Object[] messageArgs, Object[] routeArgs,
Class<? extends Component> navigationTarget, RouteParameters routeParameters, Locale locale) {
var toast = toast(key, messageArgs, locale);
String linkText = parseLinkText(key, routeArgs, locale);
return toast.withRouting(linkText, navigationTarget, routeParameters);
}

public NotificationDialog dialog(String key, Object[] parameters, Locale locale) {
MessageType type = parseMessageType(key, locale);
String messageText = parseMessage(key, parameters, locale);
Component content = switch (type) {
case HTML -> new Html("<div style=\"display:contents\">%s</div>".formatted(messageText));
case TEXT -> new Span(messageText);
};

NotificationLevel level = parseLevel(key, locale);
NotificationDialog notificationDialog = new NotificationDialog(level)
.withContent(content);
parseTitle(key, locale).ifPresent(notificationDialog::withTitle);
parseConfirmText(key, locale).ifPresentOrElse(
notificationDialog::setConfirmText,
() -> notificationDialog.setConfirmText(DEFAULT_CONFIRM_TEXT));

return notificationDialog;
}

private NotificationLevel parseLevel(String key, Locale locale) {
String levelProperty;
try {
levelProperty = messageSource.getMessage("%s.level".formatted(key),
EMPTY_PARAMETERS, locale);
} catch (NoSuchMessageException e) {
throw new RuntimeException("Missing level info for %s.".formatted(key));
}

try {
return NotificationLevel.valueOf(levelProperty.trim().toUpperCase());
} catch (IllegalArgumentException e) {
throw new RuntimeException(
"Could not parse toast level for key %s: %s".formatted(key, levelProperty));
}
}

private String parseMessage(String key, Object[] parameters, Locale locale) {
try {
return messageSource.getMessage("%s.message.text".formatted(key),
parameters, locale).strip();
} catch (NoSuchMessageException e) {
throw new RuntimeException("No message specified for " + key, e);
}
}

private MessageType parseMessageType(String key, Locale locale) {
try {
String messageType = messageSource.getMessage("%s.message.type".formatted(key),
EMPTY_PARAMETERS, locale).strip().toUpperCase();
return MessageType.valueOf(messageType);
} catch (NoSuchMessageException e) {
throw new RuntimeException("No message type specified for " + key, e);
}
}

private Optional<String> parseTitle(String key, Locale locale) {
try {
return Optional.of(messageSource.getMessage("%s.title".formatted(key),
EMPTY_PARAMETERS, locale).strip());
} catch (NoSuchMessageException e) {
log.warn("No title specified for %s.title".formatted(key));
return Optional.empty();
}
}

private Optional<Duration> parseDuration(String key, Locale locale) {
String durationProperty = messageSource.getMessage("%s.duration".formatted(key),
EMPTY_PARAMETERS, null, locale);
if (isNull(durationProperty)) {
return Optional.empty();
}
try {
return Optional.of(Duration.parse(durationProperty));
} catch (DateTimeParseException e) {
log.warn("Could not parse duration for key %s: %s".formatted(key, durationProperty));
return Optional.empty();
}
}

private String parseLinkText(String key, Object[] routeArgs, Locale locale) {
String linkText;
try {
linkText = messageSource.getMessage("%s.routing.link.text".formatted(key),
routeArgs, locale).strip();
} catch (NoSuchMessageException e) {
throw new RuntimeException("No link text specified for " + key, e);
}
return linkText;
}

private Optional<String> parseConfirmText(String key, Locale locale) {
return Optional.ofNullable(messageSource.getMessage("%s.confirm-text".formatted(key),
new Object[]{}, null, locale));
}

private enum MessageType {
HTML,
TEXT
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package life.qbic.datamanager.views.notifications.toasts;
package life.qbic.datamanager.views.notifications;

import static java.util.Objects.isNull;

Expand All @@ -11,7 +11,6 @@
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.Optional;
import life.qbic.datamanager.views.notifications.toasts.Toast.Level;
import life.qbic.logging.api.Logger;
import life.qbic.logging.service.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
Expand Down Expand Up @@ -55,7 +54,7 @@ public MessageSourceToastFactory(@Qualifier("messageSource") MessageSource messa
* @param locale the locale for which to load the message
* @return a Toast with loaded content
*/
public Toast create(String key, Object[] parameters, Locale locale) {
private Toast create(String key, Object[] parameters, Locale locale) {
MessageType type = parseMessageType(key, locale);
String messageText = parseMessage(key, parameters, locale);

Expand All @@ -64,7 +63,7 @@ public Toast create(String key, Object[] parameters, Locale locale) {
case TEXT -> new Span(messageText);
};

Level level = parseLevel(key, locale);
NotificationLevel level = parseLevel(key, locale);
Duration duration = parseDuration(key, locale).orElse(Toast.DEFAULT_OPEN_DURATION);

Toast toast = new Toast(level);
Expand Down Expand Up @@ -93,7 +92,7 @@ private MessageType parseMessageType(String key, Locale locale) {
}
}

private Level parseLevel(String key, Locale locale) {
private NotificationLevel parseLevel(String key, Locale locale) {
String levelProperty;
try {
levelProperty = messageSource.getMessage("%s.level".formatted(key),
Expand All @@ -103,7 +102,7 @@ private Level parseLevel(String key, Locale locale) {
}

try {
return Level.valueOf(levelProperty.trim().toUpperCase());
return NotificationLevel.valueOf(levelProperty.trim().toUpperCase());
} catch (IllegalArgumentException e) {
throw new RuntimeException(
"Could not parse toast level for key %s: %s".formatted(key, levelProperty));
Expand Down Expand Up @@ -150,7 +149,7 @@ private Optional<Duration> parseDuration(String key, Locale locale) {
* @return a Toast with loaded content
* @see #create(String, Object[], Locale)
*/
public Toast createRouting(String key, Object[] messageArgs, Object[] routeArgs,
private Toast createRouting(String key, Object[] messageArgs, Object[] routeArgs,
Class<? extends Component> navigationTarget,
RouteParameters routeParameters, Locale locale) {
var toast = create(key, messageArgs, locale);
Expand Down
Loading

0 comments on commit a6372b3

Please sign in to comment.