Enhance Docker build workflow by adding path filters for specific APIs and workflow file

This commit is contained in:
Sven laptop
2026-05-08 19:04:09 +02:00
parent 114a2eab46
commit 3415cfa2b9
5 changed files with 179 additions and 152 deletions
+6 -1
View File
@@ -5,11 +5,16 @@ on:
branches: branches:
- main - main
- develop - develop
paths:
- 'auth_api/**'
- 'employee_api/**'
- 'transit_api/**'
- 'admin_ui/**'
- '.github/workflows/docker-build.yml'
pull_request: pull_request:
branches: branches:
- main - main
- develop - develop
workflow_dispatch:
env: env:
# GitHub Container Registry # GitHub Container Registry
+20 -1
View File
@@ -21,6 +21,7 @@ export default function ScheduleMaker({ token, user }) {
const [selectedLine, setSelectedLine] = useState('') const [selectedLine, setSelectedLine] = useState('')
const [selectedBus, setSelectedBus] = useState('') const [selectedBus, setSelectedBus] = useState('')
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]) const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0])
const [overviewDate, setOverviewDate] = useState(new Date().toISOString().split('T')[0])
const [startTime, setStartTime] = useState('08:00') const [startTime, setStartTime] = useState('08:00')
const [driverId, setDriverId] = useState('') const [driverId, setDriverId] = useState('')
const [selectedWeekdays, setSelectedWeekdays] = useState([]) const [selectedWeekdays, setSelectedWeekdays] = useState([])
@@ -226,7 +227,15 @@ export default function ScheduleMaker({ token, user }) {
const filteredSchedules = selectedDriverFilter const filteredSchedules = selectedDriverFilter
? schedules.filter(s => String(s.driverId) === String(selectedDriverFilter)) ? schedules.filter(s => String(s.driverId) === String(selectedDriverFilter))
: schedules : schedules
const schedulesBySlot = groupSchedulesByTimeSlot(filteredSchedules, timeSlots) const overviewSchedules = filteredSchedules.filter(schedule => {
if (!overviewDate) return true
const scheduleDate = new Date(schedule.startTime)
const selectedOverview = new Date(`${overviewDate}T00:00:00`)
return scheduleDate.getFullYear() === selectedOverview.getFullYear()
&& scheduleDate.getMonth() === selectedOverview.getMonth()
&& scheduleDate.getDate() === selectedOverview.getDate()
})
const schedulesBySlot = groupSchedulesByTimeSlot(overviewSchedules, timeSlots)
return ( return (
<section className="card"> <section className="card">
@@ -326,6 +335,16 @@ export default function ScheduleMaker({ token, user }) {
)} )}
<h3 style={{ marginTop: '2rem' }}>Timetable</h3> <h3 style={{ marginTop: '2rem' }}>Timetable</h3>
<div className="form-row" style={{ marginBottom: '1rem' }}>
<input
type="date"
value={overviewDate}
onChange={e => setOverviewDate(e.target.value)}
/>
<button type="button" onClick={() => setOverviewDate(new Date().toISOString().split('T')[0])}>
Vandaag
</button>
</div>
<div className="timetable-container"> <div className="timetable-container">
<table className="timetable"> <table className="timetable">
<thead> <thead>
+2
View File
@@ -67,6 +67,7 @@ class AppTheme {
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: colorScheme, colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFFF1F5F9), scaffoldBackgroundColor: const Color(0xFFF1F5F9),
materialTapTargetSize: MaterialTapTargetSize.padded,
textTheme: _textTheme(colorScheme), textTheme: _textTheme(colorScheme),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
backgroundColor: colorScheme.surface, backgroundColor: colorScheme.surface,
@@ -138,6 +139,7 @@ class AppTheme {
brightness: Brightness.dark, brightness: Brightness.dark,
colorScheme: colorScheme, colorScheme: colorScheme,
scaffoldBackgroundColor: const Color(0xFF0B1220), scaffoldBackgroundColor: const Color(0xFF0B1220),
materialTapTargetSize: MaterialTapTargetSize.padded,
textTheme: _textTheme(colorScheme).apply(bodyColor: Colors.white, displayColor: Colors.white), textTheme: _textTheme(colorScheme).apply(bodyColor: Colors.white, displayColor: Colors.white),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
backgroundColor: const Color(0xFF0B1220), backgroundColor: const Color(0xFF0B1220),
@@ -82,15 +82,18 @@ class _CustomInputFieldState extends State<CustomInputField> {
borderSide: BorderSide(color: colorScheme.primary, width: 2), borderSide: BorderSide(color: colorScheme.primary, width: 2),
), ),
suffixIcon: widget.obscureText suffixIcon: widget.obscureText
? GestureDetector( ? IconButton(
onTap: () { tooltip: _obscureText ? 'Toon wachtwoord' : 'Verberg wachtwoord',
onPressed: () {
setState(() => _obscureText = !_obscureText); setState(() => _obscureText = !_obscureText);
}, },
child: Icon( icon: Icon(
_obscureText ? Icons.visibility_off : Icons.visibility, _obscureText ? Icons.visibility_off : Icons.visibility,
size: 28, // Larger icon for accessibility size: 28, // Larger icon for accessibility
color: colorScheme.primary, color: colorScheme.primary,
), ),
splashRadius: 24,
constraints: const BoxConstraints(minWidth: 48, minHeight: 48),
) )
: null, : null,
), ),
+145 -147
View File
@@ -53,175 +53,173 @@ class RouteCard extends StatelessWidget {
final statusColor = _getStatusColor(route.status); final statusColor = _getStatusColor(route.status);
final startTimeStr = _formatTime(route.startTime); final startTimeStr = _formatTime(route.startTime);
return GestureDetector( return Material(
onTap: () { color: Colors.transparent,
// Navigate to navigation screen child: InkWell(
Navigator.of(context).push( onTap: () {
MaterialPageRoute( Navigator.of(context).push(
builder: (context) => NavigationScreen(route: route), MaterialPageRoute(
), builder: (context) => NavigationScreen(route: route),
); ),
}, );
child: Card( },
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), borderRadius: BorderRadius.circular(20),
elevation: 0, splashFactory: InkSparkle.splashFactory,
color: colorScheme.surface, child: Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding( elevation: 0,
padding: const EdgeInsets.all(16), color: colorScheme.surface,
child: Column( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
crossAxisAlignment: CrossAxisAlignment.start, child: Padding(
children: [ padding: const EdgeInsets.all(16),
// Header: Line number + Status child: Column(
Row( crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ // Header: Line number + Status
// Line number - Large and prominent Row(
Container( mainAxisAlignment: MainAxisAlignment.spaceBetween,
padding: children: [
const EdgeInsets.symmetric(horizontal: 12, vertical: 8), // Line number - Large and prominent
decoration: BoxDecoration( Container(
gradient: LinearGradient( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
colors: [colorScheme.primary, colorScheme.tertiary], decoration: BoxDecoration(
begin: Alignment.topLeft, gradient: LinearGradient(
end: Alignment.bottomRight, colors: [colorScheme.primary, colorScheme.tertiary],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(8),
), ),
borderRadius: BorderRadius.circular(8), child: Text(
), 'Line ${route.busLine.lineNumber}',
child: Text( style: Theme.of(context).textTheme.titleMedium?.copyWith(
'Line ${route.busLine.lineNumber}', color: Colors.white,
style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold,
color: Colors.white, fontSize: 18,
fontWeight: FontWeight.bold, ),
fontSize: 18,
),
),
),
// Status badge
Container(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.14),
border: Border.all(color: statusColor),
borderRadius: BorderRadius.circular(20),
),
child: Text(
_getStatusLabel(route.status),
style: TextStyle(
color: statusColor,
fontWeight: FontWeight.w600,
fontSize: 12,
), ),
), ),
), // Status badge
], Container(
), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
const SizedBox(height: 16), decoration: BoxDecoration(
color: statusColor.withOpacity(0.14),
border: Border.all(color: statusColor),
borderRadius: BorderRadius.circular(20),
),
child: Text(
_getStatusLabel(route.status),
style: TextStyle(
color: statusColor,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
),
],
),
const SizedBox(height: 16),
// Route info: Start -> End // Route info: Start -> End
Row( Row(
children: [ children: [
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'From',
style: Theme.of(context).textTheme.labelSmall,
),
Text(
route.busLine.startStop,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
),
Icon(
Icons.arrow_forward,
color: colorScheme.outline,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'To',
style: Theme.of(context).textTheme.labelSmall,
),
Text(
route.busLine.endStop,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
const SizedBox(height: 16),
// Bus info and time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Bus type
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'From', 'Bus',
style: Theme.of(context).textTheme.labelSmall, style: Theme.of(context).textTheme.labelSmall,
), ),
Text( Text(
route.busLine.startStop, '${route.busType.name} (${route.busType.seatCapacity} seats)',
style: style: Theme.of(context).textTheme.titleSmall?.copyWith(
Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
), ),
const SizedBox(height: 4),
Text(
route.busType.licensePlate,
style: Theme.of(context).textTheme.labelMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
), ),
], ],
), ),
), // Start time
Icon( Column(
Icons.arrow_forward,
color: colorScheme.outline,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text( Text(
'To', 'Start Time',
style: Theme.of(context).textTheme.labelSmall, style: Theme.of(context).textTheme.labelSmall,
), ),
Text( Text(
route.busLine.endStop, startTimeStr,
style: style: Theme.of(context).textTheme.headlineSmall?.copyWith(
Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold,
fontWeight: FontWeight.w600, color: colorScheme.primary,
), ),
),
const SizedBox(height: 4),
Text(
'${route.busLine.estimatedDuration} min duration',
style: Theme.of(context).textTheme.labelMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
), ),
], ],
), ),
), ],
], ),
), ],
const SizedBox(height: 16), ),
// Bus info and time
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Bus type
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Bus',
style: Theme.of(context).textTheme.labelSmall,
),
Text(
'${route.busType.name} (${route.busType.seatCapacity} seats)',
style:
Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
route.busType.licensePlate,
style: Theme.of(context).textTheme.labelMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
// Start time
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Start Time',
style: Theme.of(context).textTheme.labelSmall,
),
Text(
startTimeStr,
style:
Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
color: colorScheme.primary,
),
),
const SizedBox(height: 4),
Text(
'${route.busLine.estimatedDuration} min duration',
style: Theme.of(context).textTheme.labelMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
],
),
],
), ),
), ),
), ),