Add Programmer Tasks module (work-log + time tracking)
Separate feature for the `programmer` role to record dev work by category, distinct from the IT help-desk `tasks` feature. Modeled on the IT Service Requests pattern (Brick offline-first model -> Riverpod stream/controller -> list/detail screens); seed of a future Project Management workflow. - programmer_tasks + programmer_task_activity_logs (category enum, RLS, realtime) via supabase migration - single assignee, self-logged or lead-assigned; assign/reassign logged - pause-on-switch: starting a task while another runs prompts to pause the running one, keeping one active task per user for accurate time attribution - worked-duration math shared with help-desk tasks via a generic core in task_duration.dart (existing callers unchanged) - list distinguishes running vs paused with a per-task Resume shortcut - accessible dialog labels; route /programmer-tasks + nav gated to admin/programmer - unit/widget tests: controller lifecycle, duration math, pause-switch dialog Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
// GENERATED CODE DO NOT EDIT
|
||||
part of '../brick.g.dart';
|
||||
|
||||
Future<ProgrammerTaskActivityLog> _$ProgrammerTaskActivityLogFromSupabase(
|
||||
Map<String, dynamic> data, {
|
||||
required SupabaseProvider provider,
|
||||
OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async {
|
||||
return ProgrammerTaskActivityLog(
|
||||
id: data['id'] as String,
|
||||
taskId: data['task_id'] as String,
|
||||
actorId: data['actor_id'] == null ? null : data['actor_id'] as String?,
|
||||
actionType: data['action_type'] as String,
|
||||
meta: data['meta'] == null ? null : data['meta'],
|
||||
createdAt: DateTime.parse(data['created_at'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _$ProgrammerTaskActivityLogToSupabase(
|
||||
ProgrammerTaskActivityLog instance, {
|
||||
required SupabaseProvider provider,
|
||||
OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async {
|
||||
return {
|
||||
'id': instance.id,
|
||||
'task_id': instance.taskId,
|
||||
'actor_id': instance.actorId,
|
||||
'action_type': instance.actionType,
|
||||
'meta': instance.meta,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
Future<ProgrammerTaskActivityLog> _$ProgrammerTaskActivityLogFromSqlite(
|
||||
Map<String, dynamic> data, {
|
||||
required SqliteProvider provider,
|
||||
OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async {
|
||||
return ProgrammerTaskActivityLog(
|
||||
id: data['id'] as String,
|
||||
taskId: data['task_id'] as String,
|
||||
actorId: data['actor_id'] == null ? null : data['actor_id'] as String?,
|
||||
actionType: data['action_type'] as String,
|
||||
meta: data['meta'] == null ? null : jsonDecode(data['meta']),
|
||||
createdAt: DateTime.parse(data['created_at'] as String),
|
||||
)..primaryKey = data['_brick_id'] as int;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _$ProgrammerTaskActivityLogToSqlite(
|
||||
ProgrammerTaskActivityLog instance, {
|
||||
required SqliteProvider provider,
|
||||
OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async {
|
||||
return {
|
||||
'id': instance.id,
|
||||
'task_id': instance.taskId,
|
||||
'actor_id': instance.actorId,
|
||||
'action_type': instance.actionType,
|
||||
'meta': instance.meta != null ? jsonEncode(instance.meta) : null,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Construct a [ProgrammerTaskActivityLog]
|
||||
class ProgrammerTaskActivityLogAdapter
|
||||
extends OfflineFirstWithSupabaseAdapter<ProgrammerTaskActivityLog> {
|
||||
ProgrammerTaskActivityLogAdapter();
|
||||
|
||||
@override
|
||||
final supabaseTableName = 'programmer_task_activity_logs';
|
||||
@override
|
||||
final defaultToNull = true;
|
||||
@override
|
||||
final fieldsToSupabaseColumns = {
|
||||
'id': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'id',
|
||||
),
|
||||
'taskId': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'task_id',
|
||||
),
|
||||
'actorId': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'actor_id',
|
||||
),
|
||||
'actionType': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'action_type',
|
||||
),
|
||||
'meta': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'meta',
|
||||
),
|
||||
'createdAt': const RuntimeSupabaseColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'created_at',
|
||||
),
|
||||
};
|
||||
@override
|
||||
final ignoreDuplicates = false;
|
||||
@override
|
||||
final uniqueFields = {};
|
||||
@override
|
||||
final Map<String, RuntimeSqliteColumnDefinition> fieldsToSqliteColumns = {
|
||||
'primaryKey': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: '_brick_id',
|
||||
iterable: false,
|
||||
type: int,
|
||||
),
|
||||
'id': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'id',
|
||||
iterable: false,
|
||||
type: String,
|
||||
),
|
||||
'taskId': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'task_id',
|
||||
iterable: false,
|
||||
type: String,
|
||||
),
|
||||
'actorId': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'actor_id',
|
||||
iterable: false,
|
||||
type: String,
|
||||
),
|
||||
'actionType': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'action_type',
|
||||
iterable: false,
|
||||
type: String,
|
||||
),
|
||||
'meta': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'meta',
|
||||
iterable: false,
|
||||
type: Map,
|
||||
),
|
||||
'createdAt': const RuntimeSqliteColumnDefinition(
|
||||
association: false,
|
||||
columnName: 'created_at',
|
||||
iterable: false,
|
||||
type: DateTime,
|
||||
),
|
||||
};
|
||||
@override
|
||||
Future<int?> primaryKeyByUniqueColumns(
|
||||
ProgrammerTaskActivityLog instance,
|
||||
DatabaseExecutor executor,
|
||||
) async => instance.primaryKey;
|
||||
@override
|
||||
final String tableName = 'ProgrammerTaskActivityLog';
|
||||
|
||||
@override
|
||||
Future<ProgrammerTaskActivityLog> fromSupabase(
|
||||
Map<String, dynamic> input, {
|
||||
required provider,
|
||||
covariant OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async => await _$ProgrammerTaskActivityLogFromSupabase(
|
||||
input,
|
||||
provider: provider,
|
||||
repository: repository,
|
||||
);
|
||||
@override
|
||||
Future<Map<String, dynamic>> toSupabase(
|
||||
ProgrammerTaskActivityLog input, {
|
||||
required provider,
|
||||
covariant OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async => await _$ProgrammerTaskActivityLogToSupabase(
|
||||
input,
|
||||
provider: provider,
|
||||
repository: repository,
|
||||
);
|
||||
@override
|
||||
Future<ProgrammerTaskActivityLog> fromSqlite(
|
||||
Map<String, dynamic> input, {
|
||||
required provider,
|
||||
covariant OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async => await _$ProgrammerTaskActivityLogFromSqlite(
|
||||
input,
|
||||
provider: provider,
|
||||
repository: repository,
|
||||
);
|
||||
@override
|
||||
Future<Map<String, dynamic>> toSqlite(
|
||||
ProgrammerTaskActivityLog input, {
|
||||
required provider,
|
||||
covariant OfflineFirstWithSupabaseRepository? repository,
|
||||
}) async => await _$ProgrammerTaskActivityLogToSqlite(
|
||||
input,
|
||||
provider: provider,
|
||||
repository: repository,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user