Add PM extension (Projects, Work Logs, Comments) + Quill rich-text UI
Projects: Brick-backed model with list/detail screens and nav entry. Work Logs: per-contributor time ledger, assignee running-clock + helper logged minutes with Hours/Minutes input; pause-after-save and helper-deduct prompts. Comments: threaded comments with file attachments and Quill composer. Detail screen: tabbed layout (Work Log / Comments / Activity), editable title + description via edit dialog, Quill-rendered descriptions with legacy plain-text fallback. Create dialog: fixed-width (480px max), Quill description editor. Shared QuillFieldEditor + QuillReadOnly widgets extracted for reuse. RLS: hardened activity-log actor binding, immutable creator_id/ created_at triggers, SECURITY INVOKER visibility helper, append-only work-log and scoped comment policies. Brick migration for project_id FK on programmer_tasks. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../models/programmer_task_work_log.model.dart';
|
||||
import 'supabase_provider.dart';
|
||||
|
||||
/// Work-log entries for a task (newest first), streamed live.
|
||||
final programmerTaskWorkLogsProvider =
|
||||
StreamProvider.family<List<ProgrammerTaskWorkLog>, String>((ref, taskId) {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
return client
|
||||
.from('programmer_task_work_logs')
|
||||
.stream(primaryKey: ['id'])
|
||||
.eq('task_id', taskId)
|
||||
.order('created_at', ascending: false)
|
||||
.map((rows) => rows.map(ProgrammerTaskWorkLog.fromMap).toList());
|
||||
});
|
||||
|
||||
final programmerTaskWorkLogsControllerProvider =
|
||||
Provider<ProgrammerTaskWorkLogsController>((ref) {
|
||||
return ProgrammerTaskWorkLogsController(ref.watch(supabaseClientProvider));
|
||||
});
|
||||
|
||||
class ProgrammerTaskWorkLogsController {
|
||||
ProgrammerTaskWorkLogsController(this._client);
|
||||
final dynamic _client;
|
||||
|
||||
/// Adds a work-log entry. [minutes] is null for the assignee's progress notes
|
||||
/// (their time comes from the running clock) and set for a helper's
|
||||
/// Time Consumed.
|
||||
Future<void> addWorkLog({
|
||||
required String taskId,
|
||||
required String description,
|
||||
int? minutes,
|
||||
}) async {
|
||||
final userId = _client.auth.currentUser?.id;
|
||||
if (userId == null) throw Exception('Not authenticated');
|
||||
await _client.from('programmer_task_work_logs').insert({
|
||||
'task_id': taskId,
|
||||
'author_id': userId,
|
||||
'description': description,
|
||||
'minutes': ?minutes,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user