From 7ab2f332e9dd2ac5892272ce736255f87d57730f Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 14 Jun 2024 08:57:24 -0500 Subject: [PATCH] CE-1113 Add Map of HelpContent at instance and table levels --- .../core/actions/metadata/MetaDataAction.java | 2 + .../QInstanceHelpContentManager.java | 59 ++++++- .../actions/metadata/MetaDataOutput.java | 27 +++- .../core/model/metadata/QInstance.java | 77 ++++++++- .../frontend/QFrontendTableMetaData.java | 17 +- .../model/metadata/tables/QTableMetaData.java | 75 +++++++++ .../QInstanceHelpContentManagerTest.java | 147 ++++++++++++++++++ 7 files changed, 395 insertions(+), 9 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/metadata/MetaDataAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/metadata/MetaDataAction.java index 403d94e3..d8bc012e 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/metadata/MetaDataAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/metadata/MetaDataAction.java @@ -218,6 +218,8 @@ public class MetaDataAction metaDataOutput.setEnvironmentValues(metaDataInput.getInstance().getEnvironmentValues()); + metaDataOutput.setHelpContents(metaDataInput.getInstance().getHelpContent()); + // todo post-customization - can do whatever w/ the result if you want? return metaDataOutput; diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManager.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManager.java index ed5d69da..02376ff3 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManager.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManager.java @@ -105,14 +105,21 @@ public class QInstanceHelpContentManager for(String part : key.split(";")) { String[] parts = part.split(":"); - nameValuePairs.put(parts[0], parts[1]); + if(parts.length > 1) + { + nameValuePairs.put(parts[0], parts[1]); + } + else + { + LOG.info("Discarding help content with key that does not contain name:value format", logPair("key", key), logPair("id", record.getValue("id"))); + } } String tableName = nameValuePairs.get("table"); String processName = nameValuePairs.get("process"); String fieldName = nameValuePairs.get("field"); String sectionName = nameValuePairs.get("section"); - String stepName = nameValuePairs.get("step"); + String stepName = nameValuePairs.get("step"); String widgetName = nameValuePairs.get("widget"); String slotName = nameValuePairs.get("slot"); @@ -143,7 +150,7 @@ public class QInstanceHelpContentManager /////////////////////////////////////////////////////////////////////////////////// if(StringUtils.hasContent(tableName)) { - processHelpContentForTable(key, tableName, sectionName, fieldName, roles, helpContent); + processHelpContentForTable(key, tableName, sectionName, fieldName, slotName, roles, helpContent); } else if(StringUtils.hasContent(processName)) { @@ -153,6 +160,10 @@ public class QInstanceHelpContentManager { processHelpContentForWidget(key, widgetName, slotName, roles, helpContent); } + else if(nameValuePairs.containsKey("instanceLevel")) + { + processHelpContentForInstance(key, slotName, roles, helpContent); + } } catch(Exception e) { @@ -165,7 +176,7 @@ public class QInstanceHelpContentManager /******************************************************************************* ** *******************************************************************************/ - private static void processHelpContentForTable(String key, String tableName, String sectionName, String fieldName, Set roles, QHelpContent helpContent) + private static void processHelpContentForTable(String key, String tableName, String sectionName, String fieldName, String slotName, Set roles, QHelpContent helpContent) { QTableMetaData table = QContext.getQInstance().getTable(tableName); if(table == null) @@ -212,7 +223,21 @@ public class QInstanceHelpContentManager } else { - LOG.info("Unrecognized key format for table help content", logPair("key", key)); + if(!StringUtils.hasContent(slotName)) + { + LOG.info("Missing slot name in table-level help content", logPair("key", key)); + } + else + { + if(helpContent != null) + { + table.withHelpContent(slotName, helpContent); + } + else + { + table.removeHelpContent(slotName, roles); + } + } } } @@ -307,6 +332,30 @@ public class QInstanceHelpContentManager + /******************************************************************************* + ** + *******************************************************************************/ + private static void processHelpContentForInstance(String key, String slotName, Set roles, QHelpContent helpContent) + { + if(!StringUtils.hasContent(slotName)) + { + LOG.info("Missing slot name in instance-level help content", logPair("key", key)); + } + else + { + if(helpContent != null) + { + QContext.getQInstance().withHelpContent(slotName, helpContent); + } + else + { + QContext.getQInstance().removeHelpContent(slotName, roles); + } + } + } + + + /******************************************************************************* ** add a help content object to a list - replacing an entry in the list with the ** same roles if one is found. diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/metadata/MetaDataOutput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/metadata/MetaDataOutput.java index 40174412..717a0acf 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/metadata/MetaDataOutput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/metadata/MetaDataOutput.java @@ -32,6 +32,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMe import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendReportMetaData; import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendWidgetMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent; /******************************************************************************* @@ -47,8 +48,9 @@ public class MetaDataOutput extends AbstractActionOutput private Map widgets; private Map environmentValues; - private List appTree; - private QBrandingMetaData branding; + private List appTree; + private QBrandingMetaData branding; + private Map> helpContents; @@ -226,4 +228,25 @@ public class MetaDataOutput extends AbstractActionOutput this.environmentValues = environmentValues; } + + + /******************************************************************************* + ** Setter for helpContents + ** + *******************************************************************************/ + public void setHelpContents(Map> helpContents) + { + this.helpContents = helpContents; + } + + + + /******************************************************************************* + ** Getter for helpContents + ** + *******************************************************************************/ + public Map> getHelpContents() + { + return helpContents; + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java index 1c5ecbe6..3efc1cda 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/QInstance.java @@ -33,6 +33,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.kingsrook.qqq.backend.core.actions.metadata.JoinGraph; import com.kingsrook.qqq.backend.core.actions.metadata.MetaDataAction; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.instances.QInstanceHelpContentManager; import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey; import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput; import com.kingsrook.qqq.backend.core.model.actions.metadata.MetaDataInput; @@ -44,6 +45,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.branding.QBrandingMetaData; import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface; import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNode; import com.kingsrook.qqq.backend.core.model.metadata.frontend.AppTreeNodeType; +import com.kingsrook.qqq.backend.core.model.metadata.help.HelpRole; +import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent; import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; import com.kingsrook.qqq.backend.core.model.metadata.messaging.QMessagingProviderMetaData; @@ -79,7 +82,7 @@ public class QInstance private QAuthenticationMetaData authentication = null; private QBrandingMetaData branding = null; private Map automationProviders = new HashMap<>(); - private Map messagingProviders = new HashMap<>(); + private Map messagingProviders = new HashMap<>(); //////////////////////////////////////////////////////////////////////////////////////////// // Important to use LinkedHashmap here, to preserve the order in which entries are added. // @@ -100,6 +103,8 @@ public class QInstance private Map supplementalMetaData = new LinkedHashMap<>(); + protected Map> helpContent; + private String deploymentMode; private Map environmentValues = new LinkedHashMap<>(); private String defaultTimeZoneId = "UTC"; @@ -1380,4 +1385,74 @@ public class QInstance this.schedulableTypes = schedulableTypes; } + + + /******************************************************************************* + ** Getter for helpContent + *******************************************************************************/ + public Map> getHelpContent() + { + return (this.helpContent); + } + + + + /******************************************************************************* + ** Setter for helpContent + *******************************************************************************/ + public void setHelpContent(Map> helpContent) + { + this.helpContent = helpContent; + } + + + + /******************************************************************************* + ** Fluent setter for helpContent + *******************************************************************************/ + public QInstance withHelpContent(Map> helpContent) + { + this.helpContent = helpContent; + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for adding 1 helpContent (for a slot) + *******************************************************************************/ + public QInstance withHelpContent(String slot, QHelpContent helpContent) + { + if(this.helpContent == null) + { + this.helpContent = new HashMap<>(); + } + + List listForSlot = this.helpContent.computeIfAbsent(slot, (k) -> new ArrayList<>()); + QInstanceHelpContentManager.putHelpContentInList(helpContent, listForSlot); + + return (this); + } + + + + /******************************************************************************* + ** remove a helpContent for a slot based on its set of roles + *******************************************************************************/ + public void removeHelpContent(String slot, Set roles) + { + if(this.helpContent == null) + { + return; + } + + List listForSlot = this.helpContent.get(slot); + if(listForSlot == null) + { + return; + } + + QInstanceHelpContentManager.removeHelpContentByRoleSetFromList(roles, listForSlot); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java index ef93e024..2f93c109 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/frontend/QFrontendTableMetaData.java @@ -39,6 +39,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent; import com.kingsrook.qqq.backend.core.model.metadata.sharing.ShareableTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability; import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin; @@ -76,7 +77,8 @@ public class QFrontendTableMetaData private boolean usesVariants; private String variantTableLabel; - private ShareableTableMetaData shareableTableMetaData; + private ShareableTableMetaData shareableTableMetaData; + private Map> helpContents; ////////////////////////////////////////////////////////////////////////////////// // do not add setters. take values from the source-object in the constructor!! // @@ -172,6 +174,8 @@ public class QFrontendTableMetaData usesVariants = true; variantTableLabel = actionInput.getInstance().getTable(backend.getVariantOptionsTableName()).getLabel(); } + + this.helpContents = tableMetaData.getHelpContent(); } @@ -382,4 +386,15 @@ public class QFrontendTableMetaData { return shareableTableMetaData; } + + + + /******************************************************************************* + ** Getter for helpContents + ** + *******************************************************************************/ + public Map> getHelpContents() + { + return helpContents; + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/QTableMetaData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/QTableMetaData.java index 9819f5b3..f2933188 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/QTableMetaData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/QTableMetaData.java @@ -34,6 +34,7 @@ import java.util.Optional; import java.util.Set; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.instances.QInstanceHelpContentManager; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.data.QRecordEntity; import com.kingsrook.qqq.backend.core.model.data.QRecordEntityField; @@ -43,6 +44,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface; import com.kingsrook.qqq.backend.core.model.metadata.audits.QAuditRules; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.help.HelpRole; +import com.kingsrook.qqq.backend.core.model.metadata.help.QHelpContent; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; import com.kingsrook.qqq.backend.core.model.metadata.permissions.MetaDataWithPermissionRules; @@ -110,6 +113,8 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData private ShareableTableMetaData shareableTableMetaData; + protected Map> helpContent; + /******************************************************************************* @@ -1446,4 +1451,74 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData return (this); } + + + /******************************************************************************* + ** Getter for helpContent + *******************************************************************************/ + public Map> getHelpContent() + { + return (this.helpContent); + } + + + + /******************************************************************************* + ** Setter for helpContent + *******************************************************************************/ + public void setHelpContent(Map> helpContent) + { + this.helpContent = helpContent; + } + + + + /******************************************************************************* + ** Fluent setter for helpContent + *******************************************************************************/ + public QTableMetaData withHelpContent(Map> helpContent) + { + this.helpContent = helpContent; + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for adding 1 helpContent (for a slot) + *******************************************************************************/ + public QTableMetaData withHelpContent(String slot, QHelpContent helpContent) + { + if(this.helpContent == null) + { + this.helpContent = new HashMap<>(); + } + + List listForSlot = this.helpContent.computeIfAbsent(slot, (k) -> new ArrayList<>()); + QInstanceHelpContentManager.putHelpContentInList(helpContent, listForSlot); + + return (this); + } + + + + /******************************************************************************* + ** remove a helpContent for a slot based on its set of roles + *******************************************************************************/ + public void removeHelpContent(String slot, Set roles) + { + if(this.helpContent == null) + { + return; + } + + List listForSlot = this.helpContent.get(slot); + if(listForSlot == null) + { + return; + } + + QInstanceHelpContentManager.removeHelpContentByRoleSetFromList(roles, listForSlot); + } + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManagerTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManagerTest.java index 3148b508..51af9eaa 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManagerTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceHelpContentManagerTest.java @@ -23,7 +23,9 @@ package com.kingsrook.qqq.backend.core.instances; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.function.Function; import com.kingsrook.qqq.backend.core.BaseTest; import com.kingsrook.qqq.backend.core.actions.dashboard.PersonsByCreateDateBarChart; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; @@ -31,9 +33,12 @@ import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.logging.QCollectingLogger; +import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.model.helpcontent.HelpContent; import com.kingsrook.qqq.backend.core.model.helpcontent.HelpContentMetaDataProvider; import com.kingsrook.qqq.backend.core.model.helpcontent.HelpContentRole; @@ -155,6 +160,108 @@ class QInstanceHelpContentManagerTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testTable() throws QException + { + ///////////////////////////////////// + // get the instance from base test // + ///////////////////////////////////// + QInstance qInstance = QContext.getQInstance(); + new HelpContentMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null); + + //////////////////////////////////////////////////////// + // first, assert there's no help content on the table // + //////////////////////////////////////////////////////// + assertThat(qInstance.getTable(TestUtils.TABLE_NAME_PERSON).getHelpContent()).isNullOrEmpty(); + + ////////////////////////////////////// + // insert a record missing its slot // + ////////////////////////////////////// + new InsertAction().execute(new InsertInput(HelpContent.TABLE_NAME).withRecordEntity(new HelpContent() + .withId(1) + .withKey("table:person") + .withContent("content") + .withRole(HelpContentRole.ALL_SCREENS.getId()))); + + ////////////////////////////////// + // assert still no help content // + ////////////////////////////////// + assertThat(qInstance.getTable(TestUtils.TABLE_NAME_PERSON).getHelpContent()).isNullOrEmpty(); + + ////////////////////////// + // insert a good record // + ////////////////////////// + new InsertAction().execute(new InsertInput(HelpContent.TABLE_NAME).withRecordEntity(new HelpContent() + .withId(1) + .withKey("table:person;slot:someSlot") + .withContent("content") + .withRole(HelpContentRole.ALL_SCREENS.getId()))); + + /////////////////////////////////////////////////////////////////////////////////////////////// + // now - post-insert customizer should have automatically added help content to the instance // + /////////////////////////////////////////////////////////////////////////////////////////////// + Map> helpContent = qInstance.getTable(TestUtils.TABLE_NAME_PERSON).getHelpContent(); + assertEquals(1, helpContent.size()); + assertEquals(1, helpContent.get("someSlot").size()); + assertEquals("content", helpContent.get("someSlot").get(0).getContent()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testInstance() throws QException + { + ///////////////////////////////////// + // get the instance from base test // + ///////////////////////////////////// + QInstance qInstance = QContext.getQInstance(); + new HelpContentMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null); + + /////////////////////////////////////////////////////////// + // first, assert there's no help content on the instance // + /////////////////////////////////////////////////////////// + assertThat(qInstance.getHelpContent()).isNullOrEmpty(); + + ////////////////////////////////////// + // insert a record missing its slot // + ////////////////////////////////////// + new InsertAction().execute(new InsertInput(HelpContent.TABLE_NAME).withRecordEntity(new HelpContent() + .withId(1) + .withKey("instanceLevel:true") + .withContent("content") + .withRole(HelpContentRole.ALL_SCREENS.getId()))); + + ////////////////////////////////// + // assert still no help content // + ////////////////////////////////// + assertThat(qInstance.getHelpContent()).isNullOrEmpty(); + + ////////////////////////// + // insert a good record // + ////////////////////////// + new InsertAction().execute(new InsertInput(HelpContent.TABLE_NAME).withRecordEntity(new HelpContent() + .withId(1) + .withKey("instanceLevel:true;slot:someSlot") + .withContent("content") + .withRole(HelpContentRole.ALL_SCREENS.getId()))); + + /////////////////////////////////////////////////////////////////////////////////////////////// + // now - post-insert customizer should have automatically added help content to the instance // + /////////////////////////////////////////////////////////////////////////////////////////////// + Map> helpContent = qInstance.getHelpContent(); + assertEquals(1, helpContent.size()); + assertEquals(1, helpContent.get("someSlot").size()); + assertEquals("content", helpContent.get("someSlot").get(0).getContent()); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -285,6 +392,46 @@ class QInstanceHelpContentManagerTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testMalformedKeys() throws QException + { + QInstance qInstance = QContext.getQInstance(); + new HelpContentMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null); + + QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(QInstanceHelpContentManager.class); + + Function helpContentCreator = (String key) -> new HelpContent() + .withId(1) + .withKey(key) + .withContent("v1") + .withRole(HelpContentRole.INSERT_SCREEN.getId()).toQRecord(); + + QInstanceHelpContentManager.processHelpContentRecord(qInstance, helpContentCreator.apply("foo;bar:baz")); + assertThat(collectingLogger.getCollectedMessages()).hasSize(1); + assertThat(collectingLogger.getCollectedMessages().get(0).getMessage()).contains("Discarding help content with key that does not contain name:value format"); + collectingLogger.clear(); + + QInstanceHelpContentManager.processHelpContentRecord(qInstance, helpContentCreator.apply(null)); + assertThat(collectingLogger.getCollectedMessages()).hasSize(1); + assertThat(collectingLogger.getCollectedMessages().get(0).getMessage()).contains("Error processing a helpContent record"); + collectingLogger.clear(); + + QInstanceHelpContentManager.processHelpContentRecord(qInstance, helpContentCreator.apply("table:notATable;slot:foo")); + assertThat(collectingLogger.getCollectedMessages()).hasSize(1); + assertThat(collectingLogger.getCollectedMessages().get(0).getMessage()).contains("Unrecognized table in help content"); + collectingLogger.clear(); + + QInstanceHelpContentManager.processHelpContentRecord(qInstance, helpContentCreator.apply("table:" + TestUtils.TABLE_NAME_PERSON)); + assertThat(collectingLogger.getCollectedMessages()).hasSize(1); + assertThat(collectingLogger.getCollectedMessages().get(0).getMessage()).contains("Missing slot name"); + collectingLogger.clear(); + } + + + /******************************************************************************* ** *******************************************************************************/