diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/NoCodeWidgetVelocityUtils.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/NoCodeWidgetVelocityUtils.java index e81999e8..238a92ae 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/NoCodeWidgetVelocityUtils.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/NoCodeWidgetVelocityUtils.java @@ -64,14 +64,24 @@ public class NoCodeWidgetVelocityUtils + /******************************************************************************* + ** + *******************************************************************************/ + public String icon(String iconName, String color) + { + return String.format(""" + + """, color, iconName); + } + + + /******************************************************************************* ** *******************************************************************************/ public String helpIcon() { - return (""" - - """); + return (icon("help_outline", "blue")); } @@ -81,9 +91,7 @@ public class NoCodeWidgetVelocityUtils *******************************************************************************/ public String errorIcon() { - return (""" - - """); + return (icon("error_outline", "red")); } @@ -93,9 +101,7 @@ public class NoCodeWidgetVelocityUtils *******************************************************************************/ public String warningIcon() { - return (""" - - """); + return (icon("warning", "orange")); } @@ -105,9 +111,7 @@ public class NoCodeWidgetVelocityUtils *******************************************************************************/ public String checkIcon() { - return (""" - - """); + return (icon("check", "green")); } @@ -117,9 +121,7 @@ public class NoCodeWidgetVelocityUtils *******************************************************************************/ public String pendingIcon() { - return (""" - - """); + return (icon("pending", "#0062ff")); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/branding/QBrandingMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/branding/QBrandingMetaData.java index eab6f2b3..67b5f99d 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/branding/QBrandingMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/branding/QBrandingMetaData.java @@ -35,6 +35,9 @@ public class QBrandingMetaData private String icon; private String accentColor; + private String environmentBannerText; + private String environmentBannerColor; + /******************************************************************************* @@ -244,4 +247,66 @@ public class QBrandingMetaData return (this); } + + + /******************************************************************************* + ** Getter for environmentBannerText + *******************************************************************************/ + public String getEnvironmentBannerText() + { + return (this.environmentBannerText); + } + + + + /******************************************************************************* + ** Setter for environmentBannerText + *******************************************************************************/ + public void setEnvironmentBannerText(String environmentBannerText) + { + this.environmentBannerText = environmentBannerText; + } + + + + /******************************************************************************* + ** Fluent setter for environmentBannerText + *******************************************************************************/ + public QBrandingMetaData withEnvironmentBannerText(String environmentBannerText) + { + this.environmentBannerText = environmentBannerText; + return (this); + } + + + + /******************************************************************************* + ** Getter for environmentBannerColor + *******************************************************************************/ + public String getEnvironmentBannerColor() + { + return (this.environmentBannerColor); + } + + + + /******************************************************************************* + ** Setter for environmentBannerColor + *******************************************************************************/ + public void setEnvironmentBannerColor(String environmentBannerColor) + { + this.environmentBannerColor = environmentBannerColor; + } + + + + /******************************************************************************* + ** Fluent setter for environmentBannerColor + *******************************************************************************/ + public QBrandingMetaData withEnvironmentBannerColor(String environmentBannerColor) + { + this.environmentBannerColor = environmentBannerColor; + return (this); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/QWidgetMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/QWidgetMetaData.java index f04b34d8..fc528db8 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/QWidgetMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/QWidgetMetaData.java @@ -52,6 +52,9 @@ public class QWidgetMetaData implements QWidgetMetaDataInterface private List dropdowns; private boolean storeDropdownSelections; + private boolean showReloadButton = true; + private boolean showExportButton = true; + protected Map defaultValues = new LinkedHashMap<>(); @@ -529,4 +532,66 @@ public class QWidgetMetaData implements QWidgetMetaDataInterface return (this); } + + + /******************************************************************************* + ** Getter for showReloadButton + *******************************************************************************/ + public boolean getShowReloadButton() + { + return (this.showReloadButton); + } + + + + /******************************************************************************* + ** Setter for showReloadButton + *******************************************************************************/ + public void setShowReloadButton(boolean showReloadButton) + { + this.showReloadButton = showReloadButton; + } + + + + /******************************************************************************* + ** Fluent setter for showReloadButton + *******************************************************************************/ + public QWidgetMetaData withShowReloadButton(boolean showReloadButton) + { + this.showReloadButton = showReloadButton; + return (this); + } + + + + /******************************************************************************* + ** Getter for showExportButton + *******************************************************************************/ + public boolean getShowExportButton() + { + return (this.showExportButton); + } + + + + /******************************************************************************* + ** Setter for showExportButton + *******************************************************************************/ + public void setShowExportButton(boolean showExportButton) + { + this.showExportButton = showExportButton; + } + + + + /******************************************************************************* + ** Fluent setter for showExportButton + *******************************************************************************/ + public QWidgetMetaData withShowExportButton(boolean showExportButton) + { + this.showExportButton = showExportButton; + return (this); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendWidgetMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendWidgetMetaData.java index d04b29f8..b33f4314 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendWidgetMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendWidgetMetaData.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper; import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput; +import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface; import com.kingsrook.qqq.backend.core.model.metadata.dashboard.WidgetDropdownData; @@ -50,6 +51,9 @@ public class QFrontendWidgetMetaData private final boolean storeDropdownSelections; private final List dropdowns; + private boolean showReloadButton = false; + private boolean showExportButton = false; + private final boolean hasPermission; ////////////////////////////////////////////////////////////////////////////////// @@ -74,6 +78,12 @@ public class QFrontendWidgetMetaData this.dropdowns = widgetMetaData.getDropdowns(); this.storeDropdownSelections = widgetMetaData.getStoreDropdownSelections(); + if(widgetMetaData instanceof QWidgetMetaData qWidgetMetaData) + { + this.showExportButton = qWidgetMetaData.getShowExportButton(); + this.showReloadButton = qWidgetMetaData.getShowReloadButton(); + } + hasPermission = PermissionsHelper.hasWidgetPermission(actionInput, name); } @@ -198,4 +208,25 @@ public class QFrontendWidgetMetaData return storeDropdownSelections; } + + + /******************************************************************************* + ** Getter for showReloadButton + ** + *******************************************************************************/ + public boolean getShowReloadButton() + { + return showReloadButton; + } + + + + /******************************************************************************* + ** Getter for showExportButton + ** + *******************************************************************************/ + public boolean getShowExportButton() + { + return showExportButton; + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/StreamedETLWithFrontendProcess.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/StreamedETLWithFrontendProcess.java index 3459b0ac..7b31440d 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/StreamedETLWithFrontendProcess.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/StreamedETLWithFrontendProcess.java @@ -91,6 +91,7 @@ public class StreamedETLWithFrontendProcess public static final String DEFAULT_PREVIEW_MESSAGE_FOR_UPDATE = "This is a preview of the records that will be updated."; public static final String DEFAULT_PREVIEW_MESSAGE_FOR_INSERT_OR_UPDATE = "This is a preview of the records that will be inserted or updated."; public static final String DEFAULT_PREVIEW_MESSAGE_FOR_DELETE = "This is a preview of the records that will be deleted."; + public static final String DEFAULT_PREVIEW_MESSAGE_PREFIX = "This is a preview of the records that will be "; public static final String FIELD_PREVIEW_MESSAGE = "previewMessage"; public static final String FIELD_TRANSACTION_LEVEL = "transactionLevel"; diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java index 3cc59af0..dd32efef 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSTransaction.java @@ -24,9 +24,12 @@ package com.kingsrook.qqq.backend.module.rdbms.actions; import java.sql.Connection; import java.sql.SQLException; +import java.time.Duration; +import java.time.Instant; import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.logging.QLogger; +import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; /******************************************************************************* @@ -40,6 +43,9 @@ public class RDBMSTransaction extends QBackendTransaction private Connection connection; + private Instant openedAt = Instant.now(); + private Integer logSlowTransactionSeconds = null; + /******************************************************************************* @@ -48,6 +54,17 @@ public class RDBMSTransaction extends QBackendTransaction public RDBMSTransaction(Connection connection) throws SQLException { connection.setAutoCommit(false); + + String propertyName = "qqq.rdbms.logSlowTransactionSeconds"; + try + { + logSlowTransactionSeconds = Integer.parseInt(System.getProperty(propertyName, "10")); + } + catch(Exception e) + { + LOG.debug("Error reading property [" + propertyName + "] value as integer", e); + } + this.connection = connection; } @@ -72,7 +89,18 @@ public class RDBMSTransaction extends QBackendTransaction { try { - LOG.debug("Committing transaction"); + Instant commitAt = Instant.now(); + + Duration duration = Duration.between(openedAt, commitAt); + if(logSlowTransactionSeconds != null && duration.compareTo(Duration.ofSeconds(logSlowTransactionSeconds)) > 0) + { + LOG.info("Committing long-running transaction", logPair("durationSeconds", duration.getSeconds())); + } + else + { + LOG.debug("Committing transaction"); + } + connection.commit(); LOG.debug("Commit complete"); } @@ -81,6 +109,13 @@ public class RDBMSTransaction extends QBackendTransaction LOG.error("Error committing transaction", e); throw new QException("Error committing transaction: " + e.getMessage(), e); } + finally + { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // reset this - as after one commit, the transaction is essentially re-opened for any future statements that run on it // + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + openedAt = Instant.now(); + } }