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("""
+ %s
+ """, color, iconName);
+ }
+
+
+
/*******************************************************************************
**
*******************************************************************************/
public String helpIcon()
{
- return ("""
- help_outline
- """);
+ return (icon("help_outline", "blue"));
}
@@ -81,9 +91,7 @@ public class NoCodeWidgetVelocityUtils
*******************************************************************************/
public String errorIcon()
{
- return ("""
- error_outline
- """);
+ return (icon("error_outline", "red"));
}
@@ -93,9 +101,7 @@ public class NoCodeWidgetVelocityUtils
*******************************************************************************/
public String warningIcon()
{
- return ("""
- warning
- """);
+ return (icon("warning", "orange"));
}
@@ -105,9 +111,7 @@ public class NoCodeWidgetVelocityUtils
*******************************************************************************/
public String checkIcon()
{
- return ("""
- check
- """);
+ return (icon("check", "green"));
}
@@ -117,9 +121,7 @@ public class NoCodeWidgetVelocityUtils
*******************************************************************************/
public String pendingIcon()
{
- return ("""
- pending
- """);
+ 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();
+ }
}