@abgov/nx-adsp 5.9.0-beta.1 → 5.9.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generators.json +5 -0
- package/package.json +1 -1
- package/src/generators/react-form/files/__fileName__/__fileName__.slice.ts__tmpl__ +2 -2
- package/src/generators/react-form/files/__fileName__/__fileName__.tsx__tmpl__ +2 -96
- package/src/generators/react-form/includes/input-template.ejs +107 -0
- package/src/generators/react-form/react-form.js +1 -1
- package/src/generators/react-form/react-form.js.map +1 -1
- package/src/generators/react-form/react-forms.spec.ts +1 -0
- package/src/generators/react-form/schema.d.ts +1 -0
- package/src/generators/react-form/schema.json +3 -3
- package/src/generators/react-task-list/files/__fileName__/__fileName__.module.css__tmpl__ +80 -0
- package/src/generators/react-task-list/files/__fileName__/__fileName__.slice.spec.ts__tmpl__ +26 -0
- package/src/generators/react-task-list/files/__fileName__/__fileName__.slice.ts__tmpl__ +723 -0
- package/src/generators/react-task-list/files/__fileName__/__fileName__.tsx__tmpl__ +595 -0
- package/src/generators/react-task-list/files/__fileName__/task.d.ts__tmpl__ +30 -0
- package/src/generators/react-task-list/react-task-list.d.ts +3 -0
- package/src/generators/react-task-list/react-task-list.js +124 -0
- package/src/generators/react-task-list/react-task-list.js.map +1 -0
- package/src/generators/react-task-list/react-task-list.spec.ts +71 -0
- package/src/generators/react-task-list/schema.d.ts +14 -0
- package/src/generators/react-task-list/schema.json +45 -0
- package/src/utils/form.d.ts +1 -0
- package/src/utils/form.js.map +1 -1
- package/src/utils/task.d.ts +6 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GoABadge,
|
|
3
|
+
GoABlock,
|
|
4
|
+
GoAButton,
|
|
5
|
+
GoAButtonGroup,
|
|
6
|
+
GoACallout,
|
|
7
|
+
GoAContainer,
|
|
8
|
+
GoADetails,
|
|
9
|
+
GoADivider,
|
|
10
|
+
GoADropdown,
|
|
11
|
+
GoADropdownItem,
|
|
12
|
+
GoAFormItem,
|
|
13
|
+
GoAModal,
|
|
14
|
+
GoANotification,
|
|
15
|
+
GoARadioGroup,
|
|
16
|
+
GoARadioItem,
|
|
17
|
+
GoASpinner,
|
|
18
|
+
GoATable,
|
|
19
|
+
} from '@abgov/react-components';
|
|
20
|
+
import { FunctionComponent, ReactNode, useEffect, useState } from 'react';
|
|
21
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
22
|
+
import { AppDispatch } from '../../store';
|
|
23
|
+
import {
|
|
24
|
+
TaskFilter,
|
|
25
|
+
TaskMetric,
|
|
26
|
+
TaskUser,
|
|
27
|
+
assignTask,
|
|
28
|
+
cancelTask,
|
|
29
|
+
completeTask,
|
|
30
|
+
getBusy,
|
|
31
|
+
getFilter,
|
|
32
|
+
getLive,
|
|
33
|
+
getModal,
|
|
34
|
+
getOpenTask,
|
|
35
|
+
getQueueUser,
|
|
36
|
+
getQueueWorkers,
|
|
37
|
+
getTaskMetrics,
|
|
38
|
+
getTasks,
|
|
39
|
+
initializeQueue,
|
|
40
|
+
<%= propertyName %>TaskListActions,
|
|
41
|
+
setTaskPriority,
|
|
42
|
+
startTask,
|
|
43
|
+
} from './<%= fileName %>.slice';
|
|
44
|
+
import styles from './<%= fileName %>.module.css';
|
|
45
|
+
import { Person, Task } from './task';
|
|
46
|
+
|
|
47
|
+
interface TaskListItemProps {
|
|
48
|
+
task: Task;
|
|
49
|
+
isOpen: boolean;
|
|
50
|
+
user: TaskUser;
|
|
51
|
+
onSelect: (task: Task) => void;
|
|
52
|
+
onAssign: (task: Task) => void;
|
|
53
|
+
onSetPriority: (task: Task) => void;
|
|
54
|
+
onOpen: (task: Task) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function formatTaskAge(createdOn: string): string {
|
|
58
|
+
if (!createdOn) {
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const hours = Math.round((Date.now() - new Date(createdOn).getTime()) / 36e5);
|
|
63
|
+
if (hours < 24) {
|
|
64
|
+
return `${hours} hours`;
|
|
65
|
+
} else {
|
|
66
|
+
return `${Math.round((hours * 10) / 24) / 10} days`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface TaskHeaderProps {
|
|
71
|
+
className?: string;
|
|
72
|
+
open: Task;
|
|
73
|
+
isLive: boolean;
|
|
74
|
+
onClickTasks: () => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const TaskHeader: FunctionComponent<TaskHeaderProps> = ({
|
|
78
|
+
className,
|
|
79
|
+
open,
|
|
80
|
+
isLive,
|
|
81
|
+
onClickTasks,
|
|
82
|
+
}) => {
|
|
83
|
+
return (
|
|
84
|
+
<div className={className}>
|
|
85
|
+
<div>
|
|
86
|
+
{open ? (
|
|
87
|
+
<>
|
|
88
|
+
<GoAButton mt="s" type="tertiary" onClick={onClickTasks}>
|
|
89
|
+
Tasks
|
|
90
|
+
</GoAButton>
|
|
91
|
+
<span>/</span>
|
|
92
|
+
<span>
|
|
93
|
+
{open?.name} - {open?.description}
|
|
94
|
+
</span>
|
|
95
|
+
</>
|
|
96
|
+
) : (
|
|
97
|
+
<span>Tasks</span>
|
|
98
|
+
)}
|
|
99
|
+
<span>
|
|
100
|
+
{isLive ? (
|
|
101
|
+
<GoABadge mt="m" mb="s" type="success" content="Live" />
|
|
102
|
+
) : (
|
|
103
|
+
<GoABadge mt="m" mb="s" type="information" content="Not live" />
|
|
104
|
+
)}
|
|
105
|
+
</span>
|
|
106
|
+
</div>
|
|
107
|
+
<GoADivider mb="m" />
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
interface TaskMetricsProps {
|
|
113
|
+
metrics: TaskMetric[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const TaskMetrics: FunctionComponent<TaskMetricsProps> = ({ metrics }) => {
|
|
117
|
+
return (
|
|
118
|
+
<GoABlock mt="m">
|
|
119
|
+
{metrics.map((metric) => (
|
|
120
|
+
<GoAContainer type="non-interactive" accent="thin">
|
|
121
|
+
<label>{metric.name}</label>
|
|
122
|
+
<div style={{ marginTop: 16 }}>
|
|
123
|
+
<span
|
|
124
|
+
style={{
|
|
125
|
+
fontWeight: 'bold',
|
|
126
|
+
fontSize: 'xx-large',
|
|
127
|
+
marginRight: 6,
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{metric.value}
|
|
131
|
+
</span>
|
|
132
|
+
<span style={{ fontWeight: 'lighter' }}>{metric.unit}</span>
|
|
133
|
+
</div>
|
|
134
|
+
</GoAContainer>
|
|
135
|
+
))}
|
|
136
|
+
</GoABlock>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const TaskListItem: FunctionComponent<TaskListItemProps> = ({
|
|
141
|
+
task,
|
|
142
|
+
isOpen,
|
|
143
|
+
user,
|
|
144
|
+
onSelect,
|
|
145
|
+
onAssign,
|
|
146
|
+
onSetPriority,
|
|
147
|
+
onOpen,
|
|
148
|
+
}) => {
|
|
149
|
+
return (
|
|
150
|
+
<tr onClick={() => onSelect(task)}>
|
|
151
|
+
<td>{task.priority}</td>
|
|
152
|
+
<td>{formatTaskAge(task.createdOn)}</td>
|
|
153
|
+
<td>
|
|
154
|
+
<span>{task.name}</span> - <span>{task.description}</span>
|
|
155
|
+
</td>
|
|
156
|
+
<td>{task.status}</td>
|
|
157
|
+
<td>
|
|
158
|
+
{task.assignment?.assignedTo
|
|
159
|
+
? task.assignment.assignedTo.name
|
|
160
|
+
: 'No one'}
|
|
161
|
+
</td>
|
|
162
|
+
<td>
|
|
163
|
+
<GoAButtonGroup alignment="end">
|
|
164
|
+
{user.isAssigner && (
|
|
165
|
+
<>
|
|
166
|
+
<GoAButton
|
|
167
|
+
size="compact"
|
|
168
|
+
type="secondary"
|
|
169
|
+
onClick={() => onAssign(task)}
|
|
170
|
+
>
|
|
171
|
+
Assign
|
|
172
|
+
</GoAButton>
|
|
173
|
+
<GoAButton
|
|
174
|
+
size="compact"
|
|
175
|
+
type="secondary"
|
|
176
|
+
onClick={() => onSetPriority(task)}
|
|
177
|
+
>
|
|
178
|
+
Set priority
|
|
179
|
+
</GoAButton>
|
|
180
|
+
</>
|
|
181
|
+
)}
|
|
182
|
+
{!user.isAssigner && user.isWorker && (
|
|
183
|
+
<GoAButton
|
|
184
|
+
size="compact"
|
|
185
|
+
type="secondary"
|
|
186
|
+
onClick={() => onAssign(task)}
|
|
187
|
+
disabled={task.assignment?.assignedTo?.id === user.id}
|
|
188
|
+
>
|
|
189
|
+
Assign to me
|
|
190
|
+
</GoAButton>
|
|
191
|
+
)}
|
|
192
|
+
<GoAButton
|
|
193
|
+
size="compact"
|
|
194
|
+
type="primary"
|
|
195
|
+
disabled={isOpen}
|
|
196
|
+
onClick={() => onOpen(task)}
|
|
197
|
+
>
|
|
198
|
+
Open
|
|
199
|
+
</GoAButton>
|
|
200
|
+
</GoAButtonGroup>
|
|
201
|
+
</td>
|
|
202
|
+
</tr>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
interface TaskListProps {
|
|
207
|
+
className?: string;
|
|
208
|
+
metrics: TaskMetric[];
|
|
209
|
+
filter: TaskFilter;
|
|
210
|
+
tasks: Task[];
|
|
211
|
+
selected: Task;
|
|
212
|
+
open: Task;
|
|
213
|
+
user: TaskUser;
|
|
214
|
+
onSetFilter: (filter: TaskFilter) => void;
|
|
215
|
+
onSelect: (task: Task) => void;
|
|
216
|
+
onAssign: (task: Task) => void;
|
|
217
|
+
onSetPriority: (task: Task) => void;
|
|
218
|
+
onOpen: (task: Task) => void;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const TaskList: FunctionComponent<TaskListProps> = ({
|
|
222
|
+
className,
|
|
223
|
+
metrics,
|
|
224
|
+
filter,
|
|
225
|
+
tasks,
|
|
226
|
+
open,
|
|
227
|
+
user,
|
|
228
|
+
onSetFilter,
|
|
229
|
+
onSelect,
|
|
230
|
+
onAssign,
|
|
231
|
+
onSetPriority,
|
|
232
|
+
onOpen,
|
|
233
|
+
}) => {
|
|
234
|
+
return (
|
|
235
|
+
<div className={className} data-opened={!!open}>
|
|
236
|
+
<div>
|
|
237
|
+
<TaskMetrics metrics={metrics} />
|
|
238
|
+
<GoAFormItem label="Filter" mr="s">
|
|
239
|
+
<GoADropdown
|
|
240
|
+
onChange={(_, filter) => onSetFilter(filter as TaskFilter)}
|
|
241
|
+
value={filter}
|
|
242
|
+
>
|
|
243
|
+
<GoADropdownItem label="Active" value="active" />
|
|
244
|
+
<GoADropdownItem label="My tasks" value="assigned" />
|
|
245
|
+
<GoADropdownItem label="Pending" value="pending" />
|
|
246
|
+
</GoADropdown>
|
|
247
|
+
</GoAFormItem>
|
|
248
|
+
</div>
|
|
249
|
+
<GoATable mt="l" width="100%">
|
|
250
|
+
<colgroup>
|
|
251
|
+
<col style={{ width: 95 }} />
|
|
252
|
+
<col style={{ width: 90 }} />
|
|
253
|
+
<col />
|
|
254
|
+
<col style={{ width: 95 }} />
|
|
255
|
+
<col />
|
|
256
|
+
<col style={{ width: 330 }} />
|
|
257
|
+
</colgroup>
|
|
258
|
+
<thead>
|
|
259
|
+
<tr>
|
|
260
|
+
<th>Priority</th>
|
|
261
|
+
<th>Age</th>
|
|
262
|
+
<th>Task</th>
|
|
263
|
+
<th>Status</th>
|
|
264
|
+
<th>Assigned</th>
|
|
265
|
+
<th style={{ textAlign: 'right' }}>Actions</th>
|
|
266
|
+
</tr>
|
|
267
|
+
</thead>
|
|
268
|
+
<tbody>
|
|
269
|
+
{tasks.map((task) => (
|
|
270
|
+
<TaskListItem
|
|
271
|
+
key={task.id}
|
|
272
|
+
task={task}
|
|
273
|
+
isOpen={open?.id === task.id}
|
|
274
|
+
user={user}
|
|
275
|
+
onSelect={onSelect}
|
|
276
|
+
onAssign={onAssign}
|
|
277
|
+
onSetPriority={onSetPriority}
|
|
278
|
+
onOpen={onOpen}
|
|
279
|
+
/>
|
|
280
|
+
))}
|
|
281
|
+
</tbody>
|
|
282
|
+
</GoATable>
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
interface TaskDetailsProps {
|
|
288
|
+
className?: string;
|
|
289
|
+
open: Task;
|
|
290
|
+
children: ReactNode;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const TaskDetails: FunctionComponent<TaskDetailsProps> = ({
|
|
294
|
+
className,
|
|
295
|
+
open,
|
|
296
|
+
children,
|
|
297
|
+
}) => {
|
|
298
|
+
return (
|
|
299
|
+
<div data-opened={!!open} className={className}>
|
|
300
|
+
{open && children}
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
interface TaskAssignmentModalProps {
|
|
306
|
+
user: TaskUser;
|
|
307
|
+
task: Task;
|
|
308
|
+
open: boolean;
|
|
309
|
+
workers: Person[];
|
|
310
|
+
executing: boolean;
|
|
311
|
+
onAssign: (assignTo: Person) => void;
|
|
312
|
+
onClose: () => void;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const TaskAssignmentModal: FunctionComponent<TaskAssignmentModalProps> = ({
|
|
316
|
+
user,
|
|
317
|
+
task,
|
|
318
|
+
workers,
|
|
319
|
+
open,
|
|
320
|
+
executing,
|
|
321
|
+
onAssign,
|
|
322
|
+
onClose,
|
|
323
|
+
}) => {
|
|
324
|
+
const [selected, setSelected] = useState<string>();
|
|
325
|
+
useEffect(() => {
|
|
326
|
+
setSelected(task?.assignment?.assignedTo?.id || '');
|
|
327
|
+
}, [task]);
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<GoAModal heading="Assign task" open={open} onClose={onClose}>
|
|
331
|
+
<form>
|
|
332
|
+
<p>
|
|
333
|
+
Assign task {task?.name} to a person. Only the assigned person will be
|
|
334
|
+
able to progress the task.
|
|
335
|
+
</p>
|
|
336
|
+
<div>
|
|
337
|
+
{task?.assignment?.assignedTo ? (
|
|
338
|
+
<>
|
|
339
|
+
<span>Task is currently assigned to: </span>
|
|
340
|
+
<span>{task.assignment.assignedTo.name}</span>
|
|
341
|
+
</>
|
|
342
|
+
) : (
|
|
343
|
+
<span>Task is currently not assigned.</span>
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
{user.isAssigner ? (
|
|
347
|
+
<GoAFormItem label="Assign task to" mt="m" mb="4xl">
|
|
348
|
+
<GoADropdown
|
|
349
|
+
native={true}
|
|
350
|
+
value={task?.assignment?.assignedTo?.id}
|
|
351
|
+
onChange={(_, id) => setSelected(id as string)}
|
|
352
|
+
>
|
|
353
|
+
<GoADropdownItem key="no one" value="" label="No one" />
|
|
354
|
+
{workers.map((w) => (
|
|
355
|
+
<GoADropdownItem key={w.id} value={w.id} label={w.name} />
|
|
356
|
+
))}
|
|
357
|
+
</GoADropdown>
|
|
358
|
+
</GoAFormItem>
|
|
359
|
+
) : (
|
|
360
|
+
<div>Assign this task to yourself?</div>
|
|
361
|
+
)}
|
|
362
|
+
<GoAButtonGroup alignment="end" mt="4xl">
|
|
363
|
+
<GoAButton type="secondary" onClick={onClose}>
|
|
364
|
+
Cancel
|
|
365
|
+
</GoAButton>
|
|
366
|
+
<GoAButton
|
|
367
|
+
disabled={
|
|
368
|
+
executing ||
|
|
369
|
+
(user.isAssigner &&
|
|
370
|
+
selected === (task?.assignment?.assignedTo?.id || ''))
|
|
371
|
+
}
|
|
372
|
+
type="primary"
|
|
373
|
+
onClick={() => {
|
|
374
|
+
onAssign(
|
|
375
|
+
user.isAssigner
|
|
376
|
+
? selected
|
|
377
|
+
? workers.find((w) => w.id === selected)
|
|
378
|
+
: null
|
|
379
|
+
: user
|
|
380
|
+
);
|
|
381
|
+
}}
|
|
382
|
+
>
|
|
383
|
+
Assign
|
|
384
|
+
</GoAButton>
|
|
385
|
+
</GoAButtonGroup>
|
|
386
|
+
</form>
|
|
387
|
+
</GoAModal>
|
|
388
|
+
);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
interface TaskPriorityModal {
|
|
392
|
+
task: Task;
|
|
393
|
+
open: boolean;
|
|
394
|
+
executing: boolean;
|
|
395
|
+
onSetPriority: (priority: string) => void;
|
|
396
|
+
onClose: () => void;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const TaskPriorityModal: FunctionComponent<TaskPriorityModal> = ({
|
|
400
|
+
task,
|
|
401
|
+
open,
|
|
402
|
+
executing,
|
|
403
|
+
onSetPriority,
|
|
404
|
+
onClose,
|
|
405
|
+
}) => {
|
|
406
|
+
const [priority, setPriority] = useState<string>();
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
setPriority(task?.priority);
|
|
409
|
+
}, [task]);
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
<GoAModal heading="Set task priority" open={open} onClose={onClose}>
|
|
413
|
+
<form>
|
|
414
|
+
<p>
|
|
415
|
+
Set the priority for {task?.name}. Higher priority tasks will appear
|
|
416
|
+
at the top of the list.
|
|
417
|
+
</p>
|
|
418
|
+
<div>
|
|
419
|
+
<span>Priority is currently set to: </span>
|
|
420
|
+
<span>{task?.priority}</span>
|
|
421
|
+
</div>
|
|
422
|
+
<GoAFormItem label="Set priority to" mt="m">
|
|
423
|
+
<GoARadioGroup
|
|
424
|
+
name="priority"
|
|
425
|
+
value={task?.priority}
|
|
426
|
+
onChange={(_, value) => setPriority(value)}
|
|
427
|
+
>
|
|
428
|
+
<GoARadioItem name="Urgent" value="Urgent" />
|
|
429
|
+
<GoARadioItem name="High" value="High" />
|
|
430
|
+
<GoARadioItem name="Normal" value="Normal" />
|
|
431
|
+
</GoARadioGroup>
|
|
432
|
+
</GoAFormItem>
|
|
433
|
+
<GoAButtonGroup alignment="end" mt="4xl">
|
|
434
|
+
<GoAButton type="secondary" onClick={onClose}>
|
|
435
|
+
Cancel
|
|
436
|
+
</GoAButton>
|
|
437
|
+
<GoAButton
|
|
438
|
+
type="primary"
|
|
439
|
+
disabled={executing || (priority && priority === task?.priority)}
|
|
440
|
+
onClick={() => onSetPriority(priority)}
|
|
441
|
+
>
|
|
442
|
+
Set priority
|
|
443
|
+
</GoAButton>
|
|
444
|
+
</GoAButtonGroup>
|
|
445
|
+
</form>
|
|
446
|
+
</GoAModal>
|
|
447
|
+
);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
export const <%= className %>TaskList: FunctionComponent = () => {
|
|
451
|
+
const user = useSelector(getQueueUser);
|
|
452
|
+
const live = useSelector(getLive);
|
|
453
|
+
const metrics = useSelector(getTaskMetrics);
|
|
454
|
+
const filter = useSelector(getFilter);
|
|
455
|
+
const busy = useSelector(getBusy);
|
|
456
|
+
const modal = useSelector(getModal);
|
|
457
|
+
const tasks = useSelector(getTasks);
|
|
458
|
+
const open = useSelector(getOpenTask);
|
|
459
|
+
const workers = useSelector(getQueueWorkers);
|
|
460
|
+
|
|
461
|
+
const dispatch = useDispatch<AppDispatch>();
|
|
462
|
+
useEffect(() => {
|
|
463
|
+
dispatch(
|
|
464
|
+
initializeQueue({ namespace: '<%= queueNamespace %>', name: '<%= queueName %>' })
|
|
465
|
+
);
|
|
466
|
+
}, [dispatch]);
|
|
467
|
+
|
|
468
|
+
return (
|
|
469
|
+
<div className={styles.taskList}>
|
|
470
|
+
<GoANotification type="important">
|
|
471
|
+
This is a generated rapid prototype. Use it as a starting point to build
|
|
472
|
+
the right thing for users.
|
|
473
|
+
</GoANotification>
|
|
474
|
+
<TaskHeader
|
|
475
|
+
className={styles.header}
|
|
476
|
+
open={open}
|
|
477
|
+
isLive={live}
|
|
478
|
+
onClickTasks={() => dispatch(<%= propertyName %>TaskListActions.setOpenTask())}
|
|
479
|
+
/>
|
|
480
|
+
<TaskDetails className={styles.details} open={open}>
|
|
481
|
+
{/* Replace this with task detail view so user can view and complete task. */}
|
|
482
|
+
<div className={styles.detailsPlaceholder}>
|
|
483
|
+
<div>
|
|
484
|
+
<GoACallout type="information" heading="Task detail view">
|
|
485
|
+
This is a placeholder for the task detail view. Replace with your
|
|
486
|
+
own custom view for the specific type of task that users will work
|
|
487
|
+
with.
|
|
488
|
+
</GoACallout>
|
|
489
|
+
<GoADetails ml="s" heading="Show task specific view">
|
|
490
|
+
Replace this with a custom view so user can view and perform
|
|
491
|
+
tasks. For example, if the task is to process a submission, show
|
|
492
|
+
the form fields and attached files for the assessor.
|
|
493
|
+
</GoADetails>
|
|
494
|
+
<GoADetails ml="s" heading="Update task based on user actions">
|
|
495
|
+
Tasks can be started, completed, and cancelled. Perform task
|
|
496
|
+
lifecycle actions as part of the task specific user action. For
|
|
497
|
+
example, if the task is to process a submission, the assessor's
|
|
498
|
+
action to record a decision should complete the task.
|
|
499
|
+
</GoADetails>
|
|
500
|
+
</div>
|
|
501
|
+
<GoAButtonGroup alignment="end" mt="l">
|
|
502
|
+
<GoAButton
|
|
503
|
+
type="secondary"
|
|
504
|
+
onClick={() => dispatch(<%= propertyName %>TaskListActions.setOpenTask())}
|
|
505
|
+
>
|
|
506
|
+
Close
|
|
507
|
+
</GoAButton>
|
|
508
|
+
{open?.status === 'Pending' && (
|
|
509
|
+
<GoAButton
|
|
510
|
+
disabled={busy.executing}
|
|
511
|
+
onClick={() => dispatch(startTask({ taskId: open?.id }))}
|
|
512
|
+
>
|
|
513
|
+
Start task
|
|
514
|
+
</GoAButton>
|
|
515
|
+
)}
|
|
516
|
+
{open?.status === 'In Progress' && (
|
|
517
|
+
<>
|
|
518
|
+
<GoAButton
|
|
519
|
+
type="secondary"
|
|
520
|
+
disabled={busy.executing}
|
|
521
|
+
onClick={() =>
|
|
522
|
+
dispatch(cancelTask({ taskId: open?.id, reason: null }))
|
|
523
|
+
}
|
|
524
|
+
>
|
|
525
|
+
Cancel task
|
|
526
|
+
</GoAButton>
|
|
527
|
+
<GoAButton
|
|
528
|
+
disabled={busy.executing}
|
|
529
|
+
onClick={() => dispatch(completeTask({ taskId: open?.id }))}
|
|
530
|
+
>
|
|
531
|
+
Complete task
|
|
532
|
+
</GoAButton>
|
|
533
|
+
</>
|
|
534
|
+
)}
|
|
535
|
+
</GoAButtonGroup>
|
|
536
|
+
</div>
|
|
537
|
+
</TaskDetails>
|
|
538
|
+
{busy.initializing ||
|
|
539
|
+
(busy.loading && (
|
|
540
|
+
<div className={styles.loading}>
|
|
541
|
+
<GoASpinner size="large" type="infinite" />
|
|
542
|
+
</div>
|
|
543
|
+
))}
|
|
544
|
+
<TaskList
|
|
545
|
+
className={styles.list}
|
|
546
|
+
metrics={metrics}
|
|
547
|
+
filter={filter}
|
|
548
|
+
tasks={tasks}
|
|
549
|
+
open={open}
|
|
550
|
+
selected={null}
|
|
551
|
+
user={user}
|
|
552
|
+
onSetFilter={(filter) =>
|
|
553
|
+
dispatch(<%= propertyName %>TaskListActions.setFilter(filter))
|
|
554
|
+
}
|
|
555
|
+
onSelect={() => {
|
|
556
|
+
// not used
|
|
557
|
+
}}
|
|
558
|
+
onAssign={(task) =>
|
|
559
|
+
dispatch(<%= propertyName %>TaskListActions.setTaskToAssign(task))
|
|
560
|
+
}
|
|
561
|
+
onSetPriority={(task) =>
|
|
562
|
+
dispatch(<%= propertyName %>TaskListActions.setTaskToPrioritize(task))
|
|
563
|
+
}
|
|
564
|
+
onOpen={(task) => dispatch(<%= propertyName %>TaskListActions.setOpenTask(task.id))}
|
|
565
|
+
/>
|
|
566
|
+
<TaskAssignmentModal
|
|
567
|
+
user={user}
|
|
568
|
+
task={modal.taskToAssign}
|
|
569
|
+
workers={workers}
|
|
570
|
+
open={!!modal.taskToAssign}
|
|
571
|
+
executing={busy.executing}
|
|
572
|
+
onAssign={(assignTo) =>
|
|
573
|
+
dispatch(assignTask({ taskId: modal.taskToAssign.id, assignTo }))
|
|
574
|
+
}
|
|
575
|
+
onClose={() => dispatch(<%= propertyName %>TaskListActions.setTaskToAssign(null))}
|
|
576
|
+
/>
|
|
577
|
+
<TaskPriorityModal
|
|
578
|
+
task={modal.taskToPrioritize}
|
|
579
|
+
open={!!modal.taskToPrioritize}
|
|
580
|
+
executing={busy.executing}
|
|
581
|
+
onSetPriority={(priority) =>
|
|
582
|
+
dispatch(
|
|
583
|
+
setTaskPriority({
|
|
584
|
+
taskId: modal.taskToPrioritize.id,
|
|
585
|
+
priority,
|
|
586
|
+
})
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
onClose={() =>
|
|
590
|
+
dispatch(<%= propertyName %>TaskListActions.setTaskToPrioritize(null))
|
|
591
|
+
}
|
|
592
|
+
/>
|
|
593
|
+
</div>
|
|
594
|
+
);
|
|
595
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface QueueDefinition {
|
|
2
|
+
namespace: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
assignerRoles: string[];
|
|
6
|
+
workerRoles: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Task {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
priority: string;
|
|
14
|
+
status: 'Pending' | 'In Progress' | 'Stopped' | 'Cancelled' | 'Completed';
|
|
15
|
+
createdOn: string;
|
|
16
|
+
startedOn: string;
|
|
17
|
+
endedOn: string;
|
|
18
|
+
assignment: {
|
|
19
|
+
assignedTo: {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Person {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
email: string;
|
|
30
|
+
}
|