feat(scheduler): unified resource timeline dispatch board#218
feat(scheduler): unified resource timeline dispatch board#218roncodes merged 6 commits intodev-v0.6.39from
Conversation
## Summary
Complete refactor of the order scheduler from a disconnected month-grid
into a unified, industry-standard resource timeline dispatch board.
## New Files
- addon/services/scheduling.js
Central SchedulingService with undo/redo stack, conflict detection,
optimistic assign/unschedule, bulk assign, and best-fit placement.
- addon/utils/create-full-calendar-event-from-schedule-item.js
Transforms a ScheduleItem record into a FullCalendar background event
for rendering driver shift windows on the resource timeline.
- addon/components/modals/scheduling-conflict.hbs
Modal that surfaces detected scheduling conflicts with auto-adjust
and assign-anyway resolution options.
- addon/components/modals/bulk-assign-orders.hbs
Modal for assigning multiple selected sidebar orders to a driver
at a chosen date/time in a single operation.
## Modified Files
- addon/controllers/operations/scheduler/index.js
- Injects new SchedulingService
- Reactive computed getters: unscheduledOrders (multi-status, search
filtered), calendarResources (drivers + capacity), allCalendarEvents
(order events + shift background blocks)
- Ember Concurrency debounced search task
- Bulk selection state (selectedOrderIds Set, toggleOrderSelection,
selectAllOrders, clearSelection, isOrderSelected, hasSelection)
- Undo/redo actions delegating to SchedulingService
- Real-time socket event handlers (order:updated, driver:updated)
- setViewRange, goToPrev, goToNext, goToToday toolbar actions
- openBulkAssignModal, addDriverShift actions
- Replaces hostRouter.refresh() with targeted store updates
- addon/routes/operations/scheduler/index.js
- Parallel model loading: orders (created + dispatched + active),
drivers, and schedule items in a single RSVP.hash
- Socket channel subscription/teardown lifecycle
- addon/templates/operations/scheduler/index.hbs
- Two-column layout: collapsible sidebar + full-height timeline
- Toolbar: day/week toggle, prev/today/next, undo/redo, add-shift,
bulk-assign (contextual), clear-selection
- Sidebar: debounced search input, select-all, per-order checkboxes,
FullCalendar::Draggable wrappers, empty state
- Timeline: FullCalendar resourceTimelineDay with time-precise events,
resource rows per driver, open-source license key
- addon/utils/create-full-calendar-event-from-order.js
- Removes allDay: true — events now positioned at exact scheduled time
- Adds resourceId from driver_uuid for correct driver row placement
- Derives end time from estimated_duration (default 60 min)
- Status-based backgroundColor (created=indigo, dispatched=blue,
active=green, completed=gray, cancelled=red, expired=orange)
- addon/components/order/schedule-card.hbs
- Adds optional checkbox for multi-select bulk scheduling
- Applies ring highlight when @selected=true
- translations/en-us.yaml
- Adds 22 new scheduler i18n keys (view-day, view-week, undo, redo,
search-orders, select-all, all-scheduled, bulk-assign, conflict-*,
assign-anyway, auto-adjust, clear-selection, etc.)
## Breaking Changes
None. The new SchedulingService is additive. The route model shape is
extended (adds drivers and scheduleItems) but is backward-compatible.
## Testing Notes
- Unit tests needed for SchedulingService.checkConflicts,
assignOrder optimistic rollback, and bulkAssign
- Integration tests needed for unscheduledOrders computed getter
(search filter, status filter)
- E2E: drag unscheduled order onto driver row, verify event appears
at correct time; trigger conflict, verify modal; undo, verify revert
9fd8376 to
922db3a
Compare
Fix: Modal implementations, app re-exports, and callback signaturesThis force-push ( 1. Modal templates — correct
|
| Before (wrong) | After (correct) |
|---|---|
| `<ModalDefault @modal={{@modal}} as | modal |
<modal.header>, <modal.body>, <modal.footer> block slots |
<div class="modal-body-container"> inside the component body |
@modal.options.foo |
@options.foo |
@modal.title |
Rendered automatically by Modal::Default from @options.title |
Custom <modal.footer> with modal.confirm / modal.decline |
Footer buttons controlled via @options properties (acceptButtonText, hideDeclineButton, etc.) |
modals/bulk-assign-orders.hbs — now uses @options.driver, @options.date, @options.orders with ModelSelect and DateTimeInput matching the assign-driver pattern.
modals/scheduling-conflict.hbs — now uses @options.conflicts, @options.driver, @options.order. Custom resolution buttons (Auto-Adjust, Assign Anyway) are placed inside the body and delegate to the new JS component actions.
2. New JS component — modals/scheduling-conflict.js
The conflict modal requires a backing Glimmer component to expose the autoAdjust and assignAnyway actions (which call @options.autoAdjust / @options.assignAnyway with the correct (modalsManager, done) signature). Added:
addon/components/modals/scheduling-conflict.js
3. Controller callback signatures corrected
All confirm, unschedule, delete, and autoAdjust/assignAnyway callbacks in the controller were updated from async (modal) => to async (modalsManager, done) =>, matching the actual modalsManager.onClickConfirmWithDone signature:
// modalsManager service calls:
confirm(this, done) // this = modalsManager service, done = close function4. App re-exports added (the missing piece)
All new addon/ files now have corresponding app/ re-export shims:
| New re-export | Points to |
|---|---|
app/services/scheduling.js |
@fleetbase/fleetops-engine/services/scheduling |
app/utils/create-full-calendar-event-from-schedule-item.js |
@fleetbase/fleetops-engine/utils/create-full-calendar-event-from-schedule-item |
app/components/modals/scheduling-conflict.js |
@fleetbase/fleetops-engine/components/modals/scheduling-conflict |
app/components/modals/bulk-assign-orders.js |
@fleetbase/fleetops-engine/components/modals/bulk-assign-orders |
Total files in this commit: 15 (10 original + 5 new from this fix push)
## Summary
Complete refactor of the order scheduler from a disconnected month-grid
into a unified, industry-standard resource timeline dispatch board.
## New Files
- addon/services/scheduling.js
Central SchedulingService with undo/redo stack, conflict detection,
optimistic assign/unschedule, bulk assign, and best-fit placement.
- addon/utils/create-full-calendar-event-from-schedule-item.js
Transforms a ScheduleItem record into a FullCalendar background event
for rendering driver shift windows on the resource timeline.
- addon/components/modals/scheduling-conflict.hbs
Modal that surfaces detected scheduling conflicts with auto-adjust
and assign-anyway resolution options.
- addon/components/modals/bulk-assign-orders.hbs
Modal for assigning multiple selected sidebar orders to a driver
at a chosen date/time in a single operation.
## Modified Files
- addon/controllers/operations/scheduler/index.js
- Injects new SchedulingService
- Reactive computed getters: unscheduledOrders (multi-status, search
filtered), calendarResources (drivers + capacity), allCalendarEvents
(order events + shift background blocks)
- Ember Concurrency debounced search task
- Bulk selection state (selectedOrderIds Set, toggleOrderSelection,
selectAllOrders, clearSelection, isOrderSelected, hasSelection)
- Undo/redo actions delegating to SchedulingService
- Real-time socket event handlers (order:updated, driver:updated)
- setViewRange, goToPrev, goToNext, goToToday toolbar actions
- openBulkAssignModal, addDriverShift actions
- Replaces hostRouter.refresh() with targeted store updates
- addon/routes/operations/scheduler/index.js
- Parallel model loading: orders (created + dispatched + active),
drivers, and schedule items in a single RSVP.hash
- Socket channel subscription/teardown lifecycle
- addon/templates/operations/scheduler/index.hbs
- Two-column layout: collapsible sidebar + full-height timeline
- Toolbar: day/week toggle, prev/today/next, undo/redo, add-shift,
bulk-assign (contextual), clear-selection
- Sidebar: debounced search input, select-all, per-order checkboxes,
FullCalendar::Draggable wrappers, empty state
- Timeline: FullCalendar resourceTimelineDay with time-precise events,
resource rows per driver, open-source license key
- addon/utils/create-full-calendar-event-from-order.js
- Removes allDay: true — events now positioned at exact scheduled time
- Adds resourceId from driver_uuid for correct driver row placement
- Derives end time from estimated_duration (default 60 min)
- Status-based backgroundColor (created=indigo, dispatched=blue,
active=green, completed=gray, cancelled=red, expired=orange)
- addon/components/order/schedule-card.hbs
- Adds optional checkbox for multi-select bulk scheduling
- Applies ring highlight when @selected=true
- translations/en-us.yaml
- Adds 22 new scheduler i18n keys (view-day, view-week, undo, redo,
search-orders, select-all, all-scheduled, bulk-assign, conflict-*,
assign-anyway, auto-adjust, clear-selection, etc.)
## Breaking Changes
None. The new SchedulingService is additive. The route model shape is
extended (adds drivers and scheduleItems) but is backward-compatible.
## Testing Notes
- Unit tests needed for SchedulingService.checkConflicts,
assignOrder optimistic rollback, and bulkAssign
- Integration tests needed for unscheduledOrders computed getter
(search filter, status filter)
- E2E: drag unscheduled order onto driver row, verify event appears
at correct time; trigger conflict, verify modal; undo, verify revert
57be129 to
0196a96
Compare
## Summary
Complete refactor of the order scheduler from a disconnected month-grid
into a unified, industry-standard resource timeline dispatch board.
## New Files
- addon/services/scheduling.js
Central SchedulingService with undo/redo stack, conflict detection,
optimistic assign/unschedule, bulk assign, and best-fit placement.
- addon/utils/create-full-calendar-event-from-schedule-item.js
Transforms a ScheduleItem record into a FullCalendar background event
for rendering driver shift windows on the resource timeline.
- addon/components/modals/scheduling-conflict.hbs
Modal that surfaces detected scheduling conflicts with auto-adjust
and assign-anyway resolution options.
- addon/components/modals/bulk-assign-orders.hbs
Modal for assigning multiple selected sidebar orders to a driver
at a chosen date/time in a single operation.
## Modified Files
- addon/controllers/operations/scheduler/index.js
- Injects new SchedulingService
- Reactive computed getters: unscheduledOrders (multi-status, search
filtered), calendarResources (drivers + capacity), allCalendarEvents
(order events + shift background blocks)
- Ember Concurrency debounced search task
- Bulk selection state (selectedOrderIds Set, toggleOrderSelection,
selectAllOrders, clearSelection, isOrderSelected, hasSelection)
- Undo/redo actions delegating to SchedulingService
- Real-time socket event handlers (order:updated, driver:updated)
- setViewRange, goToPrev, goToNext, goToToday toolbar actions
- openBulkAssignModal, addDriverShift actions
- Replaces hostRouter.refresh() with targeted store updates
- addon/routes/operations/scheduler/index.js
- Parallel model loading: orders (created + dispatched + active),
drivers, and schedule items in a single RSVP.hash
- Socket channel subscription/teardown lifecycle
- addon/templates/operations/scheduler/index.hbs
- Two-column layout: collapsible sidebar + full-height timeline
- Toolbar: day/week toggle, prev/today/next, undo/redo, add-shift,
bulk-assign (contextual), clear-selection
- Sidebar: debounced search input, select-all, per-order checkboxes,
FullCalendar::Draggable wrappers, empty state
- Timeline: FullCalendar resourceTimelineDay with time-precise events,
resource rows per driver, open-source license key
- addon/utils/create-full-calendar-event-from-order.js
- Removes allDay: true — events now positioned at exact scheduled time
- Adds resourceId from driver_uuid for correct driver row placement
- Derives end time from estimated_duration (default 60 min)
- Status-based backgroundColor (created=indigo, dispatched=blue,
active=green, completed=gray, cancelled=red, expired=orange)
- addon/components/order/schedule-card.hbs
- Adds optional checkbox for multi-select bulk scheduling
- Applies ring highlight when @selected=true
- translations/en-us.yaml
- Adds 22 new scheduler i18n keys (view-day, view-week, undo, redo,
search-orders, select-all, all-scheduled, bulk-assign, conflict-*,
assign-anyway, auto-adjust, clear-selection, etc.)
## Breaking Changes
None. The new SchedulingService is additive. The route model shape is
extended (adds drivers and scheduleItems) but is backward-compatible.
## Testing Notes
- Unit tests needed for SchedulingService.checkConflicts,
assignOrder optimistic rollback, and bulkAssign
- Integration tests needed for unscheduledOrders computed getter
(search filter, status filter)
- E2E: drag unscheduled order onto driver row, verify event appears
at correct time; trigger conflict, verify modal; undo, verify revert
324956a to
4be6ad4
Compare
…e/fleetops into feat/unified-scheduler-refactor
Overview
This PR implements the full scheduler refactor outlined in the technical implementation plan. The order scheduler is transformed from a disconnected month-grid into a unified, industry-standard resource timeline dispatch board — with every driver on their own row, orders positioned at their exact scheduled time, and a collapsible sidebar for unscheduled orders.
Files Changed
addon/services/scheduling.jsaddon/routes/operations/scheduler/index.jsaddon/controllers/operations/scheduler/index.jsaddon/templates/operations/scheduler/index.hbsaddon/utils/create-full-calendar-event-from-order.jsaddon/utils/create-full-calendar-event-from-schedule-item.jsaddon/components/order/schedule-card.hbsaddon/components/modals/scheduling-conflict.hbsaddon/components/modals/bulk-assign-orders.hbstranslations/en-us.yamlKey Changes in Detail
New:
SchedulingServiceassignOrder(order, driver, start)— optimistic update with automatic rollback on API failureunscheduleOrder(order)— removes driver/time assignment, moves order back to sidebarbulkAssign(orderIds, driver, start)— assigns multiple orders sequentially with gap spacingcheckConflicts(driver, start, end)— scans existing events for overlaps before committingfindBestFit(order, driver)— calls/best-fitAPI with heuristic fallbackcanUndo/canRedotracked propertiesModified:
create-full-calendar-event-from-order.jsallDay: truescheduled_attimeresourceIdresourceId: driver_uuid— event renders in correct driver rowendendderived fromestimated_duration(default 60 min)Backend Requirements (follow-up)
GET /fleet-ops/ordersmulti-status filterOrdermodel:estimated_durationfield (integer, minutes)Drivermodel:max_daily_ordersfield (integer)POST /fleet-ops/orders/bulk-scheduleendpointGET /fleet-ops/orders/:id/best-fit?driver_uuid=endpointfleet-ops.{org_uuid}Testing Checklist
Breaking Changes
None.
SchedulingServiceis additive. Route model shape is extended but backward-compatible.