Integrating an external dynamic form provider to GeneXus Flow

Unofficial Content
This documentation is valid for:

It’s possible to integrate a dynamic form manager and substitute the one that comes by default with GXflow. In this way, you can associate dynamic forms defined in a system external to GXFlow to the tasks of a process; you can also invoke the program in charge of presenting said form during task execution.

Implementing a GeneXus Extension to provide dynamic forms

You must implement a provider that allows displaying the list of dynamic forms of an external provider at the moment when the user is going to select a form to associate it with a task.

Dynamic-Form - GXFlow - Select

To do this, you must implement a GeneXus Extension. Read the following Getting Started to know more about Extensions.

All the classes and interface that are needed to do this are in the Artech.Gxpm.Common.DynamicForms namespace, and are contained in the Artech.Gxpm.Common.dll that you can find in the root directory of the GeneXus installation.

To create a dynamic form provider, first the class which implements the extension’s IGxPackage interface must implement the IHasCustomDynamicFormsProvider interface as follows:

public interface IHasCustomDynamicFormsProvider
{
    IDynamicFormsProvider GetDynamicFormsProvider();
}

The GetDynamicFormsProvider method returns the provider that must implement the IDynamicFormsProvider interface:

public interface IDynamicFormsProvider
{
    bool ClientShouldCacheValues { get; }
    IEnumerable<DynamicFormHeader> GetForms(KnowledgeBase kb);
    DynamicForm GetForm(KnowledgeBase kb, Guid guid, int version);
}

If the ClientShouldCacheValues property returns value True, then it means that all the form metadata will be cached, which means that it’s only asked once to the provider.

The GetForms method returns an enumerated with the metadata from the forms’ headers, DynamicFormHeader has the header’s properties:

    Guid Guid
    int Version
    string Name

The GetForm method returns a specific form’s complete metadata.DynamicForm has two properties:

    DynamicFormHeader Header
    IEnumerable<DynamicFormElement> Elements

The Elements property returns the metadata of the form’s elements. DynamicFormElement has the following properties:

   Guid Guid
   int Version
   string Name
   DynamicFormElementType Type
   int Length

DynamicFormElementType  is an enumerated with the valid types for an element:

    Numeric
    Character
    Boolean
    Date
    Datetime

Invocating dynamic forms

For the GXflow Client application to invoke the external program that will be in charge of showing the dynamic forms, you must go to “Server settings > Application “ and set the  Dynamic Forms Provider property with the value “External”. After saving this data, the Dynamic Forms Invoker URL property will appear, where you must configure the complete or relative URL to the web object that will be in charge of displaying the dynamic forms. If you use package (Java generator), include this as well.

Dynamic-Form - GXFlow - Invocating

The GXflow client will invoke said URL using the GeneXus Link command, and passing the following parameters:

1) Application GUID
2) Code of Process Definition
3) Code of Process Instance
4) Code of Workitem

The parameters will eventually be encrypted according to the configuration of the Knowledge Base properties.

Examples

Form invoker

The following source code is an example of a web panel that acts as a form invoker.

parm(in: &ApplicationGUID, in: &processDefinitionId, in: &processInstanceId, in: &workitemId);

Event Start
   &WorkflowContext.Load(&processDefinitionId, &processInstanceId, &workitemId)
   &WorkflowWorkitem = &WorkflowContext.Workitem
   &WorkflowActivity = &WorkflowWorkitem.Activity
   For &WorkflowActivityApplication  in &WorkflowActivity.Applications
        If (&WorkflowActivityApplication.Application.GUID.Trim() = &ApplicationGUID.Trim())
             &Type = &WorkflowActivityApplication.Application.Type    
             If &Type = WorkflowApplicationType.DYNAMIC_FORM
                  &DynFormFormGuid = Guid.FromString(&WorkflowActivityApplication.Application.GUID.Trim())
                  &DynFormFormVer  = &WorkflowActivityApplication.Version
                   &WorkflowAttribute = &WorkflowWorkitem.GetAttributeByName(‘FORM_INSTANCE_ID’)
                   If (&WorkflowAttribute.Value.IsEmpty()) // If a dynamic form instance didn’t exist already
                        // Generates a new instance of the form with GUID = &DynFormFormGuid
                        // and version = &DynFormFormVer and saves it in the &DynFormFormInstId variable
                        ...
                         // Saves the instance’s id as metadata of the workitem in case it’s necessary to invoke it again.
                        &WorkflowAttribute.Name = ‘FORM_INSTANCE_ID’
                        &WorkflowAttribute.Value = &DynFormFormInstId.ToString()
                        &WorkflowWorkitem.AddAttribute(&WorkflowAttribute)
                        COMMIT
                   Else // If the instance already exists, retrieves the metadata
                        &DynFormFormInstId = &WorkflowAttribute.Value.ToNumeric()
                   EndIf
                   // Invokes the form with id = &DynFormFormInstId and the necessary data
                    ……..
             EndIf
        EndFf
        Exit
   EndFor
EndEvent

Managing relevant data

If in the diagram there’s mapping between relevant data and fields of the form, it’s necessary that when the form is confirmed, then the relevant data mapped in said fields is updated.

The following code is an example of a procedure that is called after confirming a form to update relevant data that has mapping with fields of the entered form.

//See previous code to know how to retrieve the &WorkflowActivityApplication variable
For &WorkflowDynamicFormFieldMapping in &WorkflowActivityApplication.DynamicFieldMappings
      &WorkflowApplicationData = &WorkflowContext.ProcessInstance.GetApplicationDataByName(&WorkflowDynamicFormFieldMapping.ApplicationDataDefinition.Name.Trim())    
      &DynamicFieldGUID = &WorkflowDynamicFormFieldMapping.DynamicField.GUID.Trim()
      &DynamicFieldVersion = &WorkflowDynamicFormFieldMapping.DynamicField.Version
      //Obtains the value (&FieldValue) and data type (&FieldValue) of the filed with GUID =  &DynamicFieldGUID and version = &DynamicFieldVersion
      …..
      // Modify the value of the relevant data with the value of the field
      Do Case
            Case &FieldType = ‘date’
                  &WorkflowApplicationData.DateValue = CtoD(&FieldValue)
            Case &FieldType = ‘numeric’
                  &WorkflowApplicationData.NumericValue = Val(&FieldValue)
            Case &FieldType = ‘char’
               &WorkflowApplicationData.CharacterValue = &FieldValue
            // Other cases
                  …..
       EndCase
      COMMIT
EndFor