Add validation check for widget names used within apps

This commit is contained in:
2024-02-20 16:53:24 -06:00
parent a9999ee8ce
commit e936468f29
2 changed files with 121 additions and 1 deletions

View File

@ -37,6 +37,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler; import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph; import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.scripts.TestScriptActionInterface; import com.kingsrook.qqq.backend.core.actions.scripts.TestScriptActionInterface;
@ -52,6 +53,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.QSupplementalInstanceMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QSupplementalInstanceMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.ParentWidgetMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType; import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment; import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
@ -158,6 +160,7 @@ public class QInstanceValidator
validateProcesses(qInstance); validateProcesses(qInstance);
validateReports(qInstance); validateReports(qInstance);
validateApps(qInstance); validateApps(qInstance);
validateWidgets(qInstance);
validatePossibleValueSources(qInstance); validatePossibleValueSources(qInstance);
validateQueuesAndProviders(qInstance); validateQueuesAndProviders(qInstance);
validateJoins(qInstance); validateJoins(qInstance);
@ -1546,12 +1549,53 @@ public class QInstanceValidator
} }
} }
} }
//////////////////////
// validate widgets //
//////////////////////
for(String widgetName : CollectionUtils.nonNullList(app.getWidgets()))
{
assertCondition(qInstance.getWidget(widgetName) != null, "App " + appName + " widget " + widgetName + " is not a recognized widget.");
}
}); });
} }
} }
/*******************************************************************************
**
*******************************************************************************/
private void validateWidgets(QInstance qInstance)
{
if(CollectionUtils.nullSafeHasContents(qInstance.getWidgets()))
{
qInstance.getWidgets().forEach((widgetName, widget) ->
{
assertCondition(Objects.equals(widgetName, widget.getName()), "Inconsistent naming for widget: " + widgetName + "/" + widget.getName() + ".");
if(assertCondition(widget.getCodeReference() != null, "Missing codeReference for widget: " + widgetName))
{
validateSimpleCodeReference("Widget " + widgetName + " code reference: ", widget.getCodeReference(), AbstractWidgetRenderer.class);
}
if(widget instanceof ParentWidgetMetaData parentWidgetMetaData)
{
if(assertCondition(CollectionUtils.nullSafeHasContents(parentWidgetMetaData.getChildWidgetNameList()), "Missing child widgets for parent widget: " + widget.getName()))
{
for(String childWidgetName : parentWidgetMetaData.getChildWidgetNameList())
{
assertCondition(qInstance.getWidget(childWidgetName) != null, "Unrecognized child widget name [" + childWidgetName + "] in parent widget: " + widget.getName());
}
}
}
}
);
}
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -31,6 +31,9 @@ import java.util.function.Function;
import com.kingsrook.qqq.backend.core.BaseTest; import com.kingsrook.qqq.backend.core.BaseTest;
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer;
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
import com.kingsrook.qqq.backend.core.actions.dashboard.PersonsByCreateDateBarChart;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer;
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ParentWidgetRenderer;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
@ -46,6 +49,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.ParentWidgetMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType; import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment; import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
@ -803,7 +807,7 @@ class QInstanceValidatorTest extends BaseTest
** **
*******************************************************************************/ *******************************************************************************/
@Test @Test
void testChildNotInAnySections() void testAppChildNotInAnySections()
{ {
QTableMetaData table = new QTableMetaData().withName("test") QTableMetaData table = new QTableMetaData().withName("test")
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME) .withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
@ -822,6 +826,19 @@ class QInstanceValidatorTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testAppUnrecognizedWidgetName()
{
QAppMetaData app = new QAppMetaData().withName("test")
.withWidgets(List.of("no-such-widget"));
assertValidationFailureReasons((qInstance) -> qInstance.addApp(app), "not a recognized widget");
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -1813,6 +1830,65 @@ class QInstanceValidatorTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testWidgetNaming()
{
String name = PersonsByCreateDateBarChart.class.getSimpleName();
assertValidationFailureReasons((qInstance) -> qInstance.getWidget(name).withName(null),
"Inconsistent naming for widget");
assertValidationFailureReasons((qInstance) -> qInstance.getWidget(name).withName(""),
"Inconsistent naming for widget");
assertValidationFailureReasons((qInstance) -> qInstance.getWidget(name).withName("wrongName"),
"Inconsistent naming for widget");
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testWidgetCodeReference()
{
String name = PersonsByCreateDateBarChart.class.getSimpleName();
assertValidationFailureReasons((qInstance) -> qInstance.getWidget(name).withCodeReference(null),
"Missing codeReference for widget");
assertValidationFailureReasons((qInstance) -> qInstance.getWidget(name).withCodeReference(new QCodeReference(ArrayList.class)),
"CodeReference is not of the expected type: class " + AbstractWidgetRenderer.class.getName());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testParentWidgets()
{
assertValidationFailureReasons((qInstance) -> qInstance.addWidget(new ParentWidgetMetaData()
.withName("parentWidget")
.withCodeReference(new QCodeReference(ParentWidgetRenderer.class))
),
"Missing child widgets");
assertValidationFailureReasons((qInstance) -> qInstance.addWidget(new ParentWidgetMetaData()
.withChildWidgetNameList(List.of("noSuchWidget"))
.withName("parentWidget")
.withCodeReference(new QCodeReference(ParentWidgetRenderer.class))
),
"Unrecognized child widget name");
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/