mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
First version of no-code dashboard widgets
This commit is contained in:
@ -33,6 +33,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
@ -120,7 +121,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableBulkLoad(RenderWidgetInput input, String tableName) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
return (tablePath + "/" + tableName + ".bulkInsert");
|
||||
}
|
||||
|
||||
@ -131,7 +132,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableBulkLoadChildren(RenderWidgetInput input, String tableName) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
@ -147,7 +148,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableCreate(RenderWidgetInput input, String tableName) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
return (tablePath + "/create");
|
||||
}
|
||||
|
||||
@ -158,7 +159,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableCreateWithDefaultValues(RenderWidgetInput input, String tableName, Map<String, Serializable> defaultValues) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
return (tablePath + "/create?defaultValues=" + URLEncoder.encode(JsonUtils.toJson(defaultValues), Charset.defaultCharset()));
|
||||
}
|
||||
|
||||
@ -170,7 +171,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
public static String getCountLink(RenderWidgetInput input, String tableName, QQueryFilter filter, int count) throws QException
|
||||
{
|
||||
String totalString = QValueFormatter.formatValue(DisplayFormat.COMMAS, count);
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null || filter == null)
|
||||
{
|
||||
return (totalString);
|
||||
@ -185,7 +186,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static void addTableFilterToListIfPermissed(RenderWidgetInput input, String tableName, List<String> urls, QQueryFilter filter) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return;
|
||||
@ -201,7 +202,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableFilterUnencoded(RenderWidgetInput input, String tableName, QQueryFilter filter) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
@ -217,7 +218,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableFilter(RenderWidgetInput input, String tableName, QQueryFilter filter) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
@ -234,7 +235,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
public static String aHrefTableFilterNoOfRecords(RenderWidgetInput input, String tableName, QQueryFilter filter, Integer noOfRecords, String singularLabel, String pluralLabel) throws QException
|
||||
{
|
||||
String displayText = QValueFormatter.formatValue(DisplayFormat.COMMAS, noOfRecords) + " " + StringUtils.plural(noOfRecords, singularLabel, pluralLabel);
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (displayText);
|
||||
@ -251,7 +252,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String aHrefViewRecord(RenderWidgetInput input, String tableName, Serializable id, String linkText) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (linkText);
|
||||
@ -267,7 +268,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkRecordEdit(AbstractActionInput input, String tableName, Serializable recordId) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
return (tablePath + "/" + recordId + "/edit");
|
||||
}
|
||||
|
||||
@ -278,7 +279,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkRecordView(AbstractActionInput input, String tableName, Serializable recordId) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
@ -294,9 +295,9 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkProcessForRecord(AbstractActionInput input, String processName, Serializable recordId) throws QException
|
||||
{
|
||||
QProcessMetaData process = input.getInstance().getProcess(processName);
|
||||
QProcessMetaData process = QContext.getQInstance().getProcess(processName);
|
||||
String tableName = process.getTableName();
|
||||
String tablePath = input.getInstance().getTablePath(tableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||
return (tablePath + "/" + recordId + "/" + processName);
|
||||
}
|
||||
|
||||
@ -327,7 +328,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String linkTableCreateChild(RenderWidgetInput input, String childTableName, Map<String, Serializable> defaultValues, Set<String> disabledFields) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(childTableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(childTableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
@ -347,7 +348,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
||||
*******************************************************************************/
|
||||
public static String aHrefTableCreateChild(RenderWidgetInput input, String childTableName, Map<String, Serializable> defaultValues, Set<String> disabledFields) throws QException
|
||||
{
|
||||
String tablePath = input.getInstance().getTablePath(childTableName);
|
||||
String tablePath = QContext.getQInstance().getTablePath(childTableName);
|
||||
if(tablePath == null)
|
||||
{
|
||||
return (null);
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.RawHTML;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.AbstractWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.AbstractWidgetValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.QNoCodeWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class NoCodeWidgetRenderer extends AbstractWidgetRenderer
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(NoCodeWidgetRenderer.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
|
||||
{
|
||||
QNoCodeWidgetMetaData widgetMetaData = (QNoCodeWidgetMetaData) input.getWidgetMetaData();
|
||||
|
||||
////////////////////////////////////////////
|
||||
// build context by evaluating all values //
|
||||
////////////////////////////////////////////
|
||||
Map<String, Object> context = new HashMap<>();
|
||||
|
||||
for(AbstractWidgetValueSource valueSource : widgetMetaData.getValues())
|
||||
{
|
||||
LOG.trace("Computing: " + valueSource.getType() + " named " + valueSource.getName() + "...");
|
||||
Object value = valueSource.evaluate(context);
|
||||
LOG.trace("Computed: " + valueSource.getName() + " = " + value);
|
||||
context.put(valueSource.getName(), value);
|
||||
|
||||
context.put(valueSource.getName() + ".source", valueSource);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// set default utils object in context too //
|
||||
/////////////////////////////////////////////
|
||||
context.put("utils", new NoCodeWidgetVelocityUtils(context));
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// build content by evaluating all outputs //
|
||||
/////////////////////////////////////////////
|
||||
StringBuilder content = new StringBuilder();
|
||||
for(AbstractWidgetOutput output : widgetMetaData.getOutputs())
|
||||
{
|
||||
boolean conditionPassed = true;
|
||||
if(output.getCondition() != null)
|
||||
{
|
||||
conditionPassed = evaluateCondition(output.getCondition(), context);
|
||||
}
|
||||
|
||||
if(conditionPassed)
|
||||
{
|
||||
String render = output.render(context);
|
||||
content.append(render);
|
||||
LOG.trace("Condition passed, rendered: " + render);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.trace("Condition failed - not rendering this output.");
|
||||
}
|
||||
}
|
||||
|
||||
return (new RenderWidgetOutput(new RawHTML(widgetMetaData.getLabel(), content.toString())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private boolean evaluateCondition(QFilterCriteria condition, Map<String, Object> context)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object value = context.get(condition.getFieldName());
|
||||
return (BackendQueryFilterUtils.doesCriteriaMatch(condition, condition.getFieldName(), (Serializable) value));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error evaluating condition: " + condition, e);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.AbstractHTMLWidgetRenderer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetCount;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class NoCodeWidgetVelocityUtils
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(NoCodeWidgetVelocityUtils.class);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private final Map<String, Object> context;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public NoCodeWidgetVelocityUtils(Map<String, Object> context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public final String errorIcon()
|
||||
{
|
||||
return ("""
|
||||
<span class="material-icons-round notranslate MuiIcon-root MuiIcon-fontSizeInherit" style="color: red; position: relative; top: 6px;" aria-hidden="true">error_outline</span>
|
||||
""");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public final String checkIcon()
|
||||
{
|
||||
return ("""
|
||||
<span class="material-icons-round notranslate MuiIcon-root MuiIcon-fontSizeInherit" style="color: green; position: relative; top: 6px;" aria-hidden="true">check</span>
|
||||
""");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String plural(Integer size, String ifOne, String ifNotOne)
|
||||
{
|
||||
return StringUtils.plural(size, ifOne, ifNotOne);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String tableCountFilterLink(String countVariableName, String singular, String plural) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
WidgetCount widgetCount = (WidgetCount) context.get(countVariableName + ".source");
|
||||
Integer count = ValueUtils.getValueAsInteger(context.get(countVariableName));
|
||||
QQueryFilter filter = widgetCount.getFilter();
|
||||
return (AbstractHTMLWidgetRenderer.aHrefTableFilterNoOfRecords(null, widgetCount.getTableName(), filter, count, singular, plural));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error rendering widget link", e);
|
||||
return ("");
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
@ -72,9 +73,9 @@ public class PermissionsHelper
|
||||
private static void checkTablePermissionThrowing(AbstractActionInput actionInput, String tableName, TablePermissionSubType permissionSubType) throws QPermissionDeniedException
|
||||
{
|
||||
warnAboutPermissionSubTypeForTables(permissionSubType);
|
||||
QTableMetaData table = actionInput.getInstance().getTable(tableName);
|
||||
QTableMetaData table = QContext.getQInstance().getTable(tableName);
|
||||
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(table, actionInput.getInstance()), permissionSubType, table.getName(), actionInput);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(table, QContext.getQInstance()), permissionSubType, table.getName(), actionInput);
|
||||
}
|
||||
|
||||
|
||||
@ -102,7 +103,7 @@ public class PermissionsHelper
|
||||
*******************************************************************************/
|
||||
public static PermissionCheckResult getPermissionCheckResult(AbstractActionInput actionInput, MetaDataWithPermissionRules metaDataWithPermissionRules)
|
||||
{
|
||||
QPermissionRules rules = getEffectivePermissionRules(metaDataWithPermissionRules, actionInput.getInstance());
|
||||
QPermissionRules rules = getEffectivePermissionRules(metaDataWithPermissionRules, QContext.getQInstance());
|
||||
String permissionBaseName = getEffectivePermissionBaseName(rules, metaDataWithPermissionRules.getName());
|
||||
|
||||
switch(rules.getLevel())
|
||||
@ -167,8 +168,8 @@ public class PermissionsHelper
|
||||
*******************************************************************************/
|
||||
public static void checkProcessPermissionThrowing(AbstractActionInput actionInput, String processName, Map<String, Serializable> processValues) throws QPermissionDeniedException
|
||||
{
|
||||
QProcessMetaData process = actionInput.getInstance().getProcess(processName);
|
||||
QPermissionRules effectivePermissionRules = getEffectivePermissionRules(process, actionInput.getInstance());
|
||||
QProcessMetaData process = QContext.getQInstance().getProcess(processName);
|
||||
QPermissionRules effectivePermissionRules = getEffectivePermissionRules(process, QContext.getQInstance());
|
||||
|
||||
if(effectivePermissionRules.getCustomPermissionChecker() != null)
|
||||
{
|
||||
@ -208,8 +209,8 @@ public class PermissionsHelper
|
||||
*******************************************************************************/
|
||||
public static void checkAppPermissionThrowing(AbstractActionInput actionInput, String appName) throws QPermissionDeniedException
|
||||
{
|
||||
QAppMetaData app = actionInput.getInstance().getApp(appName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(app, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, app.getName(), actionInput);
|
||||
QAppMetaData app = QContext.getQInstance().getApp(appName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(app, QContext.getQInstance()), PrivatePermissionSubType.HAS_ACCESS, app.getName(), actionInput);
|
||||
}
|
||||
|
||||
|
||||
@ -237,8 +238,8 @@ public class PermissionsHelper
|
||||
*******************************************************************************/
|
||||
public static void checkReportPermissionThrowing(AbstractActionInput actionInput, String reportName) throws QPermissionDeniedException
|
||||
{
|
||||
QReportMetaData report = actionInput.getInstance().getReport(reportName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(report, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, report.getName(), actionInput);
|
||||
QReportMetaData report = QContext.getQInstance().getReport(reportName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(report, QContext.getQInstance()), PrivatePermissionSubType.HAS_ACCESS, report.getName(), actionInput);
|
||||
}
|
||||
|
||||
|
||||
@ -266,8 +267,8 @@ public class PermissionsHelper
|
||||
*******************************************************************************/
|
||||
public static void checkWidgetPermissionThrowing(AbstractActionInput actionInput, String widgetName) throws QPermissionDeniedException
|
||||
{
|
||||
QWidgetMetaDataInterface widget = actionInput.getInstance().getWidget(widgetName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(widget, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, widget.getName(), actionInput);
|
||||
QWidgetMetaDataInterface widget = QContext.getQInstance().getWidget(widgetName);
|
||||
commonCheckPermissionThrowing(getEffectivePermissionRules(widget, QContext.getQInstance()), PrivatePermissionSubType.HAS_ACCESS, widget.getName(), actionInput);
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,6 +98,23 @@ public class QFilterCriteria implements Serializable, Cloneable
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QFilterCriteria(String fieldName, QCriteriaOperator operator, AbstractFilterExpression<?> expression)
|
||||
{
|
||||
this.fieldName = fieldName;
|
||||
this.operator = operator;
|
||||
this.expression = expression;
|
||||
|
||||
///////////////////////////////////////
|
||||
// this guy doesn't like to be null? //
|
||||
///////////////////////////////////////
|
||||
this.values = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -305,6 +322,8 @@ public class QFilterCriteria implements Serializable, Cloneable
|
||||
return (rs.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for expression
|
||||
*******************************************************************************/
|
||||
@ -334,5 +353,4 @@ public class QFilterCriteria implements Serializable, Cloneable
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ public class QInstance
|
||||
private Map<String, QQueueMetaData> queues = new LinkedHashMap<>();
|
||||
|
||||
private Map<String, String> environmentValues = new LinkedHashMap<>();
|
||||
private String defaultTimeZoneId = "UTC";
|
||||
|
||||
private QPermissionRules defaultPermissionRules = QPermissionRules.defaultInstance();
|
||||
|
||||
@ -993,6 +994,37 @@ public class QInstance
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for defaultTimeZoneId
|
||||
*******************************************************************************/
|
||||
public void setDefaultTimeZoneId(String defaultTimeZoneId)
|
||||
{
|
||||
this.defaultTimeZoneId = defaultTimeZoneId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for defaultTimeZoneId
|
||||
*******************************************************************************/
|
||||
public QInstance withDefaultTimeZoneId(String defaultTimeZoneId)
|
||||
{
|
||||
this.defaultTimeZoneId = defaultTimeZoneId;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for defaultTimeZoneId
|
||||
*******************************************************************************/
|
||||
public String getDefaultTimeZoneId()
|
||||
{
|
||||
return (this.defaultTimeZoneId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractWidgetOutput
|
||||
{
|
||||
protected QFilterCriteria condition;
|
||||
protected String type;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract String render(Map<String, Object> context) throws QException;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for condition
|
||||
*******************************************************************************/
|
||||
public QFilterCriteria getCondition()
|
||||
{
|
||||
return (this.condition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for condition
|
||||
*******************************************************************************/
|
||||
public void setCondition(QFilterCriteria condition)
|
||||
{
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for condition
|
||||
*******************************************************************************/
|
||||
public AbstractWidgetOutput withCondition(QFilterCriteria condition)
|
||||
{
|
||||
this.condition = condition;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public AbstractWidgetOutput withType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract class AbstractWidgetValueSource
|
||||
{
|
||||
protected String name;
|
||||
protected String type;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public abstract Object evaluate(Map<String, Object> context) throws QException;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public AbstractWidgetValueSource withType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for name
|
||||
*******************************************************************************/
|
||||
public String getName()
|
||||
{
|
||||
return (this.name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for name
|
||||
*******************************************************************************/
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public AbstractWidgetValueSource withName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void supplementContext(Map<String, Object> context)
|
||||
{
|
||||
////////////////////////
|
||||
// noop in base class //
|
||||
////////////////////////
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class HtmlWrapper
|
||||
{
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
|
||||
public static final HtmlWrapper SUBHEADER = new HtmlWrapper("<h4>", "</h4>");
|
||||
public static final HtmlWrapper INDENT_1 = new HtmlWrapper("<div style='padding-left: 1rem;'>", "</div>");
|
||||
public static final HtmlWrapper INDENT_2 = new HtmlWrapper("<div style='padding-left: 2rem;'>", "</div>");
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public HtmlWrapper(String prefix, String suffix)
|
||||
{
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static HtmlWrapper paddingTop(String amount)
|
||||
{
|
||||
return (new HtmlWrapper("<div style='padding-top: " + amount + "'>", "</div>"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String wrap(String content)
|
||||
{
|
||||
return (Objects.requireNonNullElse(prefix, "")
|
||||
+ "\n" + Objects.requireNonNullElse(content, "") + "\n"
|
||||
+ Objects.requireNonNullElse(suffix, "") + "\n");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class QNoCodeWidgetMetaData extends QWidgetMetaData
|
||||
{
|
||||
private List<AbstractWidgetValueSource> values = new ArrayList<>();
|
||||
private List<AbstractWidgetOutput> outputs = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
*******************************************************************************/
|
||||
public List<AbstractWidgetValueSource> getValues()
|
||||
{
|
||||
return (this.values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
public void setValues(List<AbstractWidgetValueSource> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter to add a single value
|
||||
*******************************************************************************/
|
||||
public QNoCodeWidgetMetaData withValue(AbstractWidgetValueSource value)
|
||||
{
|
||||
if(this.values == null)
|
||||
{
|
||||
this.values = new ArrayList<>();
|
||||
}
|
||||
this.values.add(value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for values
|
||||
*******************************************************************************/
|
||||
public QNoCodeWidgetMetaData withValues(List<AbstractWidgetValueSource> values)
|
||||
{
|
||||
this.values = values;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputs
|
||||
*******************************************************************************/
|
||||
public List<AbstractWidgetOutput> getOutputs()
|
||||
{
|
||||
return (this.outputs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputs
|
||||
*******************************************************************************/
|
||||
public void setOutputs(List<AbstractWidgetOutput> outputs)
|
||||
{
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter to add a single output
|
||||
*******************************************************************************/
|
||||
public QNoCodeWidgetMetaData withOutput(AbstractWidgetOutput output)
|
||||
{
|
||||
if(this.outputs == null)
|
||||
{
|
||||
this.outputs = new ArrayList<>();
|
||||
}
|
||||
this.outputs.add(output);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputs
|
||||
*******************************************************************************/
|
||||
public QNoCodeWidgetMetaData withOutputs(List<AbstractWidgetOutput> outputs)
|
||||
{
|
||||
this.outputs = outputs;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class WidgetCalculation extends AbstractWidgetValueSource
|
||||
{
|
||||
private Operator operator;
|
||||
private List<String> values;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum Operator
|
||||
{
|
||||
SUM_INTEGERS((List<String> valueNames, Map<String, Object> context) ->
|
||||
{
|
||||
Integer sum = 0;
|
||||
for(String valueName : valueNames)
|
||||
{
|
||||
Integer addend = ValueUtils.getValueAsInteger(context.get(valueName));
|
||||
sum += addend;
|
||||
}
|
||||
return (sum);
|
||||
}),
|
||||
|
||||
AGE_MINUTES((List<String> valueNames, Map<String, Object> context) ->
|
||||
{
|
||||
Instant now = Instant.now();
|
||||
Instant then = ValueUtils.getValueAsInstant(context.get(valueNames.get(0)));
|
||||
return (then.until(now, ChronoUnit.MINUTES));
|
||||
});
|
||||
|
||||
|
||||
private final BiFunction<List<String>, Map<String, Object>, Object> function;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
Operator(BiFunction<List<String>, Map<String, Object>, Object> function)
|
||||
{
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Object execute(List<String> values, Map<String, Object> context)
|
||||
{
|
||||
return (function.apply(values, context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetCalculation()
|
||||
{
|
||||
setType(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Object evaluate(Map<String, Object> context) throws QException
|
||||
{
|
||||
return (operator.execute(values, context));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetCalculation withName(String name)
|
||||
{
|
||||
setName(name);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for operator
|
||||
*******************************************************************************/
|
||||
public Operator getOperator()
|
||||
{
|
||||
return (this.operator);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for operator
|
||||
*******************************************************************************/
|
||||
public void setOperator(Operator operator)
|
||||
{
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for operator
|
||||
*******************************************************************************/
|
||||
public WidgetCalculation withOperator(Operator operator)
|
||||
{
|
||||
this.operator = operator;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for values
|
||||
*******************************************************************************/
|
||||
public List<String> getValues()
|
||||
{
|
||||
return (this.values);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
*******************************************************************************/
|
||||
public void setValues(List<String> values)
|
||||
{
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for values
|
||||
*******************************************************************************/
|
||||
public WidgetCalculation withValues(List<String> values)
|
||||
{
|
||||
this.values = values;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class WidgetCount extends AbstractWidgetValueSource
|
||||
{
|
||||
private String tableName;
|
||||
private QQueryFilter filter;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetCount()
|
||||
{
|
||||
setType(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Object evaluate(Map<String, Object> context) throws QException
|
||||
{
|
||||
// todo - look for params in the filter (fields or values)
|
||||
// make sure to update it in supplementContext below too!!
|
||||
CountInput countInput = new CountInput();
|
||||
countInput.setTableName(tableName);
|
||||
countInput.setFilter(filter);
|
||||
CountOutput countOutput = new CountAction().execute(countInput);
|
||||
return (countOutput.getCount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void supplementContext(Map<String, Object> context)
|
||||
{
|
||||
context.put(getName() + ".filter", filter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public WidgetCount withName(String name)
|
||||
{
|
||||
setName(name);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return (this.tableName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
*******************************************************************************/
|
||||
public WidgetCount withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return (this.filter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for filter
|
||||
*******************************************************************************/
|
||||
public WidgetCount withFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.templates.RenderTemplateAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.TemplateType;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class WidgetHtmlLine extends AbstractWidgetOutput
|
||||
{
|
||||
private List<HtmlWrapper> wrappers;
|
||||
private String velocityTemplate;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetHtmlLine()
|
||||
{
|
||||
setType(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public String render(Map<String, Object> context) throws QException
|
||||
{
|
||||
RenderTemplateInput renderTemplateInput = new RenderTemplateInput();
|
||||
renderTemplateInput.setTemplateType(TemplateType.VELOCITY);
|
||||
renderTemplateInput.setCode(velocityTemplate);
|
||||
renderTemplateInput.setContext(context);
|
||||
|
||||
RenderTemplateOutput renderTemplateOutput = new RenderTemplateAction().execute(renderTemplateInput);
|
||||
String content = renderTemplateOutput.getResult();
|
||||
|
||||
if(wrappers != null)
|
||||
{
|
||||
for(int i = wrappers.size() - 1; i >= 0; i--)
|
||||
{
|
||||
content = wrappers.get(i).wrap(content);
|
||||
}
|
||||
}
|
||||
|
||||
return (content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for velocityTemplate
|
||||
*******************************************************************************/
|
||||
public String getVelocityTemplate()
|
||||
{
|
||||
return (this.velocityTemplate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for velocityTemplate
|
||||
*******************************************************************************/
|
||||
public void setVelocityTemplate(String velocityTemplate)
|
||||
{
|
||||
this.velocityTemplate = velocityTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for velocityTemplate
|
||||
*******************************************************************************/
|
||||
public WidgetHtmlLine withVelocityTemplate(String velocityTemplate)
|
||||
{
|
||||
this.velocityTemplate = velocityTemplate;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for condition
|
||||
*******************************************************************************/
|
||||
public WidgetHtmlLine withCondition(QFilterCriteria condition)
|
||||
{
|
||||
this.condition = condition;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for wrappers
|
||||
*******************************************************************************/
|
||||
public List<HtmlWrapper> getWrappers()
|
||||
{
|
||||
return (this.wrappers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for wrappers
|
||||
*******************************************************************************/
|
||||
public void setWrappers(List<HtmlWrapper> wrappers)
|
||||
{
|
||||
this.wrappers = wrappers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for wrappers
|
||||
*******************************************************************************/
|
||||
public WidgetHtmlLine withWrappers(List<HtmlWrapper> wrappers)
|
||||
{
|
||||
this.wrappers = wrappers;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter to add 1 wrapper
|
||||
*******************************************************************************/
|
||||
public WidgetHtmlLine withWrapper(HtmlWrapper wrapper)
|
||||
{
|
||||
if(this.wrappers == null)
|
||||
{
|
||||
this.wrappers = new ArrayList<>();
|
||||
}
|
||||
this.wrappers.add(wrapper);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class WidgetQueryField extends AbstractWidgetValueSource
|
||||
{
|
||||
private String tableName;
|
||||
private String selectFieldName;
|
||||
private QQueryFilter filter;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public WidgetQueryField()
|
||||
{
|
||||
setType(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public Object evaluate(Map<String, Object> context) throws QException
|
||||
{
|
||||
// todo - look for params in the filter (fields or values)
|
||||
// make sure to update it in supplementContext below too!!
|
||||
QueryInput queryInput = new QueryInput();
|
||||
queryInput.setTableName(tableName);
|
||||
queryInput.setFilter(filter);
|
||||
queryInput.setLimit(1);
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
if(CollectionUtils.nullSafeHasContents(queryOutput.getRecords()))
|
||||
{
|
||||
return (queryOutput.getRecords().get(0).getValue(selectFieldName));
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void supplementContext(Map<String, Object> context)
|
||||
{
|
||||
context.put(getName() + ".filter", filter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for name
|
||||
*******************************************************************************/
|
||||
public WidgetQueryField withName(String name)
|
||||
{
|
||||
setName(name);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return (this.tableName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
*******************************************************************************/
|
||||
public WidgetQueryField withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filter
|
||||
*******************************************************************************/
|
||||
public QQueryFilter getFilter()
|
||||
{
|
||||
return (this.filter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filter
|
||||
*******************************************************************************/
|
||||
public void setFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for filter
|
||||
*******************************************************************************/
|
||||
public WidgetQueryField withFilter(QQueryFilter filter)
|
||||
{
|
||||
this.filter = filter;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for selectFieldName
|
||||
*******************************************************************************/
|
||||
public String getSelectFieldName()
|
||||
{
|
||||
return (this.selectFieldName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for selectFieldName
|
||||
*******************************************************************************/
|
||||
public void setSelectFieldName(String selectFieldName)
|
||||
{
|
||||
this.selectFieldName = selectFieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for selectFieldName
|
||||
*******************************************************************************/
|
||||
public WidgetQueryField withSelectFieldName(String selectFieldName)
|
||||
{
|
||||
this.selectFieldName = selectFieldName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -50,7 +50,6 @@ public class BackendQueryFilterUtils
|
||||
/*******************************************************************************
|
||||
** Test if record matches filter.
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("checkstyle:indentation")
|
||||
public static boolean doesRecordMatch(QQueryFilter filter, QRecord qRecord)
|
||||
{
|
||||
if(filter == null || !filter.hasAnyCriteria())
|
||||
@ -72,6 +71,46 @@ public class BackendQueryFilterUtils
|
||||
String fieldName = criterion.getFieldName();
|
||||
Serializable value = qRecord.getValue(fieldName);
|
||||
|
||||
boolean criterionMatches = doesCriteriaMatch(criterion, fieldName, value);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, criterionMatches, filter.getBooleanOperator());
|
||||
if(shortCircuitValue != null)
|
||||
{
|
||||
return (shortCircuitValue);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// apply sub-filters if there are any //
|
||||
////////////////////////////////////////
|
||||
for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters()))
|
||||
{
|
||||
boolean subFilterMatches = doesRecordMatch(subFilter, qRecord);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, subFilterMatches, filter.getBooleanOperator());
|
||||
if(shortCircuitValue != null)
|
||||
{
|
||||
return (shortCircuitValue);
|
||||
}
|
||||
}
|
||||
|
||||
return (recordMatches.getPlain());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("checkstyle:indentation")
|
||||
public static boolean doesCriteriaMatch(QFilterCriteria criterion, String fieldName, Serializable value)
|
||||
{
|
||||
boolean criterionMatches = switch(criterion.getOperator())
|
||||
{
|
||||
case EQUALS -> testEquals(criterion, value);
|
||||
@ -106,35 +145,7 @@ public class BackendQueryFilterUtils
|
||||
yield !(testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, criterionMatches, filter.getBooleanOperator());
|
||||
if(shortCircuitValue != null)
|
||||
{
|
||||
return (shortCircuitValue);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// apply sub-filters if there are any //
|
||||
////////////////////////////////////////
|
||||
for(QQueryFilter subFilter : CollectionUtils.nonNullList(filter.getSubFilters()))
|
||||
{
|
||||
boolean subFilterMatches = doesRecordMatch(subFilter, qRecord);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Boolean shortCircuitValue = applyBooleanOperator(recordMatches, subFilterMatches, filter.getBooleanOperator());
|
||||
if(shortCircuitValue != null)
|
||||
{
|
||||
return (shortCircuitValue);
|
||||
}
|
||||
}
|
||||
|
||||
return (recordMatches.getPlain());
|
||||
return criterionMatches;
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,8 +52,6 @@ public class ValueUtils
|
||||
private static final DateTimeFormatter dateTimeFormatter_MdyyyyWithSlashes = DateTimeFormatter.ofPattern("M/d/yyyy");
|
||||
private static final DateTimeFormatter dateTimeFormatter_yyyyMMdd = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
public static final String COMPANY_TIMEZONE_ID = "America/New_York";
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.RawHTML;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.HtmlWrapper;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.QNoCodeWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetCalculation;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetCount;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetHtmlLine;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for NoCodeWidgetRenderer
|
||||
*******************************************************************************/
|
||||
class NoCodeWidgetRendererTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
TestUtils.insertDefaultShapes(QContext.getQInstance());
|
||||
|
||||
QNoCodeWidgetMetaData metaData = new QNoCodeWidgetMetaData();
|
||||
metaData.withValue(new WidgetCount()
|
||||
.withName("shapeCount")
|
||||
.withTableName(TestUtils.TABLE_NAME_SHAPE));
|
||||
|
||||
metaData.withValue(new WidgetCalculation()
|
||||
.withName("shapeCountPlusShapeCount")
|
||||
.withOperator(WidgetCalculation.Operator.SUM_INTEGERS)
|
||||
.withValues(List.of("shapeCount", "shapeCount")));
|
||||
|
||||
metaData.withOutput(new WidgetHtmlLine()
|
||||
.withWrapper(HtmlWrapper.SUBHEADER)
|
||||
.withVelocityTemplate("Header"));
|
||||
|
||||
metaData.withOutput(new WidgetHtmlLine()
|
||||
.withCondition(new QFilterCriteria("shapeCount", QCriteriaOperator.GREATER_THAN_OR_EQUALS, 0))
|
||||
.withWrapper(HtmlWrapper.INDENT_1)
|
||||
.withVelocityTemplate("""
|
||||
${utils.checkIcon()} Yes: ${shapeCount} ${utils.plural($shapeCount, "shape", "shapes")}
|
||||
"""));
|
||||
|
||||
metaData.withOutput(new WidgetHtmlLine()
|
||||
.withCondition(new QFilterCriteria("shapeCount", QCriteriaOperator.EQUALS, 0))
|
||||
.withVelocityTemplate("No: ${shapeCount}"));
|
||||
|
||||
metaData.withOutput(new WidgetHtmlLine()
|
||||
.withVelocityTemplate("Double: ${shapeCountPlusShapeCount}"));
|
||||
|
||||
RenderWidgetInput input = new RenderWidgetInput();
|
||||
input.setWidgetMetaData(metaData);
|
||||
RenderWidgetOutput output = new NoCodeWidgetRenderer().render(input);
|
||||
|
||||
String html = ((RawHTML) output.getWidgetData()).getHtml();
|
||||
System.out.println(html);
|
||||
|
||||
assertTrue(html.matches("(?s).*<h4>.*Header.*</h4>.*"));
|
||||
assertTrue(html.matches("(?s).*1rem.*Yes: 3 shapes.*"));
|
||||
assertTrue(html.matches("(?s).*>check<.*"));
|
||||
assertFalse(html.matches("(?s).*No: 3.*"));
|
||||
assertTrue(html.matches("(?s).*Double: 6.*"));
|
||||
}
|
||||
|
||||
}
|
@ -26,15 +26,18 @@ import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.QActionInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.Aggregate;
|
||||
@ -715,6 +718,11 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
|
||||
clauses.add("(" + clause + ")");
|
||||
|
||||
if(field.getType().equals(QFieldType.DATE_TIME))
|
||||
{
|
||||
values = evaluateDateTimeParamValues(values);
|
||||
}
|
||||
|
||||
params.addAll(values);
|
||||
}
|
||||
|
||||
@ -723,6 +731,66 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private List<Serializable> evaluateDateTimeParamValues(List<Serializable> values)
|
||||
{
|
||||
if(CollectionUtils.nullSafeIsEmpty(values))
|
||||
{
|
||||
return (values);
|
||||
}
|
||||
|
||||
List<Serializable> rs = new ArrayList<>();
|
||||
for(Serializable value : values)
|
||||
{
|
||||
if(value instanceof Instant)
|
||||
{
|
||||
rs.add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Instant valueAsInstant = ValueUtils.getValueAsInstant(value);
|
||||
rs.add(valueAsInstant);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Optional<Instant> valueAsRelativeInstant = parseValueAsRelativeInstant(value);
|
||||
rs.add(valueAsRelativeInstant.orElseThrow());
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
throw (new QValueException("Parameter value [" + value + "] could not be evaluated as an absolute or relative Instant"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private Optional<Instant> parseValueAsRelativeInstant(Serializable value)
|
||||
{
|
||||
String valueString = ValueUtils.getValueAsString(value);
|
||||
if(valueString == null)
|
||||
{
|
||||
return (Optional.empty());
|
||||
}
|
||||
|
||||
// todo - use parser!!
|
||||
return Optional.of(Instant.now());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user