10-16-2007 10:04 AM
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="wf:LPRvalidation">
<swimlane name="initiator"/>
<start-state name="start">
<task name="lwf:submitReviewAndApprovalTask" swimlane="initiator" />
<event type="node-leave">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
if (!bpm_package.children[i].hasAspect("lpr:DocumentStatus"))
{
bpm_package.children[i].addAspect("lpr:DocumentStatus");
}
logger.log("Leave Start Node : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
<action class="lpr.alfresco.repo.workflow.jbpm.ReviewDocuments"/>
</event>
<transition name="" to="startreview"/>
</start-state>
<node name="startreview">
<action class="org.alfresco.repo.workflow.jbpm.ForEachFork">
<foreach>#{lwf_reviewAssignees}</foreach>
<var>reviewer</var>
</action>
<event type="node-enter">
<script>
<variable name="lwf_reviewCount" access="write" />
<expression>
lwf_reviewCount = 0;
</expression>
</script>
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
<variable name="lpr_DocumentStatus" access="write" />
<expression>
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "In Review";
bpm_package.children[i].save();
logger.log("Enter Node Start Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</expression>
</script>
</action>
</event>
<transition name="review" to="review"/>
</node>
<task-node name="review">
<task name="lwf_reviewTask">
<assignment class="org.alfresco.repo.workflow.jbpm.AlfrescoAssignment">
<actor>#{reviewer}</actor>
</assignment>
</task>
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition name="reject" to="endReview" />
<transition name="approve" to="endReview" >
<script>
<variable name="lwf_reviewCount" access="read,write" />
<expression>
lwf_reviewCount = lwf_reviewCount + 1;
</expression>
</script>
</transition>
</task-node>
<join name="endReview">
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node End Review (Join) : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition to="isreviewed" />
</join>
<decision name="isreviewed">
<event type="node-enter">
<script>
<variable name="lwf_reviewerCount" access="Write"/>
<variable name="lwf_requiredReviewerPercent" access="Write"/>
<variable name="lwf_actualReviewerPercent" access="Write"/>
<expression>
lwf_requiredReviewerPercent = lwf_requiredReviewPercent;
lwf_reviewerCount = lwf_reviewAssignees.size();
lwf_actualReviewerPercent = ((lwf_reviewCount * 100) / lwf_reviewerCount);
</expression>
</script>
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node Is Reviewed : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition name="reject" to="rejectedReview"/>
<!–transition name="approve" to="approvedReview"–>
<transition name="approve" to="startapproval">
<condition>#{lwf_actualReviewerPercent >= lwf_requiredReviewerPercent}</condition>
</transition>
</decision>
<task-node name="rejectedReview">
<task name="lwf:rejectedReviewTask" swimlane="initiator" />
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "Draft";
bpm_package.children[i].save();
logger.log("Enter Node Reject Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition to="end"/>
</task-node>
<!–task-node name="approvedReview">
<task name="lwf:approvedReviewTask" swimlane="initiator" />
<transition to="startapproval"/>
</task-node–>
<node name="startapproval">
<action class="org.alfresco.repo.workflow.jbpm.ForEachFork">
<foreach>#{lwf_approvalAssignees}</foreach>
<var>approval</var>
</action>
<event type="node-enter">
<script>
<variable name="lwf_approvalCount" access="write" />
<expression>
lwf_approvalCount = 0;
</expression>
</script>
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "For Approval";
bpm_package.children[i].save();
logger.log("Enter Node Start Approval : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition name="approval" to="approval"/>
</node>
<task-node name="approval">
<task name="lwf_approvalTask">
<assignment class="org.alfresco.repo.workflow.jbpm.AlfrescoAssignment">
<actor>#{approval}</actor>
</assignment>
</task>
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node Approval : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition name="reject" to="endApproval" />
<transition name="approve" to="endApproval" >
<script>
<variable name="lwf_approvalCount" access="read,write" />
<expression>
lwf_approvalCount = lwf_approvalCount + 1;
</expression>
</script>
</transition>
</task-node>
<join name="endApproval">
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node End Approval (Join) : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition to="isapproved" />
</join>
<decision name="isapproved">
<event type="node-enter">
<script>
<variable name="lwf_approbatorCount" access="Write"/>
<variable name="lwf_requiredApprobatorPercent" access="Write"/>
<variable name="lwf_actualApprobatorPercent" access="Write"/>
<expression>
lwf_requiredApprobatorPercent = lwf_requiredApprovalPercent;
lwf_approbatorCount = lwf_approvalAssignees.size();
lwf_actualApprobatorPercent = ((lwf_approvalCount * 100) / lwf_approbatorCount);
</expression>
</script>
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node Is Approved : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition name="reject" to="rejectedApproval"/>
<transition name="approve" to="approvedApproval">
<condition>#{lwf_actualApprobatorPercent >= lwf_requiredApprobatorPercent}</condition>
</transition>
</decision>
<task-node name="rejectedApproval">
<task name="lwf:rejectedApprovalTask" swimlane="initiator" />
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "Draft";
bpm_package.children[i].save();
logger.log("Enter Node Reject Approval : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition to="end"/>
</task-node>
<task-node name="approvedApproval">
<task name="lwf:approvedApprovalTask" swimlane="initiator" />
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "Approved";
bpm_package.children[i].save();
logger.log("Enter Node Approved Approval : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
<transition to="end"/>
</task-node>
<end-state name="end">
<event type="node-enter">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
logger.log("Enter Node End : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
</event>
</end-state>
</process-definition>
La ligne de code de test excecutée est la suivante :<action class="lpr.alfresco.repo.workflow.jbpm.ReviewDocuments"/>
le code de l'action est le suivant :package lpr.alfresco.repo.workflow.jbpm;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.jbpm.JBPMNode;
import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.apache.log4j.Logger;
import org.jbpm.graph.exe.ExecutionContext;
import org.springframework.beans.factory.BeanFactory;
public class ReviewDocuments extends JBPMSpringActionHandler {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(ReviewDocuments.class);
private BeanFactory factory;
// Property names
public static final QName PROP_DOCUMENT_NAME = QName.createQName("cm","name");
public static final QName PROP_DOCUMENT_STATUS = QName.createQName("lpr.model","DocumentStatus");
@Override
protected void initialiseHandler(BeanFactory factory) {
this.factory = factory;
}
public void execute(ExecutionContext executionContext) throws Exception {
try {
Object res = executionContext.getContextInstance().getVariable("bpm_package");
if(res == null) {
//never enters here
logger.fatal("bpm_package is null");
return;
}
final NodeRef nodeRef = ((JBPMNode) res).getNodeRef();
if(nodeRef == null) {
//never enters here
logger.fatal("NodeRef is null");
return;
}
//prints value
logger.fatal("Node ref id:" + nodeRef.getId());
NodeService nodeService = (NodeService) this.factory.getBean("nodeService");
//prints value
logger.fatal("Prop name = " + nodeService.getProperty(nodeRef, ContentModel.PROP_NAME));
//prints value
logger.fatal("Prop created= " + nodeService.getProperty(nodeRef, ContentModel.PROP_CREATED));
//prints value
logger.fatal("Prop uuid = " + nodeService.getProperty(nodeRef, ContentModel.PROP_NODE_UUID));
//prints value
logger.fatal("Prop Doc Name = " + nodeService.getProperty(nodeRef, PROP_DOCUMENT_NAME));
// prints value
logger.fatal("Prop Doc Status = " + nodeService.getProperty(nodeRef, PROP_DOCUMENT_STATUS));
if(nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT) != null) {
// never enters here
logger.warn("Content property is not null");
}
ContentService contentService = (ContentService) this.factory.getBean("contentService");
ContentReader contentReader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
if(contentReader == null) {
//always goes here
logger.fatal("Content reader not found");
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Le resultat d'execution est le suivant :15:53:00,010 WARN [web.app.ResourceBundleWrapper] Failed to find I18N message string key: lwf_reviewers
15:53:00,010 WARN [web.app.ResourceBundleWrapper] Failed to find I18N message string key: lwf_approvals
15:53:00,010 WARN [web.app.ResourceBundleWrapper] Failed to find I18N message string key: lwf_review_options
15:53:25,822 DEBUG [repo.jscript.RhinoScriptProcessor] Imports resolved, adding resource '_root' content:
for (var i = 0; i < bpm_package.children.length; i++) { if (!bpm_package.children[i].hasAspect("lpr:DocumentStatus")) { bpm_package.children[i].addAspect("lpr:DocumentStatus"); } logger.log("Leave Start Node : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:25,822 DEBUG [repo.jscript.RhinoScriptProcessor] Script content resolved to:
for (var i = 0; i < bpm_package.children.length; i++) { if (!bpm_package.children[i].hasAspect("lpr:DocumentStatus")) { bpm_package.children[i].addAspect("lpr:DocumentStatus"); } logger.log("Leave Start Node : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:26,650 DEBUG [repo.jscript.ScriptLogger] Leave Start Node : In Review
15:53:26,650 DEBUG [repo.jscript.RhinoScriptProcessor] Time to execute script: 828ms
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Node ref id:29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop name = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop created= Tue Oct 16 15:53:24 CEST 2007
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop uuid = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Name = null
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Status = null
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Content reader not found
15:53:27,150 DEBUG [repo.jscript.RhinoScriptProcessor] Imports resolved, adding resource '_root' content:
for (var i = 0; i < bpm_package.children.length; i++) { bpm_package.children[i].properties["lpr:DocumentStatus"] = "In Review"; bpm_package.children[i].save(); logger.log("Enter Node Start Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:27,150 DEBUG [repo.jscript.RhinoScriptProcessor] Script content resolved to:
for (var i = 0; i < bpm_package.children.length; i++) { bpm_package.children[i].properties["lpr:DocumentStatus"] = "In Review"; bpm_package.children[i].save(); logger.log("Enter Node Start Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:27,291 DEBUG [repo.jscript.ScriptLogger] Enter Node Start Review : In Review
15:53:27,291 DEBUG [repo.jscript.RhinoScriptProcessor] Time to execute script: 141ms
15:53:27,307 DEBUG [repo.jscript.RhinoScriptProcessor] Imports resolved, adding resource '_root' content:
lwf_reviewAssignees
15:53:27,307 DEBUG [repo.jscript.RhinoScriptProcessor] Script content resolved to:
lwf_reviewAssignees
15:53:27,322 DEBUG [repo.jscript.RhinoScriptProcessor] Time to execute script: 15ms
15:53:27,353 DEBUG [repo.jscript.RhinoScriptProcessor] Imports resolved, adding resource '_root' content:
for (var i = 0; i < bpm_package.children.length; i++) { logger.log("Enter Node Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:27,353 DEBUG [repo.jscript.RhinoScriptProcessor] Script content resolved to:
for (var i = 0; i < bpm_package.children.length; i++) { logger.log("Enter Node Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]); }
15:53:27,369 DEBUG [repo.jscript.ScriptLogger] Enter Node Review : In Review
15:53:27,369 DEBUG [repo.jscript.RhinoScriptProcessor] Time to execute script: 16ms
15:53:27,416 DEBUG [repo.jscript.RhinoScriptProcessor] Imports resolved, adding resource '_root' content:
reviewer
15:53:27,416 DEBUG [repo.jscript.RhinoScriptProcessor] Script content resolved to:
reviewer
15:53:27,432 DEBUG [repo.jscript.RhinoScriptProcessor] Time to execute script: 16ms
Dans ce résultat, je n'arrive pas à faire afficher les informations relatives au document tel que le status, le nom du document en clair et non le node ID, …15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Node ref id:29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop name = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop created= Tue Oct 16 15:53:24 CEST 2007
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop uuid = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Name = null
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Status = null
Si quelqu'un peut m'aider car je patauge sérieusement.10-17-2007 02:38 AM
J'essaie de récuperer les informations relatives au document sur lequel j'ai lancé un Workflow de validation avancé.Dans le code Java, il manque l'accès aux enfants du "bpm_package" (ce que tu as correctement fait dans le code ECMAScript).La ligne de code de test excecutée est la suivante :<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.1" name="wf:LPRvalidation">
<swimlane name="initiator"/>
<start-state name="start">
<task name="lwf:submitReviewAndApprovalTask" swimlane="initiator" />
<event type="node-leave">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
for (var i = 0; i < bpm_package.children.length; i++)
{
if (!bpm_package.children[i].hasAspect("lpr:DocumentStatus"))
{
bpm_package.children[i].addAspect("lpr:DocumentStatus");
}
logger.log("Leave Start Node : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
</script>
</action>
<action class="lpr.alfresco.repo.workflow.jbpm.ReviewDocuments"/>
</event>
<transition name="" to="startreview"/>
</start-state>
…le code de l'action est le suivant :<action class="lpr.alfresco.repo.workflow.jbpm.ReviewDocuments"/>
[…]…
Object res = executionContext.getContextInstance().getVariable("bpm_package");
[…]
final NodeRef nodeRef = ((JBPMNode) res).getNodeRef();
[…]
//prints value
logger.fatal("Prop name = " + nodeService.getProperty(nodeRef, ContentModel.PROP_NAME));
Dans ce résultat, je n'arrive pas à faire afficher les informations relatives au document tel que le status, le nom du document en clair et non le node ID, …Si quelqu'un peut m'aider car je patauge sérieusement.15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Node ref id:29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop name = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop created= Tue Oct 16 15:53:24 CEST 2007
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop uuid = 29ce7ab6-7bef-11dc-9d8e-319621460cee
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Name = null
15:53:26,666 FATAL [workflow.jbpm.ReviewDocuments] Prop Doc Status = null
10-17-2007 02:57 AM
10-17-2007 03:35 AM
Dans le code Java, il manque l'accès aux enfants du "bpm_package" (ce que tu as correctement fait dans le code ECMAScript).Et en clair, cela se code comment en Java pour accéder aux enfants de "bpm_package" ??? Car Java, je débute et à vrai dire je suis un peu perdu.
for (var i = 0; i < bpm_package.children.length; i++)
{
bpm_package.children[i].properties["lpr:DocumentStatus"] = "In Review";
bpm_package.children[i].save();
logger.log("Enter Node Start Review : " + bpm_package.children[i].properties["lpr:DocumentStatus"]);
}
Mais en Java ????10-17-2007 04:06 AM
Et en clair, cela se code comment en Java pour accéder aux enfants de "bpm_package" ??? Car Java, je débute et à vrai dire je suis un peu perdu.NodeService a une méthode getChildAssocs qui retourne une liste d'associations. Les enfants sont les valeurs des getChildRef() des associations (en d'autres termes, il faut boucler sur les associations et pour chacune d'elle appeler getChildRef() pour obtenir le NodeRef de l'enfant, que l'on peut alors "explorer" –récupération de son nom, etc.— et/ou déplacer).
10-17-2007 04:23 AM
10-17-2007 05:45 AM
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(nodeRef);
for (ChildAssociationRef tchildRef : childRefs) {
final NodeRef childRef = tchildRef.getChildRef();
final String DocName = (String)nodeService.getProperty(childRef,ContentModel.PROP_NAME);
logger.fatal("Child Doc Name = " + DocName);
final String DocStatus = (String)nodeService.getProperty(childRef,PROP_DOCUMENT_STATUS);
logger.fatal("Child Doc Status = " + DocStatus);
nodeService.setProperty(childRef,PROP_DOCUMENT_STATUS,"For Approval");
}
et le résultat est le suivant :11:43:36,318 FATAL [workflow.jbpm.ReviewDocuments] Child Doc Name = 0010 - Manuel de l'utilisateur - Utilisation d'Alfresco.doc
11:43:36,318 FATAL [workflow.jbpm.ReviewDocuments] Child Doc Status = In Review
Ce code modifie également l'attribut personnalisé PROP_DOCUMENT_STATUS qui donne le status du document de In Review en For Approval
10-17-2007 05:50 AM
10-17-2007 06:25 AM
bpm_package.children[i].move(destinationFolder);
Par contre, je na sais pas quelle fonction utiliser en Java. J'ai trouver la fonction movenode, mais est-elle appropriée ? Si oui comment l'utiliser ? Dans le cas contraire, comment dois-je procéder pour copier ou déplacer un document de Workflow d'un dossier (espace) à un autres ?
10-23-2007 01:22 PM
Bon, continuons dans la lancée. Je souhaiterais maintenant déplacer mon document du dossier courrant Draft vers le dossier ..Review.Reponse ici –> http://forum.alfresco-fr.org/viewtopic.php?f=11&t=1190
Mon architecture d'approbation est le suivant :
ProcessusDraft –> Documents en version draft (accès aux rédacteurs uniquement en lecture/écriture et lecture pour les invités)
Pending Approval –> Document en attente d'approbation (accès en lecture uniquement pour les approbateurs)
Published –> Document publiés (accès en lecture uniquement aux personnes autorisées)
Review –> Document en attente de lecture (accès en lecture uniquement pour les lecteurs)
En Javascript il semblerait que l'on puisse écrire la fonction déplacer comme ceci :Par contre, je na sais pas quelle fonction utiliser en Java. J'ai trouver la fonction movenode, mais est-elle appropriée ? Si oui comment l'utiliser ? Dans le cas contraire, comment dois-je procéder pour copier ou déplacer un document de Workflow d'un dossier (espace) à un autres ?bpm_package.children[i].move(destinationFolder);
Tags
Find what you came for
We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.