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 java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
|
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.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.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
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
|
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");
|
return (tablePath + "/" + tableName + ".bulkInsert");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +132,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static String linkTableBulkLoadChildren(RenderWidgetInput input, String tableName) throws QException
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (null);
|
return (null);
|
||||||
@ -147,7 +148,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static String linkTableCreate(RenderWidgetInput input, String tableName) throws QException
|
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");
|
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
|
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()));
|
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
|
public static String getCountLink(RenderWidgetInput input, String tableName, QQueryFilter filter, int count) throws QException
|
||||||
{
|
{
|
||||||
String totalString = QValueFormatter.formatValue(DisplayFormat.COMMAS, count);
|
String totalString = QValueFormatter.formatValue(DisplayFormat.COMMAS, count);
|
||||||
String tablePath = input.getInstance().getTablePath(tableName);
|
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||||
if(tablePath == null || filter == null)
|
if(tablePath == null || filter == null)
|
||||||
{
|
{
|
||||||
return (totalString);
|
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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -201,7 +202,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static String linkTableFilterUnencoded(RenderWidgetInput input, String tableName, QQueryFilter filter) throws QException
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (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
|
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 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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (displayText);
|
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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (linkText);
|
return (linkText);
|
||||||
@ -267,7 +268,7 @@ public abstract class AbstractHTMLWidgetRenderer extends AbstractWidgetRenderer
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static String linkRecordEdit(AbstractActionInput input, String tableName, Serializable recordId) throws QException
|
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");
|
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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (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
|
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 tableName = process.getTableName();
|
||||||
String tablePath = input.getInstance().getTablePath(tableName);
|
String tablePath = QContext.getQInstance().getTablePath(tableName);
|
||||||
return (tablePath + "/" + recordId + "/" + processName);
|
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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (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
|
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)
|
if(tablePath == null)
|
||||||
{
|
{
|
||||||
return (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.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
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.exceptions.QPermissionDeniedException;
|
||||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
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
|
private static void checkTablePermissionThrowing(AbstractActionInput actionInput, String tableName, TablePermissionSubType permissionSubType) throws QPermissionDeniedException
|
||||||
{
|
{
|
||||||
warnAboutPermissionSubTypeForTables(permissionSubType);
|
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)
|
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());
|
String permissionBaseName = getEffectivePermissionBaseName(rules, metaDataWithPermissionRules.getName());
|
||||||
|
|
||||||
switch(rules.getLevel())
|
switch(rules.getLevel())
|
||||||
@ -167,8 +168,8 @@ public class PermissionsHelper
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static void checkProcessPermissionThrowing(AbstractActionInput actionInput, String processName, Map<String, Serializable> processValues) throws QPermissionDeniedException
|
public static void checkProcessPermissionThrowing(AbstractActionInput actionInput, String processName, Map<String, Serializable> processValues) throws QPermissionDeniedException
|
||||||
{
|
{
|
||||||
QProcessMetaData process = actionInput.getInstance().getProcess(processName);
|
QProcessMetaData process = QContext.getQInstance().getProcess(processName);
|
||||||
QPermissionRules effectivePermissionRules = getEffectivePermissionRules(process, actionInput.getInstance());
|
QPermissionRules effectivePermissionRules = getEffectivePermissionRules(process, QContext.getQInstance());
|
||||||
|
|
||||||
if(effectivePermissionRules.getCustomPermissionChecker() != null)
|
if(effectivePermissionRules.getCustomPermissionChecker() != null)
|
||||||
{
|
{
|
||||||
@ -208,8 +209,8 @@ public class PermissionsHelper
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static void checkAppPermissionThrowing(AbstractActionInput actionInput, String appName) throws QPermissionDeniedException
|
public static void checkAppPermissionThrowing(AbstractActionInput actionInput, String appName) throws QPermissionDeniedException
|
||||||
{
|
{
|
||||||
QAppMetaData app = actionInput.getInstance().getApp(appName);
|
QAppMetaData app = QContext.getQInstance().getApp(appName);
|
||||||
commonCheckPermissionThrowing(getEffectivePermissionRules(app, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, app.getName(), actionInput);
|
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
|
public static void checkReportPermissionThrowing(AbstractActionInput actionInput, String reportName) throws QPermissionDeniedException
|
||||||
{
|
{
|
||||||
QReportMetaData report = actionInput.getInstance().getReport(reportName);
|
QReportMetaData report = QContext.getQInstance().getReport(reportName);
|
||||||
commonCheckPermissionThrowing(getEffectivePermissionRules(report, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, report.getName(), actionInput);
|
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
|
public static void checkWidgetPermissionThrowing(AbstractActionInput actionInput, String widgetName) throws QPermissionDeniedException
|
||||||
{
|
{
|
||||||
QWidgetMetaDataInterface widget = actionInput.getInstance().getWidget(widgetName);
|
QWidgetMetaDataInterface widget = QContext.getQInstance().getWidget(widgetName);
|
||||||
commonCheckPermissionThrowing(getEffectivePermissionRules(widget, actionInput.getInstance()), PrivatePermissionSubType.HAS_ACCESS, widget.getName(), actionInput);
|
commonCheckPermissionThrowing(getEffectivePermissionRules(widget, QContext.getQInstance()), PrivatePermissionSubType.HAS_ACCESS, widget.getName(), actionInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public class QFilterCriteria implements Serializable, Cloneable
|
|||||||
private QCriteriaOperator operator;
|
private QCriteriaOperator operator;
|
||||||
private List<Serializable> values;
|
private List<Serializable> values;
|
||||||
|
|
||||||
private String otherFieldName;
|
private String otherFieldName;
|
||||||
private AbstractFilterExpression<?> expression;
|
private AbstractFilterExpression<?> expression;
|
||||||
|
|
||||||
|
|
||||||
@ -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());
|
return (rs.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for expression
|
** Getter for expression
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@ -334,5 +353,4 @@ public class QFilterCriteria implements Serializable, Cloneable
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,7 @@ public class QInstance
|
|||||||
private Map<String, QQueueMetaData> queues = new LinkedHashMap<>();
|
private Map<String, QQueueMetaData> queues = new LinkedHashMap<>();
|
||||||
|
|
||||||
private Map<String, String> environmentValues = new LinkedHashMap<>();
|
private Map<String, String> environmentValues = new LinkedHashMap<>();
|
||||||
|
private String defaultTimeZoneId = "UTC";
|
||||||
|
|
||||||
private QPermissionRules defaultPermissionRules = QPermissionRules.defaultInstance();
|
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.
|
** Test if record matches filter.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SuppressWarnings("checkstyle:indentation")
|
|
||||||
public static boolean doesRecordMatch(QQueryFilter filter, QRecord qRecord)
|
public static boolean doesRecordMatch(QQueryFilter filter, QRecord qRecord)
|
||||||
{
|
{
|
||||||
if(filter == null || !filter.hasAnyCriteria())
|
if(filter == null || !filter.hasAnyCriteria())
|
||||||
@ -72,40 +71,7 @@ public class BackendQueryFilterUtils
|
|||||||
String fieldName = criterion.getFieldName();
|
String fieldName = criterion.getFieldName();
|
||||||
Serializable value = qRecord.getValue(fieldName);
|
Serializable value = qRecord.getValue(fieldName);
|
||||||
|
|
||||||
boolean criterionMatches = switch(criterion.getOperator())
|
boolean criterionMatches = doesCriteriaMatch(criterion, fieldName, value);
|
||||||
{
|
|
||||||
case EQUALS -> testEquals(criterion, value);
|
|
||||||
case NOT_EQUALS -> !testEquals(criterion, value);
|
|
||||||
case IN -> testIn(criterion, value);
|
|
||||||
case NOT_IN -> !testIn(criterion, value);
|
|
||||||
case IS_BLANK -> testBlank(criterion, value);
|
|
||||||
case IS_NOT_BLANK -> !testBlank(criterion, value);
|
|
||||||
case CONTAINS -> testContains(criterion, fieldName, value);
|
|
||||||
case NOT_CONTAINS -> !testContains(criterion, fieldName, value);
|
|
||||||
case IS_NULL_OR_IN -> testBlank(criterion, value) || testIn(criterion, value);
|
|
||||||
case STARTS_WITH -> testStartsWith(criterion, fieldName, value);
|
|
||||||
case NOT_STARTS_WITH -> !testStartsWith(criterion, fieldName, value);
|
|
||||||
case ENDS_WITH -> testEndsWith(criterion, fieldName, value);
|
|
||||||
case NOT_ENDS_WITH -> !testEndsWith(criterion, fieldName, value);
|
|
||||||
case GREATER_THAN -> testGreaterThan(criterion, value);
|
|
||||||
case GREATER_THAN_OR_EQUALS -> testGreaterThan(criterion, value) || testEquals(criterion, value);
|
|
||||||
case LESS_THAN -> !testGreaterThan(criterion, value) && !testEquals(criterion, value);
|
|
||||||
case LESS_THAN_OR_EQUALS -> !testGreaterThan(criterion, value);
|
|
||||||
case BETWEEN ->
|
|
||||||
{
|
|
||||||
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
QFilterCriteria criteria1 = new QFilterCriteria().withValues(new ArrayList<>(criterion.getValues()));
|
|
||||||
criteria1.getValues().remove(0);
|
|
||||||
yield (testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
|
||||||
}
|
|
||||||
case NOT_BETWEEN ->
|
|
||||||
{
|
|
||||||
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
QFilterCriteria criteria1 = new QFilterCriteria().withValues(criterion.getValues());
|
|
||||||
criteria1.getValues().remove(0);
|
|
||||||
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. //
|
// add this new value to the existing recordMatches value - and if we can short circuit the remaining checks, do so. //
|
||||||
@ -139,6 +105,51 @@ public class BackendQueryFilterUtils
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@SuppressWarnings("checkstyle:indentation")
|
||||||
|
public static boolean doesCriteriaMatch(QFilterCriteria criterion, String fieldName, Serializable value)
|
||||||
|
{
|
||||||
|
boolean criterionMatches = switch(criterion.getOperator())
|
||||||
|
{
|
||||||
|
case EQUALS -> testEquals(criterion, value);
|
||||||
|
case NOT_EQUALS -> !testEquals(criterion, value);
|
||||||
|
case IN -> testIn(criterion, value);
|
||||||
|
case NOT_IN -> !testIn(criterion, value);
|
||||||
|
case IS_BLANK -> testBlank(criterion, value);
|
||||||
|
case IS_NOT_BLANK -> !testBlank(criterion, value);
|
||||||
|
case CONTAINS -> testContains(criterion, fieldName, value);
|
||||||
|
case NOT_CONTAINS -> !testContains(criterion, fieldName, value);
|
||||||
|
case IS_NULL_OR_IN -> testBlank(criterion, value) || testIn(criterion, value);
|
||||||
|
case STARTS_WITH -> testStartsWith(criterion, fieldName, value);
|
||||||
|
case NOT_STARTS_WITH -> !testStartsWith(criterion, fieldName, value);
|
||||||
|
case ENDS_WITH -> testEndsWith(criterion, fieldName, value);
|
||||||
|
case NOT_ENDS_WITH -> !testEndsWith(criterion, fieldName, value);
|
||||||
|
case GREATER_THAN -> testGreaterThan(criterion, value);
|
||||||
|
case GREATER_THAN_OR_EQUALS -> testGreaterThan(criterion, value) || testEquals(criterion, value);
|
||||||
|
case LESS_THAN -> !testGreaterThan(criterion, value) && !testEquals(criterion, value);
|
||||||
|
case LESS_THAN_OR_EQUALS -> !testGreaterThan(criterion, value);
|
||||||
|
case BETWEEN ->
|
||||||
|
{
|
||||||
|
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
QFilterCriteria criteria1 = new QFilterCriteria().withValues(new ArrayList<>(criterion.getValues()));
|
||||||
|
criteria1.getValues().remove(0);
|
||||||
|
yield (testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
||||||
|
}
|
||||||
|
case NOT_BETWEEN ->
|
||||||
|
{
|
||||||
|
QFilterCriteria criteria0 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
QFilterCriteria criteria1 = new QFilterCriteria().withValues(criterion.getValues());
|
||||||
|
criteria1.getValues().remove(0);
|
||||||
|
yield !(testGreaterThan(criteria0, value) || testEquals(criteria0, value)) && (!testGreaterThan(criteria1, value) || testEquals(criteria1, value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return criterionMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Based on an incoming boolean value (accumulator), a new value, and a boolean
|
** Based on an incoming boolean value (accumulator), a new value, and a boolean
|
||||||
** operator, update the accumulator, and if we can then short-circuit remaining
|
** operator, update the accumulator, and if we can then short-circuit remaining
|
||||||
|
@ -52,8 +52,6 @@ public class ValueUtils
|
|||||||
private static final DateTimeFormatter dateTimeFormatter_MdyyyyWithSlashes = DateTimeFormatter.ofPattern("M/d/yyyy");
|
private static final DateTimeFormatter dateTimeFormatter_MdyyyyWithSlashes = DateTimeFormatter.ofPattern("M/d/yyyy");
|
||||||
private static final DateTimeFormatter dateTimeFormatter_yyyyMMdd = DateTimeFormatter.ofPattern("yyyyMMdd");
|
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.Connection;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||||
import com.kingsrook.qqq.backend.core.actions.interfaces.QActionInterface;
|
import com.kingsrook.qqq.backend.core.actions.interfaces.QActionInterface;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
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.logging.QLogger;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.Aggregate;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.Aggregate;
|
||||||
@ -715,6 +718,11 @@ public abstract class AbstractRDBMSAction implements QActionInterface
|
|||||||
|
|
||||||
clauses.add("(" + clause + ")");
|
clauses.add("(" + clause + ")");
|
||||||
|
|
||||||
|
if(field.getType().equals(QFieldType.DATE_TIME))
|
||||||
|
{
|
||||||
|
values = evaluateDateTimeParamValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
params.addAll(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