feat: add Security room with Users and Groups sections
- Add Security room accessible from main navigation - Implement Users list page with DataGrid (fetches from /auth/users) - Implement Groups list page with DataGrid (fetches from /auth/groups) - Move user/group management from Control Room to dedicated Security room - Remove Authentik section from Control Room navigation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
2adb50b352
commit
a5a8e7ba88
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:tatlock_ui/features/security/router.dart';
|
||||
import 'package:tatlock_ui/features/security/users/users_list_page.dart';
|
||||
import 'package:tatlock_ui/features/security/groups/groups_list_page.dart';
|
||||
import 'package:tatlock_ui/shared/layouts/widgets/nav_panel.dart';
|
||||
|
||||
/// Main Security room page with nav panel and section content.
|
||||
class SecurityPage extends ConsumerWidget {
|
||||
const SecurityPage({
|
||||
super.key,
|
||||
this.nav = SecurityNav.users,
|
||||
});
|
||||
|
||||
/// The current nav item to display.
|
||||
final SecurityNav nav;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
// Nav Panel - section navigation with grouping
|
||||
NavPanel(
|
||||
title: 'Sections',
|
||||
icon: Icons.security_outlined,
|
||||
items: SecurityNav.values.map((n) => n.toNavItem()).toList(),
|
||||
selectedId: nav.id,
|
||||
onItemSelected: (id) {
|
||||
final newNav = SecurityNav.values.firstWhere(
|
||||
(n) => n.id == id,
|
||||
);
|
||||
// Navigate to section URL
|
||||
context.go(pathForSecurityNav(newNav));
|
||||
},
|
||||
),
|
||||
// Divider
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
thickness: 1,
|
||||
color: colorScheme.outlineVariant,
|
||||
),
|
||||
// Section content
|
||||
Expanded(
|
||||
child: _SectionContent(nav: nav),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders content for the selected nav item.
|
||||
class _SectionContent extends StatelessWidget {
|
||||
const _SectionContent({required this.nav});
|
||||
|
||||
final SecurityNav nav;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (nav) {
|
||||
case SecurityNav.users:
|
||||
return const UsersListPage();
|
||||
case SecurityNav.groups:
|
||||
return const GroupsListPage();
|
||||
default:
|
||||
return _PlaceholderSection(nav: nav);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder for nav items not yet implemented.
|
||||
class _PlaceholderSection extends StatelessWidget {
|
||||
const _PlaceholderSection({required this.nav});
|
||||
|
||||
final SecurityNav nav;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
nav.icon,
|
||||
size: 64,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
nav.label,
|
||||
style: textTheme.headlineSmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${nav.section} • Coming soon',
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user