Added cancel details in activity logs as well as used icons
This commit is contained in:
parent
e99b87bd20
commit
97d9e83f17
|
|
@ -2227,7 +2227,14 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
: (profileById[l.actorId]?.fullName ?? l.actorId!);
|
: (profileById[l.actorId]?.fullName ?? l.actorId!);
|
||||||
switch (l.actionType) {
|
switch (l.actionType) {
|
||||||
case 'created':
|
case 'created':
|
||||||
timeline.add(_activityRow('Task created', actorName, l.createdAt));
|
timeline.add(
|
||||||
|
_activityRow(
|
||||||
|
'Task created',
|
||||||
|
actorName,
|
||||||
|
l.createdAt,
|
||||||
|
icon: Icons.add_task,
|
||||||
|
),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'assigned':
|
case 'assigned':
|
||||||
final meta = l.meta ?? {};
|
final meta = l.meta ?? {};
|
||||||
|
|
@ -2241,6 +2248,7 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
auto ? 'Auto-assigned to $name' : 'Assigned to $name',
|
auto ? 'Auto-assigned to $name' : 'Assigned to $name',
|
||||||
actorName,
|
actorName,
|
||||||
l.createdAt,
|
l.createdAt,
|
||||||
|
icon: Icons.person_add,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2252,7 +2260,12 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
.map((id) => profileById[id]?.fullName ?? id)
|
.map((id) => profileById[id]?.fullName ?? id)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
timeline.add(
|
timeline.add(
|
||||||
_activityRow('Reassigned to $toNames', actorName, l.createdAt),
|
_activityRow(
|
||||||
|
'Reassigned to $toNames',
|
||||||
|
actorName,
|
||||||
|
l.createdAt,
|
||||||
|
icon: Icons.swap_horiz,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'started':
|
case 'started':
|
||||||
|
|
@ -2268,7 +2281,14 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
label =
|
label =
|
||||||
'Task started — Response: ${_formatDuration(responseDuration)} ($assigneeName responded at ${AppTime.formatDate(resp)} ${AppTime.formatTime(resp)})';
|
'Task started — Response: ${_formatDuration(responseDuration)} ($assigneeName responded at ${AppTime.formatDate(resp)} ${AppTime.formatTime(resp)})';
|
||||||
}
|
}
|
||||||
timeline.add(_activityRow(label, actorName, l.createdAt));
|
timeline.add(
|
||||||
|
_activityRow(
|
||||||
|
label,
|
||||||
|
actorName,
|
||||||
|
l.createdAt,
|
||||||
|
icon: Icons.play_arrow,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'completed':
|
case 'completed':
|
||||||
|
|
@ -2283,15 +2303,69 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
'Task completed — Execution: ${_formatDuration(exec)} (${AppTime.formatDate(start)} ${AppTime.formatTime(start)} → ${AppTime.formatDate(end)} ${AppTime.formatTime(end)})';
|
'Task completed — Execution: ${_formatDuration(exec)} (${AppTime.formatDate(start)} ${AppTime.formatTime(start)} → ${AppTime.formatDate(end)} ${AppTime.formatTime(end)})';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timeline.add(_activityRow(label, actorName, l.createdAt));
|
timeline.add(
|
||||||
|
_activityRow(
|
||||||
|
label,
|
||||||
|
actorName,
|
||||||
|
l.createdAt,
|
||||||
|
icon: Icons.check_circle,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'cancelled':
|
||||||
|
final meta = l.meta ?? {};
|
||||||
|
final reason = (meta['reason'] as String?) ?? '';
|
||||||
|
final base = reason.isNotEmpty
|
||||||
|
? 'Task cancelled — $reason'
|
||||||
|
: 'Task cancelled';
|
||||||
|
timeline.add(
|
||||||
|
_activityRow(base, actorName, l.createdAt, icon: Icons.cancel),
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
timeline.add(_activityRow(l.actionType, actorName, l.createdAt));
|
timeline.add(
|
||||||
|
_activityRow(
|
||||||
|
l.actionType,
|
||||||
|
actorName,
|
||||||
|
l.createdAt,
|
||||||
|
icon: Icons.info,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the task is cancelled but no explicit cancelled activity row exists,
|
||||||
|
// show a fallback using the task's cancellation fields.
|
||||||
|
final hasCancelledLog = logs.any((e) => e.actionType == 'cancelled');
|
||||||
|
if (task.status == 'cancelled' && !hasCancelledLog) {
|
||||||
|
final reason = task.cancellationReason;
|
||||||
|
final at = task.cancelledAt ?? AppTime.now();
|
||||||
|
String inferredActor = 'System';
|
||||||
|
try {
|
||||||
|
final candidates = logs
|
||||||
|
.where((e) => e.actorId != null && e.createdAt.isBefore(at))
|
||||||
|
.toList();
|
||||||
|
if (candidates.isNotEmpty) {
|
||||||
|
candidates.sort((a, b) => a.createdAt.compareTo(b.createdAt));
|
||||||
|
final last = candidates.last;
|
||||||
|
inferredActor = profileById[last.actorId]?.fullName ?? last.actorId!;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
timeline.add(
|
||||||
|
_activityRow(
|
||||||
|
reason != null && reason.isNotEmpty
|
||||||
|
? 'Task cancelled — $reason'
|
||||||
|
: 'Task cancelled',
|
||||||
|
inferredActor,
|
||||||
|
at,
|
||||||
|
icon: Icons.cancel,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Response and execution times are now merged into the related
|
// Response and execution times are now merged into the related
|
||||||
// 'Task started' and 'Task completed' timeline entries above.
|
// 'Task started' and 'Task completed' timeline entries above.
|
||||||
|
|
||||||
|
|
@ -2305,17 +2379,18 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
|
|
||||||
// TAT helpers removed; timings are shown inline in the activity timeline.
|
// TAT helpers removed; timings are shown inline in the activity timeline.
|
||||||
|
|
||||||
Widget _activityRow(String title, String actor, DateTime at) {
|
Widget _activityRow(
|
||||||
|
String title,
|
||||||
|
String actor,
|
||||||
|
DateTime at, {
|
||||||
|
IconData icon = Icons.circle,
|
||||||
|
}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(icon, size: 16, color: Theme.of(context).colorScheme.primary),
|
||||||
Icons.circle,
|
|
||||||
size: 12,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user