Free cookie consent management tool by TermsFeed

Task Report Pattern

Tip:  Interface patterns give you an opportunity to explore different interface designs. Be sure to check out How to Adapt a Pattern for Your Application.

Goal

Provides a simple way to create and display an Appian task report. This page explains how you can use this pattern in your interface, and walks through the design structure in detail.

This design pattern is not recommended for offline interfaces because reflecting immediate changes in an interface based on user interaction requires a connection to the server.

screenshot of the task report pattern

Design structure

This page will break down this expression so you can better understand how to adapt this pattern to your own data so that it works to best suit your needs. For an example of how to modify this pattern or how to see a task report in a site, see the Task Report Tutorial. For a task report recipe that works in offline mobile, see Offline Mobile Task Report.

The main components in this pattern are dropdowns, read only grids, process task links, and rich text. The image below displays how the pattern looks on a blank interface with callouts for the main components. You can examine the entire expression or jump down to the subsections below with referenced line numbers to see a detailed breakdown of the main components.

Pattern expression

When you drag and drop the Task Report pattern onto your interface, 200 lines of expressions will be added to the section where you dragged it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
a!localVariables(
  local!statusFilter: null,
  
  /* https://docs.appian.com/suite/help/latest/Task_Report_Tutorial.html */
  /* Basic steps to follow:                                              */
  /* 1. Create a Process Report object                                   */
  /* 2. Duplicate an existing process report, e.g. active_tasks          */
  /* 3. Create a Document constant for the report, e.g. TASKS_REPORT     */
  /* 4. Replace the value parameter of the refresh variable              */
  /*    local!taskReportData with a process analytics query e.g.         */
  /*    a!queryProcessAnalytics(                                         */
  /*      report: cons!TASKS_REPORT,                                     */
  /*      query: a!query(                                                */
  /*        pagingInfo: a!pagingInfo(                                    */
  /*          startIndex: 1,                                             */
  /*          batchSize: -1,                                             */
  /*          sort: a!sortInfo(                                          */
  /*            field: "c2",                                             */
  /*            ascending: false                                         */
  /*          )                                                          */
  /*       ),                                                            */
  /*       filter: a!queryFilter(                                        */
  /*         field: "c5",                                                */
  /*         operator: "in",                                             */
  /*         value: local!statusFilter,                                  */
  /*         applyWhen: a!isNotNullOrEmpty(local!statusFilter)           */
  /*       )                                                             */
  /*     )                                                               */
  /*   )                                                                 */

  /* The variable used to refresh the task report data */
  local!refreshTrigger: true,
      
  /* Placeholder variable for the task data returned by a process analytics query */
  local!taskReportData: a!refreshVariable(
    refreshOnVarChange: local!refreshTrigger,
    value: {
      startIndex: 1,
      batchSize: 7,
      sort: {field: "c2", ascending: false},
      totalCount: 10,
      data: a!localVariables(
        local!data: {
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #38",  dp0: 268440077, dp2: null, dp4: null, dp3: 268435772, dp5: 268435772, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #39",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #123", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #40",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #124", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #125", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #41",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null)
        },
        if(
          a!isNullOrEmpty(local!statusFilter),
          local!data,
          index(
            local!data,
            wherecontains(local!statusFilter, local!data.c5),
            {}
          )
        )
      ),
      identifiers: {123456781, 123456782, 123456783, 123456784, 123456785, 123456786, 123456787},
      name: "Employee Tasks",
      /* Maps field labels above to user friendly name */
      columnConfigs: {
        a!map(label: "Name",        field: "c0", drilldownField: "dp0", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: "TASK_DETAILS"),
        a!map(label: "Process",     field: "c3", drilldownField: "dp3", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: "PROCESS_DASHBOARD"),
        a!map(label: "Status",      field: "c5", drilldownField: "dp5", configuredFormatting: "TASK_STATUS", configuredDrilldown: "PROCESS_DETAILS"),
        a!map(label: "Assignee",    field: "c8", drilldownField: "dp2", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: null),
        a!map(label: "Received On", field: "c2", drilldownField: "dp2", configuredFormatting: "DATE_TIME",   configuredDrilldown: null)
      }
    }
  ),
  /* Maps the "c5" / "Status" field values to status names */
  local!taskStatuses: {
    a!map(name: "Assigned",               icon: "user-o",             color: "#666666"),
    a!map(name: "Accepted",               icon: "user-check",         color: "ACCENT"),
    a!map(name: "Completed",              icon: "check-circle",       color: "POSITIVE"),
    a!map(name: "Not Started",            icon: "circle-o-large",     color: "#666666"),
    a!map(name: "Cancelled",              icon: "stop-circle",        color: "#fdb858"),
    a!map(name: "Paused",                 icon: "pause-circle",       color: "#666666"),
    a!map(name: "Aborted",                icon: "question-circle",    color: "#666666"),
    a!map(name: "Cancelled By Exception", icon: "minus-circle",       color: "#fdb858"),
    a!map(name: "Cancelled By Exception", icon: "times-circle",       color: "NEGATIVE"),
    a!map(name: "Submitted",              icon: "share",              color: "ACCENT"),
    a!map(name: "Running",                icon: "spinner",            color: "ACCENT"),
    a!map(name: "Error",                  icon: "exclamation-circle", color: "NEGATIVE")
  },
  {
    a!sectionLayout(
      label: "Employee Tasks",
      labelColor: "SECONDARY",
      contents: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: {
                a!multipleDropdownField(
                  label: "Status",
                  labelPosition: "COLLAPSED",
                  placeholder: "All statuses",
                  choiceLabels: { "Assigned", "Accepted", "Completed", "Not Started" },
                  choiceValues: enumerate(4),
                  value: local!statusFilter,
                  saveInto: local!statusFilter
                )
              },
              width: "MEDIUM"
            ),
            a!columnLayout(
              contents: {
                a!buttonArrayLayout(
                  buttons: a!buttonWidget(
                    icon: "refresh",
                    value: not(local!refreshTrigger),
                    saveInto: local!refreshTrigger,
                    size: "SMALL",
                    style: "OUTLINE",
                    color: "SECONDARY",
                    accessibilityText: "Refresh task data"
                  )
                )
              }
            )
          },
          marginBelow: "NONE"
        ),
        a!gridField(
          label: "Employee Tasks",
          labelPosition: "COLLAPSED",
          data: local!taskReportData.data,
          columns: a!forEach(
            items: local!taskReportData.columnConfigs,
            expression: a!gridColumn(
              label: fv!item.label,
              sortField: fv!item.field,
              value: a!localVariables(
                local!fieldValue: index(fv!row, fv!item.field, {}),
                /* Display the data based on its configured formatting */
                a!match(
                  value: fv!item.configuredFormatting,
                  equals: "TASK_STATUS",
                  then: a!localVariables(
                    local!status: index(local!taskStatuses, local!fieldValue + 1, {}),
                    a!richTextDisplayField(
                      value: {
                        a!richTextIcon(
                          icon: index(local!status, "icon", "circle"),
                          color: index(local!status, "color", "#666666")
                        ),
                        "  ",
                        index(local!status, "name", "Other")
                      }
                    )
                  ),
                  equals: "DATE_TIME",
                  then: if(
                    a!isNullOrEmpty(local!fieldValue),
                    local!fieldValue,
                    text(local!fieldValue, "MMM D, YYYY, H:MM am/pm")
                  ),
                  /* Show a process link for task details */
                  whenTrue: fv!item.configuredDrilldown = "TASK_DETAILS",
                  then: a!linkField(
                    links: a!processTaskLink(
                      label: local!fieldValue,
                      task: index(fv!row, fv!item.drilldownField, {})
                    )
                  ),
                  /* Show username or group name for Assignee field                         */
                  /* Note: For task reports that only show tasks for the current user,      */
                  /* the "Assignee" column can be hidden. Task list can be named "My Tasks" */
                  whenTrue: fv!item.field = "c8",
                  then: a!richTextDisplayField(
                    value: a!forEach(
                      items: fv!row.c8,
                      expression: if(
                        /* Check if User, otherwise its a Group */
                        isusernametaken(fv!item),
                        a!richTextItem(
                          text: user(fv!item, "firstName") & " " & user(fv!item, "lastName") & char(10),
                          link: a!userRecordLink(user: fv!item),
                          linkStyle: "STANDALONE"
                        ),
                        /* Adding char(10) adds line breaks to the list of names */
                        group(fv!item, "groupName") & char(10)
                      )
                    )
                  ),
                  default: local!fieldValue
                )
              ),
              align: if(fv!item.configuredFormatting = "DATE_TIME", "END", "START")
            )
          ),
          pageSize: 10,
          borderStyle: "LIGHT",
          rowHeader: 1
        )
      }
    )
  }
)

[Line 1-32] Provide instructions in comments

The first two lines in the expression begin the local variables, but are directly followed by 25 lines of comments. These comments contain a link to the Task Report Tutorial and a set of 4 steps to tell you how to create a task report.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
a!localVariables(
  local!statusFilter: null,
  
  /* https://docs.appian.com/suite/help/latest/Task_Report_Tutorial.html */
  /* Basic steps to follow:                                              */
  /* 1. Create a Process Report object                                   */
  /* 2. Duplicate an existing process report, e.g. active_tasks          */
  /* 3. Create a Document constant for the report, e.g. TASKS_REPORT     */
  /* 4. Replace the value parameter of the refresh variable              */
  /*    local!taskReportData with a process analytics query e.g.         */
  /*    a!queryProcessAnalytics(                                         */
  /*      report: cons!TASKS_REPORT,                                     */
  /*      query: a!query(                                                */
  /*        pagingInfo: a!pagingInfo(                                    */
  /*          startIndex: 1,                                             */
  /*          batchSize: -1,                                             */
  /*          sort: a!sortInfo(                                          */
  /*            field: "c2",                                             */
  /*            ascending: false                                         */
  /*          )                                                          */
  /*       ),                                                            */
  /*       filter: a!queryFilter(                                        */
  /*         field: "c5",                                                */
  /*         operator: "in",                                             */
  /*         value: local!statusFilter,                                  */
  /*         applyWhen: a!isNotNullOrEmpty(local!statusFilter)           */
  /*       )                                                             */
  /*     )                                                               */
  /*   )                                                                 */
  
  /* The variable used to refresh the task report data */
  local!refreshTrigger: true,

[Line 34-73] Define the local variable for task data

This is the first local variable that populates the placeholder data for the grid.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
   
  /* Placeholder variable for the task data returned by a process analytics query */
  local!taskReportData: a!refreshVariable(
    refreshOnVarChange: local!refreshTrigger,
    value: {
      startIndex: 1,
      batchSize: 7,
      sort: {field: "c2", ascending: false},
      totalCount: 10,
      data: a!localVariables(
        local!data: {
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #38",  dp0: 268440077, dp2: null, dp4: null, dp3: 268435772, dp5: 268435772, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #39",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #123", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 0, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #40",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #124", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "Document Processing",  c8: loggedInUser(), c7: null, c2: now(), c0: "Review Document: Invoice #125", dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null),
          a!map(c5: 1, c4: 1, c3: "New Purchase Request", c8: loggedInUser(), c7: null, c2: now(), c0: "Approve Purchase Request #41",  dp0: 268440067, dp2: null, dp4: null, dp3: 268435771, dp5: 268435771, dp7: null, dp8: null)
        },
        if(
          a!isNullOrEmpty(local!statusFilter),
          local!data,
          index(
            local!data,
            wherecontains(local!statusFilter, local!data.c5),
            {}
          )
        )
      ),
      identifiers: {123456781, 123456782, 123456783, 123456784, 123456785, 123456786, 123456787},
      name: "Employee Tasks",
      /* Maps field labels above to user friendly name */
      columnConfigs: {
        a!map(label: "Name",        field: "c0", drilldownField: "dp0", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: "TASK_DETAILS"),
        a!map(label: "Process",     field: "c3", drilldownField: "dp3", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: "PROCESS_DASHBOARD"),
        a!map(label: "Status",      field: "c5", drilldownField: "dp5", configuredFormatting: "TASK_STATUS", configuredDrilldown: "PROCESS_DETAILS"),
        a!map(label: "Assignee",    field: "c8", drilldownField: "dp2", configuredFormatting: "NORMAL_TEXT", configuredDrilldown: null),
        a!map(label: "Received On", field: "c2", drilldownField: "dp2", configuredFormatting: "DATE_TIME",   configuredDrilldown: null)
      }
    }
  ),

When you adapt this pattern to work for you, you need to remove this entire section (lines 35-73) and replace the pattern's placeholder data with your own data.

To replace the placeholder data:

  1. In the a!refreshVariable() function, delete the contents of the value parameter starting on line 37. Copy and paste the following expression from the commented expression in lines 11-29 of the pattern and use it for the contents of the value parameter:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
       a!queryProcessAnalytics(                                         
         report: cons!TASKS_REPORT,                                     
         query: a!query(                                                
           pagingInfo: a!pagingInfo(                                    
             startIndex: 1,                                             
             batchSize: -1,                                             
             sort: a!sortInfo(                                          
               field: "c2",                                             
               ascending: false                                         
             )                                                          
          ),                                                            
          filter: a!queryFilter(                                        
            field: "c5",                                                
            operator: "in",                                             
            value: local!statusFilter,                                  
            applyWhen: a!isNotNullOrEmpty(local!statusFilter)           
          )                                                             
        )                                                               
      ),                                                                 
                 
    
  2. Replace cons!TASKS_REPORT with a Document constant that points to a task report. See the Task Report Tutorial for step-by-step instructions.
  3. To see your changes reflected in the interface preview, click TEST.

Note:  Clicking TEST forces the local variables in your interface preview to refresh. Do this any time you update a local variable to see your changes reflected in the interface.

To learn more about adapting this pattern to use your own data and reports, see the Task Report tutorial.

Reference task report columns

Notice in the new local variable expression that the field parameter values are c5 and c2. This comes from the underlying process report, which identifies each column with a field id.

You can see these field ids and which column they refer to in the LOCAL VARIABLES pane in the interface object. This pane displays the query results for the local!taskReportData variable. Simply expand taskReportData, then columnConfigs to see the column configuration parameters for each column in the task report.

These configurations list the label, field, drilldownField, configuredFormatting, and configuredDrilldown parameters for each column. Looking at this, we can see the field id c2 is for the "Received" column and c5 is for the "Status" column.

You can also use these parameters with fv!item within the a!forEach() function that creates the grid. For example, the pattern uses fv!item.label, fv!item.field, and fv!item.configuredFormatting for formatting the grid columns.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
a!gridField(
          label: "My Tasks",
          labelPosition: "COLLAPSED",
          data: local!taskReportData.data,
          columns: a!forEach(
            items: local!taskReportData.columnConfigs,
            expression: a!gridColumn(
!             label: fv!item.label,
!             sortField: fv!item.field,
              value: a!localVariables(
                local!fieldValue: index(fv!row, fv!item.field, {}),
                /* Display the data based on its configured formatting */
                a!match(
!                 value: fv!item.configuredFormatting,
                  equals: "TASK_STATUS",
                  then: a!localVariables(
                    local!status: index(local!taskStatuses, local!fieldValue + 1, {}),
                    a!richTextDisplayField(
                      value: {
                        a!richTextIcon(
                          icon: index(local!status, "icon", "circle"),
                          color: index(local!status, "color", "#666666")
                        ),
                        "  ",
                        index(local!status, "name", "Other")
                      }
                    )
                  ),
...

You can use this column configuration information to make changes to the task report. For example, you could sort the report by priority (c4) instead of the received date (c2).

[Line 74-88] Define the local variable to make friendly names for statuses

This section of the expression creates user-friendly names for each standard task status and maps it to an icon and color. When you adapt this pattern to work with your own data and tasks, you can use all or some of these task statuses, depending on which are most relevant for your workflow.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    /* Maps the "c5" / "Status" field values to status names */
  local!taskStatuses: {
    a!map(name: "Assigned",               icon: "user-o",             color: "#666666"),
    a!map(name: "Accepted",               icon: "user-check",         color: "ACCENT"),
    a!map(name: "Completed",              icon: "check-circle",       color: "POSITIVE"),
    a!map(name: "Not Started",            icon: "circle-o-large",     color: "#666666"),
    a!map(name: "Cancelled",              icon: "stop-circle",        color: "#fdb858"),
    a!map(name: "Paused",                 icon: "pause-circle",       color: "#666666"),
    a!map(name: "Aborted",                icon: "question-circle",    color: "#666666"),
    a!map(name: "Cancelled By Exception", icon: "minus-circle",       color: "#fdb858"),
    a!map(name: "Cancelled By Exception", icon: "times-circle",       color: "NEGATIVE"),
    a!map(name: "Submitted",              icon: "share",              color: "ACCENT"),
    a!map(name: "Running",                icon: "spinner",            color: "ACCENT"),
    a!map(name: "Error",                  icon: "exclamation-circle", color: "NEGATIVE")
  },

[Line 89-126] Create the status filter

This section of the expression creates the status filter using a multiple dropdown field. When you adapt this pattern to work with your own data and tasks, change the choice labels and values in the dropdown to match your statuses.

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  {
    a!sectionLayout(
      label: "Employee Tasks",
      labelColor: "SECONDARY",
      contents: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: {
                a!multipleDropdownField(
                  label: "Status",
                  labelPosition: "COLLAPSED",
                  placeholder: "All statuses",
                  choiceLabels: { "Assigned", "Accepted", "Completed", "Not Started" },
                  choiceValues: enumerate(4),
                  value: local!statusFilter,
                  saveInto: local!statusFilter
                )
              },
              width: "MEDIUM"
            ),
            a!columnLayout(
              contents: {
                a!buttonArrayLayout(
                  buttons: a!buttonWidget(
                    icon: "refresh",
                    value: not(local!refreshTrigger),
                    saveInto: local!refreshTrigger,
                    size: "SMALL",
                    style: "OUTLINE",
                    color: "SECONDARY",
                    accessibilityText: "Refresh task data"
                  )
                )
              }
            )
          },
          marginBelow: "NONE"
        ),

[Line 127-202] Create the grid

This section of the expression creates the grid to display tasks, formats the status column, and adds process links to each task. The grid uses the a!forEach() function to loop through all the local variables associated with each placeholder task and display them as a row in the grid.

Lines 140-141 use a!match() and the value parameter to determine the type of data (either date, status, or text).

Lines 142-155 use the equals and then parameters in the match() function to format any values of type TASK_STATUS so that they show the status.

Lines 156-161 use the equals and then parameters to format any values of type DATE_TIME so that they show when the task was received.

Lines 162-169 use the whentrue and then parameters to format the process task links for each task in the grid so that users can select a task and view its details.

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
        a!gridField(
          label: "Employee Tasks",
          labelPosition: "COLLAPSED",
          data: local!taskReportData.data,
          columns: a!forEach(
            items: local!taskReportData.columnConfigs,
            expression: a!gridColumn(
              label: fv!item.label,
              sortField: fv!item.field,
              value: a!localVariables(
                local!fieldValue: index(fv!row, fv!item.field, {}),
                /* Display the data based on its configured formatting */
                a!match(
                  value: fv!item.configuredFormatting,
                  equals: "TASK_STATUS",
                  then: a!localVariables(
                    local!status: index(local!taskStatuses, local!fieldValue + 1, {}),
                    a!richTextDisplayField(
                      value: {
                        a!richTextIcon(
                          icon: index(local!status, "icon", "circle"),
                          color: index(local!status, "color", "#666666")
                        ),
                        "  ",
                        index(local!status, "name", "Other")
                      }
                    )
                  ),
                  equals: "DATE_TIME",
                  then: if(
                    a!isNullOrEmpty(local!fieldValue),
                    local!fieldValue,
                    text(local!fieldValue, "MMM D, YYYY, H:MM am/pm")
                  ),
                  /* Show a process link for task details */
                  whenTrue: fv!item.configuredDrilldown = "TASK_DETAILS",
                  then: a!linkField(
                    links: a!processTaskLink(
                      label: local!fieldValue,
                      task: index(fv!row, fv!item.drilldownField, {})
                    )
                  ),
                  /* Show username or group name for Assignee field                         */
                  /* Note: For task reports that only show tasks for the current user,      */
                  /* the "Assignee" column can be hidden. Task list can be named "My Tasks" */
                  whenTrue: fv!item.field = "c8",
                  then: a!richTextDisplayField(
                    value: a!forEach(
                      items: fv!row.c8,
                      expression: if(
                        /* Check if User, otherwise its a Group */
                        isusernametaken(fv!item),
                        a!richTextItem(
                          text: user(fv!item, "firstName") & " " & user(fv!item, "lastName") & char(10),
                          link: a!userRecordLink(user: fv!item),
                          linkStyle: "STANDALONE"
                        ),
                        /* Adding char(10) adds line breaks to the list of names */
                        group(fv!item, "groupName") & char(10)
                      )
                    )
                  ),
                  default: local!fieldValue
                )
              ),
              align: if(fv!item.configuredFormatting = "DATE_TIME", "END", "START")
            )
          ),
          pageSize: 10,
          borderStyle: "LIGHT",
          rowHeader: 1
        )
      }
    )
  }
)

Feedback