Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e44f32a
fix service rate/service fees display, fix sms verification code comp…
roncodes Dec 8, 2025
a5f4aac
pass company_uuid to sms verification code generation
roncodes Dec 8, 2025
768f3d6
feat: added composite indexes to improve application performance
roncodes Dec 16, 2025
44358af
fix: Transform polymorphic type columns in API resources to use short…
roncodes Dec 16, 2025
0c36904
perf: Fix OrderTracker timeout issues with caching and HTTP timeouts
roncodes Dec 16, 2025
c89b96f
fix: Handle SpatialExpression to Point conversion in OrderTracker
roncodes Dec 16, 2025
a412691
fix: Handle SpatialExpression to Point conversion in all OSRM methods
roncodes Dec 16, 2025
1246eff
perf: Aggressive optimizations to prevent 30s timeout in OrderTracker
roncodes Dec 16, 2025
9fe27cd
feat: Add comprehensive caching and query optimizations to LiveContro…
roncodes Dec 16, 2025
9bcd7e9
feat: Add version-based cache invalidation to LiveCacheService
roncodes Dec 16, 2025
16b0f9c
ran linter and disabled `with_tracker_data` param on active orders
roncodes Dec 16, 2025
aff435c
perf: Limit tracker data to first 30 orders in LiveController
roncodes Dec 16, 2025
c2f1096
added HasApiModelCache trait to relevant models
roncodes Dec 16, 2025
67ea43a
stronger query guard against distance based sql queries
roncodes Dec 18, 2025
9dd0d8b
refactor: eliminate N+1 queries in OrderResource
roncodes Dec 18, 2025
7caa0e7
refactor: use whenLoaded() syntax and remove unused $isPublic variable
roncodes Dec 18, 2025
db91309
feat: implement lightweight OrderIndexResource for optimized list views
roncodes Dec 18, 2025
cba1d1d
feat: add location tracking data to lightweight Driver and Vehicle re…
roncodes Dec 18, 2025
73cfbbd
feat: add foreign key UUIDs to all index resources for frontend data …
roncodes Dec 18, 2025
5ae06a6
ran linter
roncodes Dec 18, 2025
9957167
feat: add avatar_url to Place and qr_code/barcode to Order index reso…
roncodes Dec 18, 2025
cd29318
refactor: remove barcode field from Order index resource, keep only q…
roncodes Dec 18, 2025
5655002
feat: add viewport-based spatial filtering to LiveController endpoints
roncodes Dec 18, 2025
1f19714
refactor: remove spatial filtering from orders endpoint
roncodes Dec 18, 2025
a18dffb
feat: implement viewport-based spatial filtering in live map component
roncodes Dec 18, 2025
a87e1ec
fix: use MySQL spatial functions for viewport filtering
roncodes Dec 18, 2025
066570e
fix: add bounds parameter to initial map load
roncodes Dec 18, 2025
96a8bfd
fix: add coordinate validation to spatial filtering
roncodes Dec 18, 2025
d411984
fix: add tracking_number relationship and meta flag to Order index re…
roncodes Dec 18, 2025
980805e
feat: use index resources for vehicles and places in LiveController
roncodes Dec 18, 2025
6dc0fea
fix: add address attribute to Place index resource
roncodes Dec 18, 2025
69b59bb
almost eveyrthing is wotking t 5x performance
roncodes Dec 18, 2025
95046ed
fix: convert SpatialExpression to Point in OrderTracker ETA calculation
roncodes Dec 18, 2025
6ab69bb
feat: optimize tracker data generation in LiveController
roncodes Dec 18, 2025
bb048c0
fix: convert SpatialExpression to Point in all OrderTracker ETA methods
roncodes Dec 18, 2025
5e79f58
feat: implement lazy loading for order tracker data
roncodes Dec 18, 2025
89e8de4
feat: add caching to tracker endpoint with automatic invalidation
roncodes Dec 18, 2025
10153fc
fix: add tracking property back to Order index resource
roncodes Dec 18, 2025
e8d056c
fix broken translations
roncodes Dec 18, 2025
3c5e803
ran prettier
roncodes Dec 18, 2025
a5928c2
fix scheduler
roncodes Dec 18, 2025
f729179
Fix scheduler + add tooltip to order event
roncodes Dec 19, 2025
e9c5508
Update service rate form template to use rate_fees relationship
roncodes Dec 19, 2025
bde94d6
Merge pull request #196 from fleetbase/fix/service-rate-fee-persistence
roncodes Dec 19, 2025
8910e31
Fix Fixed Rate distance display in details view
roncodes Dec 19, 2025
3fe6ade
Refactor Fixed Rate fee generation - move logic to service
roncodes Dec 19, 2025
574fd2e
properly use the on change for max distance input
roncodes Dec 19, 2025
d4b5cd2
Fix duplicate rate_fees bug after save
roncodes Dec 19, 2025
59bd91d
cleanup order details pill usage
roncodes Dec 19, 2025
42313a4
Add cleanup method to remove duplicate unsaved rate_fees after save
roncodes Dec 19, 2025
750c599
Remove manual cleanup - now handled in serializer
roncodes Dec 19, 2025
e007a78
Add @onChange handler to MoneyInput for rate_fees
roncodes Dec 19, 2025
2674792
Revert MoneyInput @onChange changes - unnecessary
roncodes Dec 19, 2025
16c14c7
Refactor setServiceRateFees and setServiceRateParcelFees to apply cas…
roncodes Dec 19, 2025
dce5cc2
Remove redundant onRowInsert() calls - Insertable trait already handl…
roncodes Dec 19, 2025
e34e4f1
feat: fixed service rates
roncodes Dec 19, 2025
053c9d5
Fixed linter
roncodes Dec 19, 2025
149e343
upgraded dependencies
roncodes Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion addon/components/customer/create-order-form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
<ModelSelect
@modelName="place"
@selectedModel={{waypoint.place}}
@placeholder={{concat (t "order.fields.select-waypoint-placeholder") " " (add index 1)}}
@placeholder={{concat (t "order.fields.select-waypoint") " " (add index 1)}}
@triggerClass="form-select form-input truncate max-w-250px"
@infiniteScroll={{false}}
@customSearchEndpoint="places/search"
Expand Down
68 changes: 34 additions & 34 deletions addon/components/customer/order-form.hbs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions addon/components/customer/orders.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
</div>
{{else}}
<div class="px-10 py-2 flex items-center justify-center">
<p class="text-red-600 dark:text-red-100">{{t "fleet-ops.operations.orders.index.view.no-order-activity"}}</p>
<p class="text-red-600 dark:text-red-100">{{t "order.fields.no-order-activity"}}</p>
</div>
{{/each}}
</div>
Expand All @@ -179,7 +179,7 @@
@value={{group.waypoint.tracking}}
class="rounded-md bg-yellow-300 text-yellow-900 px-2 py-0.5 text-xs flex-grow-0 truncate"
>
<span>{{t "fleet-ops.operations.orders.index.view.tracking"}}</span>
<span>{{t "order.fields.tracking"}}</span>
<span>{{group.waypoint.tracking}}</span>
</ClickToCopy>
<Badge @status={{group.waypoint.status_code}} />
Expand Down
2 changes: 1 addition & 1 deletion addon/components/display-place.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
<div class="px-1">
<div class="text-sm flex flex-row items-center px-3 py-1 rounded-md my-1 text-gray-300">
{{t "fleet-ops.operations.orders.index.view.waypoint-actions"}}
{{t "order.fields.waypoint-actions"}}
</div>
</div>
<div class="next-dd-menu-seperator"></div>
Expand Down
33 changes: 16 additions & 17 deletions addon/components/driver/pill.hbs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
{{#let (or @driver @resource) as |resource|}}
<Pill
@resource={{resource}}
@imageSrc={{avatar-url resource.photo_url}}
@subtitle={{n-a resource.phone "No Phone"}}
@fallbackImageType="driverImage"
@showOnlineIndicator={{true}}
@onClick={{@onClick}}
@anchorClass={{@anchorClass}}
@imageClass={{@imageClass}}
@imageWrapperClass={{@imageWrapperClass}}
@contentWrapperClass={{@contentWrapperClass}}
@titleClass={{@titleClass}}
@subtitleClass={{@subtitleClass}}
...attributes
/>
{{/let}}
<Pill
@resource={{this.resource}}
@imageSrc={{avatar-url this.resource.photo_url}}
@titleFallback={{or @titleFallback "No driver"}}
@subtitle={{n-a this.resource.phone (if this.resource "No phone" "-")}}
@fallbackImageType="driverImage"
@showOnlineIndicator={{if this.resource true false}}
@onClick={{@onClick}}
@anchorClass={{@anchorClass}}
@imageClass={{@imageClass}}
@imageWrapperClass={{@imageWrapperClass}}
@contentWrapperClass={{@contentWrapperClass}}
@titleClass={{@titleClass}}
@subtitleClass={{@subtitleClass}}
...attributes
/>
6 changes: 5 additions & 1 deletion addon/components/driver/pill.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import Component from '@glimmer/component';

export default class DriverPillComponent extends Component {}
export default class DriverPillComponent extends Component {
get resource() {
return this.args.driver ?? this.args.resource;
}
}
38 changes: 35 additions & 3 deletions addon/components/map/leaflet-live-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export default class MapLeafletLiveMapComponent extends Component {
this.#createMapContextMenu(map);
this.trigger('onLoad', ...arguments);
this.load.perform();

// Listen for map move/zoom events to trigger viewport-based resource reload
map.on('moveend', () => this.reloadResourcesInViewport.perform());
map.on('zoomend', () => this.reloadResourcesInViewport.perform());
}

@action trigger(name, ...rest) {
Expand Down Expand Up @@ -160,11 +164,19 @@ export default class MapLeafletLiveMapComponent extends Component {
/** load resources and wait for stuff here and trigger map ready **/
@task *load() {
try {
// Get initial map bounds for spatial filtering
const bounds = this.map ? this.map.getBounds() : null;
const params = bounds
? {
bounds: [bounds.getSouth(), bounds.getWest(), bounds.getNorth(), bounds.getEast()],
}
: {};

const data = yield all([
this.loadResource.perform('routes'),
this.loadResource.perform('vehicles'),
this.loadResource.perform('drivers'),
this.loadResource.perform('places'),
this.loadResource.perform('vehicles', { params }),
this.loadResource.perform('drivers', { params }),
this.loadResource.perform('places', { params }),
this.loadResource.perform('service-areas'),
]);

Expand All @@ -176,6 +188,26 @@ export default class MapLeafletLiveMapComponent extends Component {
}
}

@task({ restartable: true }) *reloadResourcesInViewport() {
if (!this.map) {
return;
}

// Get current map bounds
const bounds = this.map.getBounds();
const params = {
bounds: [bounds.getSouth(), bounds.getWest(), bounds.getNorth(), bounds.getEast()],
};

// Reload spatially-filtered resources (drivers, vehicles, places)
// Orders, routes, and service-areas are not spatially filtered
try {
yield all([this.loadResource.perform('vehicles', { params }), this.loadResource.perform('drivers', { params }), this.loadResource.perform('places', { params })]);
} catch (err) {
debug('Failed to reload resources in viewport: ' + err.message);
}
}

@task *loadResource(path, options = {}) {
if (this.abilities.cannot(`fleet-ops list ${path}`)) return [];

Expand Down
1 change: 1 addition & 0 deletions addon/components/map/order-list-overlay/order.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{{on "dblclick" (fn this.onDoubleClick @order)}}
{{on "mouseenter" (fn this.onMouseEnter @order)}}
{{on "mouseleave" (fn this.onMouseLeave @order)}}
{{did-insert this.setupIntersectionObserver}}
...attributes
>
<div class="order-listing-row">
Expand Down
42 changes: 42 additions & 0 deletions addon/components/map/order-list-overlay/order.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class MapOrderListOverlayOrderComponent extends Component {
@tracked trackerDataLoaded = false;
observer = null;
@action onClick(order, event) {
//Don't run callback if action button is clicked
if (event.target.closest('span.order-listing-action-button')) {
Expand Down Expand Up @@ -32,4 +35,43 @@ export default class MapOrderListOverlayOrderComponent extends Component {
this.args.onMouseLeave(...arguments);
}
}

@action setupIntersectionObserver(element) {
// Create IntersectionObserver to detect when order becomes visible
this.observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !this.trackerDataLoaded) {
this.loadTrackerData();
}
});
},
{
root: null, // viewport
rootMargin: '50px', // start loading slightly before visible
threshold: 0.1, // trigger when 10% visible
}
);

this.observer.observe(element);
}

loadTrackerData() {
const { order } = this.args;

if (order && typeof order.loadTrackerData === 'function' && !this.trackerDataLoaded) {
this.trackerDataLoaded = true;
order.loadTrackerData();
}
}

willDestroy() {
super.willDestroy(...arguments);

// Clean up observer
if (this.observer) {
this.observer.disconnect();
this.observer = null;
}
}
}
4 changes: 2 additions & 2 deletions addon/components/modals/bulk-assign-driver.hbs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Modals::BulkActionModel @options={{@options}} @onConfirm={{@onConfirm}} @onDecline={{@onDecline}} as |options|>
<div>
<InputGroup @name={{t "common.select-driver"}} @helpText={{t "fleet-ops.operations.orders.index.bulk-assign-driver-helptext"}}>
<InputGroup @name={{t "common.select-field" field=(t "resource.driver")}} @helpText={{t "fleet-ops.operations.orders.index.bulk-assign-driver-helptext"}}>
<ModelSelect
@modelName="driver"
@selectedModel={{options.driverAssigned}}
@query={{options.driversQuery}}
@placeholder={{t "fleet-ops.operations.orders.index.new.assign-driver-placeholder"}}
@placeholder={{t "order.fields.assign-driver-placeholder"}}
@triggerClass="form-select form-input"
@infiniteScroll={{false}}
@renderInPlace={{true}}
Expand Down
2 changes: 1 addition & 1 deletion addon/components/order-tracking-lookup.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
</div>
{{else}}
<div class="px-10 py-2 flex items-center justify-center">
<p class="text-red-600 dark:text-red-100">{{t "fleet-ops.operations.orders.index.view.no-order-activity"}}</p>
<p class="text-red-600 dark:text-red-100">{{t "order.fields.no-order-activity"}}</p>
</div>
{{/each}}
</div>
Expand Down
12 changes: 6 additions & 6 deletions addon/components/order/details/detail.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
<span>{{t "order.fields.driver-assigned"}}</span>
</div>
<div class="field-value">
<Driver::Pill @driver={{@resource.driver_assigned}} @onClick={{this.focusOrderAssignedDriver}} />
<Driver::Pill @driver={{@resource.driver_assigned}} @onClick={{this.focusOrderAssignedDriver}} @titleFallback="No driver assigned" @titleClass={{unless @resource.driver_assigned "text-gray-300"}} />
</div>
</div>
<div class="field-info-container">
<div class="field-name flex flex-row items-center justify-between">
<span>{{t "order.fields.vehicle-assigned"}}</span>
</div>
<div class="field-value">
<Vehicle::Pill @vehicle={{@resource.vehicle_assigned}} />
<Vehicle::Pill @vehicle={{@resource.vehicle_assigned}} @titleFallback="No vehicle assigned" @titleClass={{unless @resource.vehicle_assigned "text-gray-300"}} />
</div>
</div>
<div class="field-info-container">
Expand All @@ -48,8 +48,8 @@
/>
</div>
<div>
<div class="text-sm">{{n-a @resource.customer.name "No Customer"}}</div>
<div class="text-xs text-gray-400 dark:text-gray-500">{{n-a @resource.customer.phone "No Phone"}}</div>
<div class="text-sm {{unless @resource.customer 'text-gray-300'}}">{{n-a @resource.customer.name "No customer"}}</div>
<div class="text-xs text-gray-400 dark:text-gray-500">{{n-a @resource.customer.phone "No phone"}}</div>
</div>
</div>
</div>
Expand All @@ -70,8 +70,8 @@
/>
</div>
<div>
<div class="text-sm">{{n-a @resource.facilitator.name "No Facilitator"}}</div>
<div class="text-xs text-gray-400 dark:text-gray-500">{{n-a @resource.facilitator.phone "No Phone"}}</div>
<div class="text-sm {{unless @resource.facilitator 'text-gray-300'}}">{{n-a @resource.facilitator.name "No facilitator"}}</div>
<div class="text-xs text-gray-400 dark:text-gray-500">{{n-a @resource.facilitator.phone "No phone"}}</div>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion addon/components/order/details/notes.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default class OrderDetailsNotesComponent extends Component {
@task *save() {
try {
yield this.args.resource.persistProperty('notes', this.args.resource.notes);
this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.view.order-notes-updated'));
this.notifications.success(this.intl.t('order.fields.order-notes-updated'));
this.isEditing = false;
} catch (error) {
this.notifications.serverError(error);
Expand Down
6 changes: 3 additions & 3 deletions addon/components/order/route-editor.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
<Button
@type="magic"
@icon="magic"
@text={{t "fleet-ops.operations.orders.index.new.optimize-route"}}
@text={{t "order.fields.optimize-route"}}
@size="sm"
@onClick={{perform this.optimizeRoute}}
@permission="fleet-ops optimize order"
@helpText={{t "fleet-ops.operations.orders.index.new.optimize-route-help-text"}}
@helpText={{t "order.fields.optimize-route-help-text"}}
@disabled={{lt @resource.payload.waypoints.length 3}}
@isLoading={{this.optimizeRoute.isRunning}}
/>
Expand Down Expand Up @@ -46,7 +46,7 @@
<ModelSelect
@modelName="place"
@selectedModel={{waypoint}}
@placeholder={{concat (t "fleet-ops.operations.orders.index.new.select-waypoint-placeholder") " " (add index 1)}}
@placeholder={{concat (t "order.fields.select-waypoint") " " (add index 1)}}
@triggerClass="form-select form-input truncate max-w-300px"
@infiniteScroll={{false}}
@customSearchEndpoint="places/search"
Expand Down
Loading
Loading