Merge remote-tracking branch 'upstream/main'

This commit is contained in:
lapin
2025-10-28 09:47:55 +01:00
16 changed files with 650 additions and 357 deletions

View File

@@ -1,13 +1,17 @@
# 🚀 Fleetbase v0.7.12 — 2025-10-22
# 🚀 Fleetbase v0.7.13 — 2025-10-28
> Patches
> Connectivity Module + Positions Playback + Positions & Device Events Drawer
---
## ✨ Highlights
- Improvements to Fleet-Ops orders Kanban view, filter by order type and search/filters working.
- Patches to food truck API.
- Patches to multiple waypoints API handling.
- Introduces the new Connectivity module in Fleet-Ops for managing telematics, devices, sensors with native support for Flespi, Geotab, and Samsara built in.
- Introduces Position replay for Vehicles
- Added new live map drawer tabs "Positions", and "Events" to view all trackable resources position data, as well as replay positions
- Improved the report query builder + fix drag sort on group by/aggregate fn and order by columns
- Patched entities by destination order view
- Improved movement tracker service to account for spead, improved bearing/heading for accurate playback and live tracking of assets
- Improved tracking endpoint for both vehicles and drivers
---

View File

@@ -20,8 +20,8 @@
"require": {
"php": "^8.0",
"appstract/laravel-opcache": "^4.0",
"fleetbase/core-api": "^1.6.19",
"fleetbase/fleetops-api": "^0.6.20",
"fleetbase/core-api": "^1.6.20",
"fleetbase/fleetops-api": "^0.6.21",
"fleetbase/registry-bridge": "^0.1.0",
"fleetbase/storefront-api": "^0.4.3",
"guzzlehttp/guzzle": "^7.0.1",

26
api/composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f985446e2caaac2043fa2956abae1819",
"content-hash": "e7233912fa3ae9936f14283737e39794",
"packages": [
{
"name": "appstract/laravel-opcache",
@@ -2158,16 +2158,16 @@
},
{
"name": "fleetbase/core-api",
"version": "1.6.19",
"version": "1.6.20",
"source": {
"type": "git",
"url": "https://github.com/fleetbase/core-api.git",
"reference": "71c3273b6dcf93abe98eadb54707d2a59e190b7e"
"reference": "f5786609b581593945907a67f659a56bff8e0b93"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fleetbase/core-api/zipball/71c3273b6dcf93abe98eadb54707d2a59e190b7e",
"reference": "71c3273b6dcf93abe98eadb54707d2a59e190b7e",
"url": "https://api.github.com/repos/fleetbase/core-api/zipball/f5786609b581593945907a67f659a56bff8e0b93",
"reference": "f5786609b581593945907a67f659a56bff8e0b93",
"shasum": ""
},
"require": {
@@ -2252,9 +2252,9 @@
],
"support": {
"issues": "https://github.com/fleetbase/core-api/issues",
"source": "https://github.com/fleetbase/core-api/tree/v1.6.19"
"source": "https://github.com/fleetbase/core-api/tree/v1.6.20"
},
"time": "2025-10-22T03:35:41+00:00"
"time": "2025-10-27T21:04:58+00:00"
},
{
"name": "fleetbase/countries",
@@ -2323,16 +2323,16 @@
},
{
"name": "fleetbase/fleetops-api",
"version": "0.6.20",
"version": "0.6.21",
"source": {
"type": "git",
"url": "https://github.com/fleetbase/fleetops.git",
"reference": "f0bbf9cc6fa2e68dca73c95fb93cf7d2b3cdae9d"
"reference": "df585850698a8deaa69c77a965f8ab6de145493e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fleetbase/fleetops/zipball/f0bbf9cc6fa2e68dca73c95fb93cf7d2b3cdae9d",
"reference": "f0bbf9cc6fa2e68dca73c95fb93cf7d2b3cdae9d",
"url": "https://api.github.com/repos/fleetbase/fleetops/zipball/df585850698a8deaa69c77a965f8ab6de145493e",
"reference": "df585850698a8deaa69c77a965f8ab6de145493e",
"shasum": ""
},
"require": {
@@ -2407,9 +2407,9 @@
],
"support": {
"issues": "https://github.com/fleetbase/fleetops/issues",
"source": "https://github.com/fleetbase/fleetops/tree/v0.6.20"
"source": "https://github.com/fleetbase/fleetops/tree/v0.6.21"
},
"time": "2025-10-22T03:37:16+00:00"
"time": "2025-10-27T21:19:21+00:00"
},
{
"name": "fleetbase/laravel-mysql-spatial",

View File

@@ -17,9 +17,9 @@ export default class ConsoleController extends Controller {
@service intl;
@service universe;
@service abilities;
@service sidebar;
@tracked organizations = [];
@tracked sidebarContext;
@tracked sidebarToggleEnabled = true;
@tracked sidebarToggleState = {};
@tracked hiddenSidebarRoutes = ['console.home', 'console.notifications', 'console.virtual'];
@tracked menuItems = [];
@@ -42,17 +42,17 @@ export default class ConsoleController extends Controller {
// Hide the sidebar if the current route is in hiddenSidebarRoutes
if (shouldHideSidebar) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
return; // Exit early as no further action is required
}
// If the sidebar was manually closed and not on a hidden route, keep it closed
if (isSidebarManuallyClosed) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
} else {
// Otherwise, show the sidebar
this.sidebarContext.show();
this.sidebar.show();
}
// Ensure toggle is enabled unless on a hidden route
@@ -87,7 +87,7 @@ export default class ConsoleController extends Controller {
this.universe.trigger('sidebarContext.available', sidebarContext);
if (this.hiddenSidebarRoutes.includes(this.router.currentRouteName)) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
}
}

View File

@@ -13,7 +13,11 @@ export default class DashboardModel extends Model {
/** @attributes */
@attr('string') name;
@attr('string') extension;
@attr('boolean') is_default;
@attr('array') tags;
@attr('object') options;
@attr('object') meta;
/** @dates */
@attr('date') created_at;

View File

@@ -3,6 +3,7 @@ import { computed } from '@ember/object';
import { isArray } from '@ember/array';
import { getOwner } from '@ember/application';
import { isPresent, isEmpty } from '@ember/utils';
import { format, formatDistanceToNow } from 'date-fns';
export default class ReportModel extends Model {
/** @ids */
@@ -35,6 +36,10 @@ export default class ReportModel extends Model {
@attr('raw') meta;
@attr('string') status;
/** @dates */
@attr('date') created_at;
@attr('date') updated_at;
/** @relationships */
// @belongsTo('company') company;
// @belongsTo('user') createdBy;
@@ -54,8 +59,23 @@ export default class ReportModel extends Model {
}
/** @computed */
@computed('query_config.columns.length', 'query_config.table.name')
get hasValidConfig() {
@computed('updated_at') get updatedAgo() {
return formatDistanceToNow(this.updated_at);
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAgo() {
return formatDistanceToNow(this.created_at);
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('query_config.columns.length', 'query_config.table.name') get hasValidConfig() {
return (
isPresent(this.query_config) &&
isPresent(this.query_config.table) &&
@@ -65,23 +85,19 @@ export default class ReportModel extends Model {
);
}
@computed('query_config.table.name')
get tableName() {
@computed('query_config.table.name') get tableName() {
return this.query_config?.table?.name || '';
}
@computed('query_config.table.label', 'tableName')
get tableLabel() {
@computed('query_config.table.label', 'tableName') get tableLabel() {
return this.query_config?.table?.label || this.tableName;
}
@computed('query_config.columns.[]')
get selectedColumns() {
@computed('query_config.columns.[]') get selectedColumns() {
return this.query_config?.columns || [];
}
@computed('selectedColumns.[]', 'query_config.joins.[]')
get totalSelectedColumns() {
@computed('selectedColumns.[]', 'query_config.joins.[]') get totalSelectedColumns() {
let count = this.selectedColumns.length;
// Add columns from joins
@@ -96,13 +112,11 @@ export default class ReportModel extends Model {
return count;
}
@computed('query_config.joins.[]')
get hasJoins() {
@computed('query_config.joins.[]') get hasJoins() {
return isArray(this.query_config?.joins) && this.query_config.joins.length > 0;
}
@computed('hasJoins', 'query_config.joins.[]')
get joinedTables() {
@computed('hasJoins', 'query_config.joins.[]') get joinedTables() {
if (!this.hasJoins) {
return [];
}
@@ -115,13 +129,11 @@ export default class ReportModel extends Model {
}));
}
@computed('query_config.conditions.[]')
get hasConditions() {
@computed('query_config.conditions.[]') get hasConditions() {
return isArray(this.query_config?.conditions) && this.query_config.conditions.length > 0;
}
@computed('hasConditions', 'query_config.conditions.[]')
get conditionsCount() {
@computed('hasConditions', 'query_config.conditions.[]') get conditionsCount() {
if (!this.hasConditions) {
return 0;
}
@@ -129,23 +141,19 @@ export default class ReportModel extends Model {
return this.countConditionsRecursively(this.query_config.conditions);
}
@computed('query_config.groupBy.[]')
get hasGrouping() {
@computed('query_config.groupBy.[]') get hasGrouping() {
return isArray(this.query_config?.groupBy) && this.query_config.groupBy.length > 0;
}
@computed('query_config.sortBy.[]')
get hasSorting() {
@computed('query_config.sortBy.[]') get hasSorting() {
return isArray(this.query_config?.sortBy) && this.query_config.sortBy.length > 0;
}
@computed('query_config.limit')
get hasLimit() {
@computed('query_config.limit') get hasLimit() {
return isPresent(this.query_config?.limit) && this.query_config.limit > 0;
}
@computed('conditionsCount', 'hasGrouping', 'hasJoins', 'joinedTables.length', 'totalSelectedColumns')
get complexity() {
@computed('conditionsCount', 'hasGrouping', 'hasJoins', 'joinedTables.length', 'totalSelectedColumns') get complexity() {
let score = 0;
score += this.totalSelectedColumns;
@@ -162,8 +170,7 @@ export default class ReportModel extends Model {
}
}
@computed('complexity', 'totalSelectedColumns', 'joinedTables.length')
get estimatedPerformance() {
@computed('complexity', 'totalSelectedColumns', 'joinedTables.length') get estimatedPerformance() {
if (this.complexity === 'simple' && this.totalSelectedColumns <= 10) {
return 'fast';
} else if (this.complexity === 'moderate' && this.joinedTables.length <= 2) {
@@ -173,8 +180,7 @@ export default class ReportModel extends Model {
}
}
@computed('last_executed_at')
get lastExecutedDisplay() {
@computed('last_executed_at') get lastExecutedDisplay() {
if (!this.last_executed_at) {
return 'Never executed';
}
@@ -182,8 +188,7 @@ export default class ReportModel extends Model {
return this.last_executed_at.toLocaleDateString() + ' ' + this.last_executed_at.toLocaleTimeString();
}
@computed('average_execution_time')
get averageExecutionTimeDisplay() {
@computed('average_execution_time') get averageExecutionTimeDisplay() {
if (!this.average_execution_time) {
return 'N/A';
}
@@ -195,13 +200,11 @@ export default class ReportModel extends Model {
}
}
@computed('execution_count')
get executionCountDisplay() {
@computed('execution_count') get executionCountDisplay() {
return this.execution_count || 0;
}
@computed('last_result_count')
get lastResultCountDisplay() {
@computed('last_result_count') get lastResultCountDisplay() {
if (this.last_result_count === null || this.last_result_count === undefined) {
return 'N/A';
}
@@ -209,23 +212,19 @@ export default class ReportModel extends Model {
return this.last_result_count.toLocaleString();
}
@computed('export_formats.[]')
get availableExportFormats() {
@computed('export_formats.[]') get availableExportFormats() {
return this.export_formats || ['csv', 'excel', 'json'];
}
@computed('tags.[]')
get tagsList() {
@computed('tags.[]') get tagsList() {
return this.tags || [];
}
@computed('shared_with.[]')
get sharedWithList() {
@computed('shared_with.[]') get sharedWithList() {
return this.shared_with || [];
}
@computed('is_scheduled', 'next_scheduled_run', 'schedule_frequency', 'schedule_timezone')
get scheduleInfo() {
@computed('is_scheduled', 'next_scheduled_run', 'schedule_frequency', 'schedule_timezone') get scheduleInfo() {
if (!this.is_scheduled) {
return null;
}
@@ -237,8 +236,7 @@ export default class ReportModel extends Model {
};
}
@computed('hasConditions', 'query_config.conditions.[]')
get conditionsSummary() {
@computed('hasConditions', 'query_config.conditions.[]') get conditionsSummary() {
if (!this.hasConditions) {
return [];
}
@@ -246,8 +244,7 @@ export default class ReportModel extends Model {
return this.extractConditionsSummary(this.query_config.conditions);
}
@computed('status')
get statusDisplay() {
@computed('status') get statusDisplay() {
const statusMap = {
draft: 'Draft',
active: 'Active',
@@ -258,8 +255,7 @@ export default class ReportModel extends Model {
return statusMap[this.status] || this.status;
}
@computed('status')
get statusClass() {
@computed('status') get statusClass() {
const statusClasses = {
draft: 'status-draft',
active: 'status-active',

View File

@@ -7,7 +7,7 @@
@userMenuItems={{this.userMenuItems}}
@onAction={{this.onAction}}
@showSidebarToggle={{true}}
@sidebarToggleEnabled={{this.sidebarToggleEnabled}}
@sidebarToggleEnabled={{true}}
@onSidebarToggle={{this.onSidebarToggle}}
/>
<Layout::Main class={{this.currentRouteClass}}>

View File

@@ -1,7 +1,7 @@
{{page-title "Dashboard"}}
<Layout::Section::Body class="overflow-y-scroll h-full">
<TwoFaEnforcementAlert />
<Dashboard @sidebar={{this.sidebarContext}} @createWrapperClass="px-10" class="flex items-center justify-between mb-4 mt-6 px-14" />
<Dashboard @extension="core" @createWrapperClass="px-10" class="flex items-center justify-between mb-4 mt-6 px-14" />
<Spacer @height="300px" />
</Layout::Section::Body>
<div id="console-home-wormhole" />

View File

@@ -49,7 +49,8 @@ module.exports = function (environment) {
defaultValues: {
categoryImage: getenv('DEFAULT_CATEGORY_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-1.png'),
placeholderImage: getenv('DEFAULT_PLACEHOLDER_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-2.png'),
placeholderImage: getenv('DEFAULT_PLACEHOLDER_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png'),
placeholderImageOld: getenv('DEFAULT_PLACEHOLDER_IMAGE_OLD', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-2.png'),
driverImage: getenv('DEFAULT_DRIVER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
userImage: getenv('DEFAULT_USER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
contactImage: getenv('DEFAULT_CONTACT_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),

View File

@@ -1,6 +1,6 @@
{
"name": "@fleetbase/console",
"version": "0.7.12",
"version": "0.7.13",
"private": true,
"description": "Modular logistics and supply chain operating system (LSOS)",
"repository": "https://github.com/fleetbase/fleetbase",
@@ -33,7 +33,7 @@
"@fleetbase/ember-core": "latest",
"@fleetbase/ember-ui": "latest",
"@fleetbase/fleetops-data": "latest",
"@fleetbase/fleetops-engine": "^0.6.20",
"@fleetbase/fleetops-engine": "^0.6.21",
"@fleetbase/iam-engine": "^0.1.4",
"@fleetbase/leaflet-routing-machine": "^3.2.17",
"@fleetbase/registry-bridge-engine": "^0.1.0",

832
console/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,7 @@ ENV QUEUE_CONNECTION=redis
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
ENV CONSOLE_PATH=/fleetbase/console
ENV OCTANE_SERVER=frankenphp
ENV FLEETBASE_VERSION=0.7.12
ENV FLEETBASE_VERSION=0.7.13
# Set environment
ARG ENVIRONMENT=production