feat(programmer): admin monitor tab + drill-down
- Add isStrictAdminProvider (role == 'admin' only) - Add programmer_tasks_tabs.dart with ProgrammerTasksTab enum, programmerTasksTabsFor, parseProgrammerTasksTab, programmerTasksTabLabel - Make ProgrammerTasksListScreen role-aware via initialTab param and programmerTasksTabsFor; admin sees Monitor/Mine/All tabs - Add MonitorTab with AppStatusSummaryRow + responsive programmer grid (1/2/3 cols) + HelpPanel side/bottom - Add ProgrammerMonitorCard with state pills (Working/Paused/Idle/On leave/Pass slip) - Add HelpPanel ConsumerStatefulWidget with day stepper and help-edge rows - Add ProgrammerDrillDownScreen (/programmer-tasks/programmers/:userId); non-admins see lock empty view - Router: pass tab query param; add programmers/:userId before :id route - Tests: 7/7 pass; analyze: 0 new issues Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tasq/models/profile.model.dart';
|
||||
import 'package:tasq/screens/programmer_tasks/monitor/monitor_model.dart';
|
||||
import 'package:tasq/screens/programmer_tasks/monitor/programmer_monitor_card.dart';
|
||||
import 'package:tasq/screens/programmer_tasks/programmer_tasks_tabs.dart';
|
||||
import 'package:tasq/utils/app_time.dart';
|
||||
|
||||
Profile _profile({String id = 'u1', String name = 'Alice'}) => Profile(
|
||||
id: id,
|
||||
role: 'programmer',
|
||||
fullName: name,
|
||||
);
|
||||
|
||||
ProgrammerMonitorEntry _entry({
|
||||
required MonitorState state,
|
||||
String id = 'u1',
|
||||
String name = 'Alice',
|
||||
}) =>
|
||||
ProgrammerMonitorEntry(
|
||||
programmer: _profile(id: id, name: name),
|
||||
state: state,
|
||||
currentTask: null,
|
||||
currentTaskToday: Duration.zero,
|
||||
todayTotal: Duration.zero,
|
||||
inProgress: 0,
|
||||
paused: 0,
|
||||
notStarted: 0,
|
||||
sheetStatus: null,
|
||||
helped: [],
|
||||
helpedBy: [],
|
||||
);
|
||||
|
||||
Widget _wrapCard(ProgrammerMonitorEntry entry) {
|
||||
return ProviderScope(
|
||||
child: MaterialApp(
|
||||
home: Scaffold(
|
||||
body: ProgrammerMonitorCard(
|
||||
entry: entry,
|
||||
onTap: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
setUpAll(AppTime.initialize);
|
||||
|
||||
group('programmerTasksTabsFor', () {
|
||||
test('tabs in this slice', () {
|
||||
expect(
|
||||
programmerTasksTabsFor(isStrictAdmin: true),
|
||||
[
|
||||
ProgrammerTasksTab.monitor,
|
||||
ProgrammerTasksTab.mine,
|
||||
ProgrammerTasksTab.all,
|
||||
],
|
||||
);
|
||||
expect(
|
||||
programmerTasksTabsFor(isStrictAdmin: false),
|
||||
[ProgrammerTasksTab.mine, ProgrammerTasksTab.all],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('parseProgrammerTasksTab', () {
|
||||
test('parse tab query', () {
|
||||
expect(parseProgrammerTasksTab('day-sheets'), ProgrammerTasksTab.daySheets);
|
||||
expect(parseProgrammerTasksTab('x'), isNull);
|
||||
expect(parseProgrammerTasksTab(null), isNull);
|
||||
expect(parseProgrammerTasksTab('monitor'), ProgrammerTasksTab.monitor);
|
||||
expect(parseProgrammerTasksTab('mine'), ProgrammerTasksTab.mine);
|
||||
expect(parseProgrammerTasksTab('all'), ProgrammerTasksTab.all);
|
||||
expect(parseProgrammerTasksTab('approvals'), ProgrammerTasksTab.approvals);
|
||||
});
|
||||
});
|
||||
|
||||
group('monitor card pill labels', () {
|
||||
testWidgets('onLeave -> On leave', (tester) async {
|
||||
await tester.pumpWidget(_wrapCard(_entry(state: MonitorState.onLeave)));
|
||||
await tester.pump();
|
||||
expect(find.text('On leave'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('passSlip -> Pass slip', (tester) async {
|
||||
await tester.pumpWidget(_wrapCard(_entry(state: MonitorState.passSlip)));
|
||||
await tester.pump();
|
||||
expect(find.text('Pass slip'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('working -> Working', (tester) async {
|
||||
await tester.pumpWidget(_wrapCard(_entry(state: MonitorState.working)));
|
||||
await tester.pump();
|
||||
expect(find.text('Working'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('paused -> Paused', (tester) async {
|
||||
await tester.pumpWidget(_wrapCard(_entry(state: MonitorState.paused)));
|
||||
await tester.pump();
|
||||
expect(find.text('Paused'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('idle -> Idle', (tester) async {
|
||||
await tester.pumpWidget(_wrapCard(_entry(state: MonitorState.idle)));
|
||||
await tester.pump();
|
||||
expect(find.text('Idle'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user