SPRINT-17: updated dropdowns to be required, added divider

This commit is contained in:
Tim Chamberlain
2022-12-08 15:06:40 -06:00
parent 697261f91b
commit 8454f94020
9 changed files with 230 additions and 43 deletions

View File

@ -0,0 +1,47 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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 com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.exceptions.QException;
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.DividerWidgetData;
/*******************************************************************************
** Generic widget for showing a divider
*******************************************************************************/
public class DividerWidgetRenderer extends AbstractWidgetRenderer
{
/*******************************************************************************
**
*******************************************************************************/
@Override
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
{
ActionHelper.validateSession(input);
return (new RenderWidgetOutput(new DividerWidgetData()));
}
}

View File

@ -69,9 +69,10 @@ public class ParentWidgetRenderer extends AbstractWidgetRenderer
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// handle any PVSs creating dropdown data for the frontend // // handle any PVSs creating dropdown data for the frontend //
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
List<List<Map<String, String>>> pvsData = new ArrayList<>(); List<List<Map<String, String>>> pvsData = new ArrayList<>();
List<String> pvsLabels = new ArrayList<>(); List<String> pvsLabels = new ArrayList<>();
List<String> pvsNames = new ArrayList<>(); List<String> pvsNames = new ArrayList<>();
List<String> missingRequiredSelections = new ArrayList<>();
for(ParentWidgetMetaData.DropdownData dropdownData : CollectionUtils.nonNullList(metaData.getDropdowns())) for(ParentWidgetMetaData.DropdownData dropdownData : CollectionUtils.nonNullList(metaData.getDropdowns()))
{ {
String possibleValueSourceName = dropdownData.getPossibleValueSourceName(); String possibleValueSourceName = dropdownData.getPossibleValueSourceName();
@ -81,7 +82,8 @@ public class ParentWidgetRenderer extends AbstractWidgetRenderer
// this looks complicated, but is just look for a label in the dropdown data and if found use it, // // this looks complicated, but is just look for a label in the dropdown data and if found use it, //
// otherwise look for label in PVS and if found use that, otherwise just use the PVS name // // otherwise look for label in PVS and if found use that, otherwise just use the PVS name //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pvsLabels.add(dropdownData.getLabel() != null ? dropdownData.getLabel() : (possibleValueSource.getLabel() != null ? possibleValueSource.getLabel() : possibleValueSourceName)); String pvsLabel = dropdownData.getLabel() != null ? dropdownData.getLabel() : (possibleValueSource.getLabel() != null ? possibleValueSource.getLabel() : possibleValueSourceName);
pvsLabels.add(pvsLabel);
pvsNames.add(possibleValueSourceName); pvsNames.add(possibleValueSourceName);
SearchPossibleValueSourceInput pvsInput = new SearchPossibleValueSourceInput(input.getInstance()); SearchPossibleValueSourceInput pvsInput = new SearchPossibleValueSourceInput(input.getInstance());
@ -126,12 +128,37 @@ public class ParentWidgetRenderer extends AbstractWidgetRenderer
"label", possibleValue.getLabel() "label", possibleValue.getLabel()
)); ));
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// because we know the dropdowns and what the field names will be when something is selected, we can make //
// sure that something has been selected, and if not, display a message that a selection needs made //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(dropdownData.getIsRequired())
{
if(!input.getQueryParams().containsKey(possibleValueSourceName) || !StringUtils.hasContent(input.getQueryParams().get(possibleValueSourceName)))
{
missingRequiredSelections.add(pvsLabel);
}
}
} }
widgetData.setDropdownNameList(pvsNames); widgetData.setDropdownNameList(pvsNames);
widgetData.setDropdownLabelList(pvsLabels); widgetData.setDropdownLabelList(pvsLabels);
widgetData.setDropdownDataList(pvsData); widgetData.setDropdownDataList(pvsData);
widgetData.setChildWidgetNameList(metaData.getChildWidgetNameList());
////////////////////////////////////////////////////////////////////////////////
// if there are any missing required dropdowns, build up a message to display //
////////////////////////////////////////////////////////////////////////////////
if(missingRequiredSelections.size() > 0)
{
StringBuilder sb = new StringBuilder("Please select a ").append(StringUtils.joinWithCommasAndAnd(missingRequiredSelections));
sb.append(" from the ").append(StringUtils.plural(missingRequiredSelections.size(), "dropdown", "dropdowns")).append(" above.");
widgetData.setDropdownNeedsSelectedText(sb.toString());
}
else
{
widgetData.setChildWidgetNameList(metaData.getChildWidgetNameList());
}
return (new RenderWidgetOutput(widgetData)); return (new RenderWidgetOutput(widgetData));
} }

View File

@ -161,7 +161,6 @@ public class SearchPossibleValueSourceAction
QQueryFilter queryFilter = new QQueryFilter(); QQueryFilter queryFilter = new QQueryFilter();
queryFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR); queryFilter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
queryInput.setFilter(queryFilter);
if(input.getIdList() != null) if(input.getIdList() != null)
{ {
@ -207,11 +206,19 @@ public class SearchPossibleValueSourceAction
queryFilter.setOrderBys(possibleValueSource.getOrderByFields()); queryFilter.setOrderBys(possibleValueSource.getOrderByFields());
// todo - default filter
// todo - skip & limit as params // todo - skip & limit as params
queryInput.setLimit(250); queryInput.setLimit(250);
///////////////////////////////////////////////////////////////////////////////////////////////////////
// if given a default filter, make it the 'top level' filter and the one we just created a subfilter //
///////////////////////////////////////////////////////////////////////////////////////////////////////
if(input.getDefaultQueryFilter() != null)
{
input.getDefaultQueryFilter().addSubFilter(queryFilter);
queryFilter = input.getDefaultQueryFilter();
}
queryInput.setFilter(queryFilter);
QueryOutput queryOutput = new QueryAction().execute(queryInput); QueryOutput queryOutput = new QueryAction().execute(queryInput);
List<Serializable> ids = queryOutput.getRecords().stream().map(r -> r.getValue(table.getPrimaryKeyField())).toList(); List<Serializable> ids = queryOutput.getRecords().stream().map(r -> r.getValue(table.getPrimaryKeyField())).toList();
List<QPossibleValue<?>> qPossibleValues = possibleValueTranslator.buildTranslatedPossibleValueList(possibleValueSource, ids); List<QPossibleValue<?>> qPossibleValues = possibleValueTranslator.buildTranslatedPossibleValueList(possibleValueSource, ids);

View File

@ -38,7 +38,7 @@ public class RenderWidgetInput extends AbstractActionInput
{ {
private QSession session; private QSession session;
private QWidgetMetaDataInterface widgetMetaData; private QWidgetMetaDataInterface widgetMetaData;
private Map<String, String> queryParams; private Map<String, String> queryParams = new HashMap<>();

View File

@ -41,12 +41,11 @@ public class ChartData implements QWidget
} }
*/ */
private String title; private String title;
private String description; private String description;
private List<String> colors; private Data chartData;
private Data chartData; private boolean isCurrency = false;
private boolean isCurrency = false; private int height;
private int height;
@ -68,9 +67,12 @@ public class ChartData implements QWidget
setDescription(description); setDescription(description);
setChartData(new ChartData.Data() setChartData(new ChartData.Data()
.withLabels(labels) .withLabels(labels)
.withDatasets(new ChartData.Data.Dataset() .withDatasets(List.of(
.withLabel(seriesLabel) new ChartData.Data.Dataset()
.withData(data))); .withLabel(seriesLabel)
.withData(data)
))
);
} }
@ -261,8 +263,8 @@ public class ChartData implements QWidget
*******************************************************************************/ *******************************************************************************/
public static class Data public static class Data
{ {
private List<String> labels; private List<String> labels;
private Dataset dataset; private List<Dataset> datasets;
@ -306,22 +308,7 @@ public class ChartData implements QWidget
*******************************************************************************/ *******************************************************************************/
public List<Dataset> getDatasets() public List<Dataset> getDatasets()
{ {
if(dataset != null) return (datasets);
{
return List.of(dataset);
}
return List.of();
}
/*******************************************************************************
** Setter for datasets
**
*******************************************************************************/
public void setDataset(Dataset dataset)
{
this.dataset = dataset;
} }
@ -330,9 +317,9 @@ public class ChartData implements QWidget
** Fluent setter for datasets ** Fluent setter for datasets
** **
*******************************************************************************/ *******************************************************************************/
public Data withDatasets(Dataset datasets) public Data withDatasets(List<Dataset> datasets)
{ {
this.dataset = datasets; this.datasets = datasets;
return (this); return (this);
} }
@ -344,8 +331,8 @@ public class ChartData implements QWidget
public static class Dataset public static class Dataset
{ {
private String label; private String label;
private String color;
private List<Number> data; private List<Number> data;
private String color;

View File

@ -0,0 +1,48 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. 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.dashboard.widgets;
/*******************************************************************************
** Model containing datastructure expected by frontend divider widget
**
*******************************************************************************/
public class DividerWidgetData implements QWidget
{
/*******************************************************************************
**
*******************************************************************************/
public DividerWidgetData()
{
}
/*******************************************************************************
** Getter for type
**
*******************************************************************************/
public String getType()
{
return WidgetType.DIVIDER.getType();
}
}

View File

@ -27,7 +27,7 @@ import java.util.Map;
/******************************************************************************* /*******************************************************************************
** Model containing datastructure expected by frontend stepper widget ** Model containing datastructure expected by frontend parent widget
** **
*******************************************************************************/ *******************************************************************************/
public class ParentWidgetData implements QWidget public class ParentWidgetData implements QWidget
@ -43,6 +43,7 @@ public class ParentWidgetData implements QWidget
private List<List<Map<String, String>>> dropdownDataList; private List<List<Map<String, String>>> dropdownDataList;
private List<String> childWidgetNameList; private List<String> childWidgetNameList;
private String dropdownNeedsSelectedText;
@ -200,4 +201,38 @@ public class ParentWidgetData implements QWidget
return (this); return (this);
} }
/*******************************************************************************
** Getter for dropdownNeedsSelectedText
**
*******************************************************************************/
public String getDropdownNeedsSelectedText()
{
return dropdownNeedsSelectedText;
}
/*******************************************************************************
** Setter for dropdownNeedsSelectedText
**
*******************************************************************************/
public void setDropdownNeedsSelectedText(String dropdownNeedsSelectedText)
{
this.dropdownNeedsSelectedText = dropdownNeedsSelectedText;
}
/*******************************************************************************
** Fluent setter for dropdownNeedsSelectedText
**
*******************************************************************************/
public ParentWidgetData withDropdownNeedsSelectedText(String dropdownNeedsSelectedText)
{
this.dropdownNeedsSelectedText = dropdownNeedsSelectedText;
return (this);
}
} }

View File

@ -30,6 +30,7 @@ public enum WidgetType
BAR_CHART("barChart"), BAR_CHART("barChart"),
CHART("chart"), CHART("chart"),
CHILD_RECORD_LIST("childRecordList"), CHILD_RECORD_LIST("childRecordList"),
DIVIDER("divider"),
GENERIC("generic"), GENERIC("generic"),
HORIZONTAL_BAR_CHART("horizontalBarChart"), HORIZONTAL_BAR_CHART("horizontalBarChart"),
HTML("html"), HTML("html"),

View File

@ -180,9 +180,10 @@ public class ParentWidgetMetaData extends QWidgetMetaData
*******************************************************************************/ *******************************************************************************/
public static class DropdownData public static class DropdownData
{ {
private String possibleValueSourceName; private String possibleValueSourceName;
private String foreignKeyFieldName; private String foreignKeyFieldName;
private String label; private String label;
private boolean isRequired;
@ -286,6 +287,40 @@ public class ParentWidgetMetaData extends QWidgetMetaData
return (this); return (this);
} }
/*******************************************************************************
** Getter for isRequired
**
*******************************************************************************/
public boolean getIsRequired()
{
return isRequired;
}
/*******************************************************************************
** Setter for isRequired
**
*******************************************************************************/
public void setIsRequired(boolean isRequired)
{
this.isRequired = isRequired;
}
/*******************************************************************************
** Fluent setter for isRequired
**
*******************************************************************************/
public DropdownData withIsRequired(boolean isRequired)
{
this.isRequired = isRequired;
return (this);
}
} }
} }