Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Workflow examples

    Hi,

    We would like to add workflow/wizard functionality into our existing SmartGWT based application. I have searched forum and found those threads requesting workflow examples, but not a single line of working example code:
    So, I would like to share what I have learned so far.

    I have created a simple flow starting with fetching process state data from client-only DataSource.
    Next node is a script task which logs data.
    Then, there is a user task which displays a form in the window and allows user to enter data.
    Modified data is processed by a gateway, which compares to specified criteria.
    Then it goes to error flow and back to user form or, if data matches criteria (field1='value1')), to node saving data and finishing process.

    Here is index.html js example code:
    Code:
    <!DOCTYPE html>
    
    <html>
        <head>
    
            <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
            <title>Client</title>
    
        </head>
    
        <body>
    
            <script type="text/javascript">
                var isomorphicDir = "isomorphic/";
            </script>
    
            <script src="isomorphic/system/modules-debug/ISC_Core.js">          </script>
            <script src="isomorphic/system/modules-debug/ISC_Foundation.js">    </script>
            <script src="isomorphic/system/modules-debug/ISC_Containers.js">    </script>
            <script src="isomorphic/system/modules-debug/ISC_Grids.js">         </script>
            <script src="isomorphic/system/modules-debug/ISC_Forms.js">         </script>
            <script src="isomorphic/system/modules-debug/ISC_RichTextEditor.js"></script>
            <script src="isomorphic/system/modules-debug/ISC_Calendar.js">      </script>
            <script src="isomorphic/system/modules-debug/ISC_DataBinding.js">   </script>
            <script src="isomorphic/system/modules-debug/ISC_Workflow.js">      </script>
    
            <script src="isomorphic/skins/Graphite/load_skin.js"></script>
    
            <script type="text/javascript">
    var ds = isc.DataSource.create({
        ID: "Test",
        dataURL: "test.data.xml",
        dataFormat: "xml",
        dataProtocol: "postXML",
        fields: [
            {name: "id", type: "text", primaryKey: true},
            {name: "field1", type: "text"},
            {name: "field2", type: "text"},
        ],
        clientOnly: true
    });
    var process = isc.Process.create({
        //state: {field1: "valueA", field2: "valueB"},
        elements : [
            isc.ServiceTask.create({
                ID: "data",
                dataSource: ds,
                outputFieldList: ["id", "field1", "field2"],
                operationType: "fetch",
                criteria: {field1: "valueA"},
                nextElement: "script"
            }),
            isc.ScriptTask.create({
                ID: "script",
                inputFieldList: ["id", "field1", "field2"],
                execute: function(input, inputRecord) {
                    isc.logEcho(inputRecord, "ScriptTask");
                },
                nextElement: "form"
            }),
            isc.UserTask.create({
                ID: "form",
                inputFieldList: ["id", "field1", "field2"],
                outputFieldList: ["id", "field1", "field2"],
                targetView: isc.Window.create({
                    ID: "wnd",
                    width: 300,
                    height: 120,
                    items: [isc.DynamicForm.create({
                        ID: "df",
                        fields:[
                            {name:"id", type:"text", hidden: true},
                            {name:"field1", type:"text"},
                            {name:"field2", type:"text"},
                            {title:"Submit", type:"submit"}
                        ],
                    })]
                }),
                targetForm: "df",
                nextElement: "gate"
            }),
    //      isc.XORGateway.create({ ID: "gate", inputFieldList: "field1", criteria: advancedCriteria, failureElement: "errorFlow", nextElement: "goodFlow" }),
            isc.DecisionGateway.create({
                ID: "gate",
                inputFieldList: ["id", "field1","field2"],
                criteriaMap: {goodFlow: {field1: "value1"}, errorFlow: {field1: "value2"}},
                defaultElement: "errorFlow"
            }),
            isc.ScriptTask.create({
                ID:"goodFlow",
                inputFieldList: ["id", "field1", "field2"],
                execute: function(input, inputRecord) {
                    isc.warn("goodFlow - save");
                    isc.Window.getById("wnd").hide();
                },
                nextElement: "save"
            }),
            isc.ServiceTask.create({
                ID: "save",
                inputFieldList: ["id", "field1", "field2"],
                dataSource: ds,
                operationType: "update",
            }),
            isc.ScriptTask.create({
                ID:"errorFlow",
                inputFieldList: ["id", "field1", "field2"],
                execute: function(input, inputRecord) {
                    isc.warn("errorFlow - try again");
                },
                nextElement: "script"
            })
        ]
    });
    
    process.start();
            </script>
    
        </body>
    </html>

    and MainEntryPoint.java gwt example code:

    Code:
    package pl.com.tech4.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.data.Criteria;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.Record;
    import com.smartgwt.client.data.fields.DataSourceTextField;
    import com.smartgwt.client.types.DSDataFormat;
    import com.smartgwt.client.types.DSOperationType;
    import com.smartgwt.client.types.DSProtocol;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.util.workflow.DecisionGateway;
    import com.smartgwt.client.util.workflow.ProcessElement;
    import com.smartgwt.client.util.workflow.ScriptTask;
    import com.smartgwt.client.util.workflow.ServiceTask;
    import com.smartgwt.client.util.workflow.UserTask;
    import com.smartgwt.client.util.workflow.XORGateway;
    import com.smartgwt.client.widgets.Window;
    import com.smartgwt.client.widgets.form.DynamicForm;
    import com.smartgwt.client.widgets.form.fields.SubmitItem;
    import com.smartgwt.client.widgets.form.fields.TextItem;
    import java.util.HashMap;
    
    public class MainEntryPoint implements EntryPoint {
    
        @Override
        public void onModuleLoad() {
    
            layout();
        }
    
        private void layout() {
    
            DataSource ds = new DataSource();
            ds.setID("Test");
            ds.setDataURL("test.data.xml");
            ds.setDataFormat(DSDataFormat.XML);
            ds.setDataProtocol(DSProtocol.POSTXML);
            DataSourceTextField id = new DataSourceTextField("id");
            id.setPrimaryKey(true);
            DataSourceTextField field1 = new DataSourceTextField("field1");
            DataSourceTextField field2 = new DataSourceTextField("field2");
            ds.setFields(id, field1, field2);
            ds.setClientOnly(true);
    
            com.smartgwt.client.util.workflow.Process process = new com.smartgwt.client.util.workflow.Process() {
                @Override
                public void finished(Record state) {
                    SC.logWarn("Process finished.");
                }
            };
            process.setID("process");
    
            ServiceTask dataTask = new ServiceTask();
            dataTask.setID("data");
            dataTask.setDataSource(ds);
            dataTask.setOutputFieldList("id", "field1", "field2");
            dataTask.setOperationType(DSOperationType.FETCH);
            dataTask.setCriteria(new Criteria("field1", "valueA"));
            dataTask.setNextElement("script");
    
            ScriptTask scriptTask = new ScriptTask() {
                @Override
                public Object execute(Object input, Record inputRecord) {
                    SC.logEcho(inputRecord.getJsObj(),"scriptTask");
                    return input;
                }
            };
            scriptTask.setID("script");
            scriptTask.setNextElement("form");
            scriptTask.setInputFieldList("id", "field1", "field2");
    
            UserTask formTask = new UserTask();
            formTask.setID("form");
            formTask.setNextElement("gate");
            formTask.setInputFieldList("id", "field1", "field2");
            formTask.setOutputFieldList("id", "field1", "field2");
            final Window wnd = new Window();
            wnd.setWidth(300);
            wnd.setHeight(120);
            DynamicForm df = new DynamicForm();
            df.setID("df");
            TextItem idItem = new TextItem("id");
            idItem.setHidden(true);
            TextItem field1Item = new TextItem("field1");
            TextItem field2Item = new TextItem("field2");
            SubmitItem submit = new SubmitItem("submit");
            df.setFields(idItem, field1Item, field2Item, submit);
            wnd.addItem(df);
            formTask.setTargetView(wnd);
            formTask.setTargetForm(df);
    
    //        XORGateway gateway = new XORGateway();
    //        gateway.setCriteria(criteria);
    //        gateway.setNextElement("goodFlow");
    //        gateway.setFailureElement("errorFlow");
            DecisionGateway gateway = new DecisionGateway();
            gateway.setID("gate");
            HashMap criteriaMap = new HashMap();
            criteriaMap.put("goodFlow", new Criteria("field1", "value1"));
            criteriaMap.put("errorFlow", new Criteria("field1", "value2"));
            gateway.setCriteriaMap(criteriaMap);
            gateway.setDefaultElement("errorFlow");
    
            ScriptTask goodFlowTask = new ScriptTask() {
                @Override
                public Object execute(Object input, Record inputRecord) {
                    SC.warn("goodFlow - save");
                    wnd.hide();
                    return input;
                }
            };
            goodFlowTask.setID("goodFlow");
            goodFlowTask.setInputFieldList("id", "field1", "field2");
            goodFlowTask.setNextElement("save");
    
            ServiceTask saveTask = new ServiceTask();
            saveTask.setID("save");
            saveTask.setDataSource(ds);
            saveTask.setInputFieldList("id", "field1", "field2");
            saveTask.setOperationType(DSOperationType.UPDATE);
    
            ScriptTask errorFlowTask = new ScriptTask() {
                @Override
                public Object execute(Object input, Record inputRecord) {
                    SC.warn("errorFlow - try again");
                    return input;
                }
            };
            errorFlowTask.setID("errorFlow");
            errorFlowTask.setInputFieldList("id", "field1", "field2");
            errorFlowTask.setNextElement("script");
    
            ProcessElement[] elements = new ProcessElement[7];
            elements[0] = dataTask;
            elements[1] = scriptTask;
            elements[2] = formTask;
            elements[3] = gateway;
            elements[4] = goodFlowTask;
            elements[5] = saveTask;
            elements[6] = errorFlowTask;
    
    //        process.setElements(elements);//does not work
            process.getOrCreateJsObj();
            process.setAttribute("elements", elements, true);
    
            //Record state = new Record();
            //state.setAttribute("field1Item", "value2");
            //process.setState(state);
    
            process.start();
    
        }
    
    }
    Data file for client-only ds test.data.xml:
    Code:
    <response>
        <startRow>0</startRow>
        <endRow>1</endRow>
        <totalRows>2</totalRows>
        <data>
            <Test>
                <id>1</id>
                <field1>valueA</field1>
                <field2>valueB</field2>
            </Test>
            <Test>
                <id>2</id>
                <field1>valueC</field1>
                <field2>valueD</field2>
            </Test>
        </data>
        <status>STATUS_SUCCESS</status>
    </response>
    I have been working with SmartClient 12.1d dated 2019.12.01.

    Comments welcome.

    MichalG

    #2
    many thanks!

    Comment


      #3
      Hello, many thanks for your sample, I managed to find the time to try your same sample in my application with one of my dataSources. Now it's more clear how it works.

      BTW, did you ever use it for something useful in your applications? I mean, I'm not sure I see the advantage of using it with a simple sample like this, and also what Isomorphic says here:

      https://forums.smartclient.com/forum...184#post256184
      The Workflow system is really a target for visual tools
      makes me wonder if it is really useful outside of Reify.
      But probably it's me that I'm still not seeing the big picture of this API (which seems way more rich than the first time I saw it).
      Last edited by claudiobosticco; 15th Oct 2020, 07:18.

      Comment


        #4
        We see it as principally something for visual tools - although we’ve worked hard to make the XML workflow format nearly as expressive as code, it’s still slightly less so.

        Some people who are not using visual tools to edit workflows may prefer it because it could allow someone who can’t really write code to write limited bits of logic by writing XML.

        In Reify of course there is a full visual workflow editor, with all kinds of intelligence built in; we have seen non-programmers build complex branching logic - the kinds of thing you would definitely assume would require a developer.

        Comment


          #5
          I can't comment Reify usage - no experience in it.

          We found workflow subsystem quite flexible, especially together with xml definition.

          We just prepared few user assistants based on workflow and have plans to include them in next production version.

          They are targeted for tasks which would be done by users occasionally using our system, for example "failure report" which ask step by step where crash occurred, what broke, any photo and so on...

          Other target we hope workflow would help us is customized usage made upon customer's request provided and distributed as xml/js extensions to production version.

          Comment


            #6
            MichalG, thanks again for chiming in.

            Since you aren’t using visual tools to author it, what do you see as the principle value of workflow for these scenarios?

            Do you have non-programmers authoring it? Or perhaps reading it?

            Or are you trying to restrict extensions so they can only do certain things (that is, only things that can be expressed in a workflow)?

            Comment


              #7
              A bigger picture of our development environment is:

              An UML tool is a central point where project is created. Everything from menu, fields and panels definitions, buttons and reports are modeled using hierarchical tagged values of project elements.

              We have got an export plugin to project structure which prepares xml definitions of datasources, panels and so on. Those are loaded and interpreted by our SGWT based client application. SGWT client app shows user interface build from xml definition. Client app is not modified or customized in any way, at least between major versions. All customizations are made through diff changes of core system as it goes out from project.

              The point about workflow for us is its flexibility when defined in xml. We have got standard panels (grid above, for below linked together), but we lack more flexible user interface solutions from time to time and workflow seems to be good tool for that.

              We also see workflow useful when building wizards better adjusted to mobile usage: forms with one or just a few fields at a time, grids with just a few columns etc.

              Mobility is probably the most often asked feature of our potential customers now.

              As far as non-programmers of ours are concerned: they describe their requirements very traditional way (project management tracking system), but they have very good acquaintance of possible interface solutions. Then, programmers analyze it and implement. So far we find it quicker and result better quality.

              Comment

              Working...
              X