From 5146ec9d2f1bcde64dc994b7b5837eeec2923f18 Mon Sep 17 00:00:00 2001 From: Dmitry Kremnev Date: Tue, 24 Mar 2026 16:00:46 +0400 Subject: [PATCH] Add UI action to render MessageTemplate with selected entities to validate parameters jmix-framework/jmix_4892 --- .../MessageTemplateDetailView.java | 8 ++ .../MessageTemplateListView.java | 9 ++ .../MessageTemplatePreviewView.java | 91 ++++++++++++++++++ .../MessageTemplatesPreviewer.java | 94 +++++++++++++++++++ .../messages.properties | 5 + .../message-template-detail-view.xml | 4 +- .../message-template-list-view.xml | 3 + .../message-template-preview-view.xml | 32 +++++++ .../messages.properties | 5 + .../messages_ru.properties | 5 + 10 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatePreviewView.java create mode 100644 jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatesPreviewer.java create mode 100644 jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/message-template-preview-view.xml diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateDetailView.java b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateDetailView.java index 5ab3ba1904..f7408e5828 100644 --- a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateDetailView.java +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateDetailView.java @@ -42,6 +42,7 @@ import io.jmix.messagetemplatesflowui.kit.component.GrapesJsBlock; import io.jmix.messagetemplatesflowui.view.htmleditor.HtmlEditorView; import io.jmix.messagetemplatesflowui.view.messagetemplateparameter.MessageTemplateParameterDetailView; +import io.jmix.messagetemplatesflowui.view.messagetemplatepreview.MessageTemplatesPreviewer; import org.springframework.beans.factory.annotation.Autowired; import java.nio.charset.StandardCharsets; @@ -79,6 +80,8 @@ public class MessageTemplateDetailView extends StandardDetailView event) { + messageTemplatesPreviewer.showPreview(getEditedEntity(), this); + } } diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateListView.java b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateListView.java index c59f36f082..a77de47ac6 100644 --- a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateListView.java +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplate/MessageTemplateListView.java @@ -41,6 +41,7 @@ import io.jmix.messagetemplates.entity.MessageTemplateParameter; import io.jmix.messagetemplates.entity.TemplateType; import io.jmix.messagetemplatesflowui.accesscontext.UiImportExportMessageTemplateContext; +import io.jmix.messagetemplatesflowui.view.messagetemplatepreview.MessageTemplatesPreviewer; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,6 +102,8 @@ public class MessageTemplateListView extends StandardListView { protected Downloader downloader; @Autowired protected Notifications notifications; + @Autowired + protected MessageTemplatesPreviewer messageTemplatesPreviewer; protected boolean isCreatePermitted; protected boolean isImportExportPermitted; @@ -146,6 +149,12 @@ public void onMessageTemplatesDataGridCopy(ActionPerformedEvent event) { } } + @Subscribe("messageTemplatesDataGrid.preview") + public void onMessageTemplatesDataGridPreview(ActionPerformedEvent event) { + MessageTemplate selectedItem = messageTemplatesDataGrid.getSingleSelectedItem(); + messageTemplatesPreviewer.showPreview(selectedItem, this); + } + @Subscribe("importField") public void onImportFileUploadSucceeded(FileUploadSucceededEvent event) { byte[] fileBytes = event.getSource().getValue(); diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatePreviewView.java b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatePreviewView.java new file mode 100644 index 0000000000..297fb17267 --- /dev/null +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatePreviewView.java @@ -0,0 +1,91 @@ +/* + * Copyright 2026 Haulmont. + * + * Licensed 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 io.jmix.messagetemplatesflowui.view.messagetemplatepreview; + +import com.vaadin.flow.component.ClickEvent; +import com.vaadin.flow.component.Html; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import io.jmix.flowui.UiComponents; +import io.jmix.flowui.component.textarea.JmixTextArea; +import io.jmix.flowui.download.DownloadFormat; +import io.jmix.flowui.download.Downloader; +import io.jmix.flowui.kit.component.button.JmixButton; +import io.jmix.flowui.view.*; +import io.jmix.messagetemplates.entity.TemplateType; +import org.springframework.beans.factory.annotation.Autowired; + +import java.nio.charset.StandardCharsets; + +@ViewController("msgtmp_MessageTemplatePreviewView") +@ViewDescriptor("message-template-preview-view.xml") +@DialogMode(resizable = true) +public class MessageTemplatePreviewView extends StandardView { + + @Autowired + protected UiComponents uiComponents; + @Autowired + protected Downloader downloader; + + @ViewComponent + protected VerticalLayout contentBox; + @ViewComponent + protected JmixButton openInNewTabButton; + + protected TemplateType type; + protected String content; + + @Subscribe + public void onInit(InitEvent event) { + downloader.setShowNewWindow(true); + } + + public void setPreviewContent(TemplateType type, String content) { + this.type = type; + this.content = content; + } + + @Subscribe + public void onBeforeShow(BeforeShowEvent event) { + if (TemplateType.HTML.equals(type)) { + initHtmlLayout(); + } else { + initTextLayout(); + } + } + + protected void initHtmlLayout() { + openInNewTabButton.setVisible(true); + + //
wrapping required to avoid 'HTML must contain exactly one top-level element' exception + Html html = new Html("
%s
".formatted(content)); + contentBox.addAndExpand(html); + } + + protected void initTextLayout() { + JmixTextArea textArea = uiComponents.create(JmixTextArea.class); + + textArea.setReadOnly(true); + textArea.setWidth("60em"); + textArea.setValue(content); + contentBox.addAndExpand(textArea); + } + + @Subscribe("openInNewTabButton") + public void onOpenInNewTabButtonClick(ClickEvent event) { + downloader.download(content.getBytes(StandardCharsets.UTF_8), "preview.html", DownloadFormat.HTML); + } +} diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatesPreviewer.java b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatesPreviewer.java new file mode 100644 index 0000000000..f3da4c5841 --- /dev/null +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/java/io/jmix/messagetemplatesflowui/view/messagetemplatepreview/MessageTemplatesPreviewer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2026 Haulmont. + * + * Licensed 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 io.jmix.messagetemplatesflowui.view.messagetemplatepreview; + +import io.jmix.core.annotation.Internal; +import io.jmix.flowui.DialogWindows; +import io.jmix.flowui.view.StandardOutcome; +import io.jmix.flowui.view.View; +import io.jmix.messagetemplates.MessageTemplatesGenerator; +import io.jmix.messagetemplates.entity.MessageTemplate; +import io.jmix.messagetemplatesflowui.view.parametersinputdialog.MessageTemplateParametersInputDialog; +import org.jspecify.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.Map; + +/** + * Provides functionality for previewing {@link MessageTemplate}. + *

+ * Allows users to enter parameters used for generating a message preview + * and displays the result in a dialog. + *

+ * This is an internal component and is not intended for direct use in application code. + */ +@Internal +@Component("msgtmp_MessageTemplatesPreviewer") +public class MessageTemplatesPreviewer { + + @Autowired + protected MessageTemplatesGenerator messageTemplatesGenerator; + @Autowired + protected DialogWindows dialogWindows; + + /** + * Opens a preview for the specified message template. + *

+ * If the template contains parameters, a dialog for parameter input is shown first. + * After confirmation, the template is generated and the result is displayed. + * + * @param messageTemplate the message template (can be {@code null}) + * @param origin the originating view used to open dialogs + */ + public void showPreview(@Nullable MessageTemplate messageTemplate, View origin) { + if (messageTemplate == null) { + return; + } + + if (!messageTemplate.getParameters().isEmpty()) { + dialogWindows.view(origin, MessageTemplateParametersInputDialog.class) + .withViewConfigurer(view -> + view.setTemplateParameters(messageTemplate.getParameters())) + .withAfterCloseListener(event -> { + if (event.closedWith(StandardOutcome.SAVE)) { + showTemplate(messageTemplate, event.getView().getParameters(), origin); + } + }) + .open(); + } else { + showTemplate(messageTemplate, Collections.emptyMap(), origin); + } + } + + /** + * Generates the message template using the provided parameters + * and displays the result in the preview dialog. + * + * @param template the message template + * @param parameters parameters used for generation + * @param origin the originating view + */ + protected void showTemplate(MessageTemplate template, Map parameters, View origin) { + String content = messageTemplatesGenerator.generateMessage(template, parameters); + + dialogWindows.view(origin, MessageTemplatePreviewView.class) + .withViewConfigurer(view -> view.setPreviewContent(template.getType(), content)) + .open(); + } +} diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/messages.properties b/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/messages.properties index 8333012b5d..ab86c4fa5e 100644 --- a/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/messages.properties +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/messages.properties @@ -21,10 +21,12 @@ io.jmix.messagetemplatesflowui.view.messagetemplategroup/MessageTemplateGroupDet io.jmix.messagetemplatesflowui.view.messagetemplateblock/MessageTemplateBlockListView.title=Template blocks io.jmix.messagetemplatesflowui.view.messagetemplateblock/MessageTemplateBlockDetailView.title=Template block io.jmix.messagetemplatesflowui.view.messagetemplateparameter/MessageTemplateParameterDetailView.title=Template parameter +io.jmix.messagetemplatesflowui.view.messagetemplatepreview/MessageTemplatePreviewView.title=Preview io.jmix.messagetemplatesflowui.view.parametersinputdialog/MessageTemplateParametersInputDialog.title=Input parameters io.jmix.messagetemplatesflowui.view.messagetemplate/exportButton.text=Export io.jmix.messagetemplatesflowui.view.messagetemplate/messageTemplatesDataGrid.copyAction.text=Copy +io.jmix.messagetemplatesflowui.view.messagetemplate/messageTemplatesDataGrid.previewAction.text=Preview io.jmix.messagetemplatesflowui.view.messagetemplate/messageTemplatesDataGrid.exportJsonAction.text=Export as JSON io.jmix.messagetemplatesflowui.view.messagetemplate/messageTemplatesDataGrid.exportZipAction.text=Export as ZIP io.jmix.messagetemplatesflowui.view.messagetemplate/importField.uploadText=Import @@ -39,6 +41,7 @@ io.jmix.messagetemplatesflowui.view.messagetemplate/mainTabSheet.parametersTab.l io.jmix.messagetemplatesflowui.view.messagetemplate/importTemplateField.title=Import HTML io.jmix.messagetemplatesflowui.view.messagetemplate/editCodeBtn.title=Edit HTML io.jmix.messagetemplatesflowui.view.messagetemplate/viewBtn.title=View HTML +io.jmix.messagetemplatesflowui.view.messagetemplate/previewButton.text=Preview io.jmix.messagetemplatesflowui.view.messagetemplate/plainTextArea.header=Template content io.jmix.messagetemplatesflowui.view.messagetemplate/emptyContentValidationMessage=Template content must not be blank @@ -49,6 +52,8 @@ io.jmix.messagetemplatesflowui.view.messagetemplateparameter/mainTabSheet.detail io.jmix.messagetemplatesflowui.view.messagetemplateparameter/mainTabSheet.localizationTab.label=Localization io.jmix.messagetemplatesflowui.view.messagetemplateparameter/uniqueAliasValidationMessage=A parameter with the same alias already exist +io.jmix.messagetemplatesflowui.view.messagetemplatepreview/openInNewTabButton.text=Open in new tab + io.jmix.messagetemplatesflowui.view.messagetemplateparameter.model/MessageTemplateParameterLocalization=Message template parameter localization io.jmix.messagetemplatesflowui.view.messagetemplateparameter.model/MessageTemplateParameterLocalization.id=ID io.jmix.messagetemplatesflowui.view.messagetemplateparameter.model/MessageTemplateParameterLocalization.locale=Locale diff --git a/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/view/messagetemplate/message-template-detail-view.xml b/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/view/messagetemplate/message-template-detail-view.xml index f34cc8a01d..e1e3888d4e 100644 --- a/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/view/messagetemplate/message-template-detail-view.xml +++ b/jmix-messagetemplates/messagetemplates-flowui/src/main/resources/io/jmix/messagetemplatesflowui/view/messagetemplate/message-template-detail-view.xml @@ -77,8 +77,8 @@ +