Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 23 additions & 1 deletion addon/routes/operations.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class OperationsRoute extends Route {}
export default class OperationsRoute extends Route {
@service('universe/menu-service') menuService;
@service universe;

beforeModel(transition) {
if (transition.intent && transition.intent.url) {
// Here we will check if it's an actual virtual route instead of operations
const intendedUrl = transition.intent.url;
const intentSegments = intendedUrl.split('/');
// Needs to match for section and slug
const section = intentSegments[2];
const slug = intentSegments[3];
// This is not a operations route check menu service for a virtual registration match
if (section !== 'operations') {
const menuItem = this.menuService.lookupMenuItem('engine:fleet-ops', slug, null, section);
if (menuItem) {
return this.universe.transitionMenuItem('console.fleet-ops.virtual', menuItem);
}
}
}
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/fleetops-api",
"version": "0.6.40",
"version": "0.6.41",
"description": "Fleet & Transport Management Extension for Fleetbase",
"keywords": [
"fleetbase-extension",
Expand Down
2 changes: 1 addition & 1 deletion extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fleet-Ops",
"version": "0.6.40",
"version": "0.6.41",
"description": "Fleet & Transport Management Extension for Fleetbase",
"repository": "https://github.com/fleetbase/fleetops",
"license": "AGPL-3.0-or-later",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/fleetops-engine",
"version": "0.6.40",
"version": "0.6.41",
"description": "Fleet & Transport Management Extension for Fleetbase",
"fleetbase": {
"route": "fleet-ops"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

/**
* Make `orchestrator_priority` nullable on the orders table.
*
* The original migration (2026_04_08_000003) added this column as NOT NULL
* with a database-level default of 50. When Eloquent explicitly passes NULL
* for the column (e.g. when a user submits the order form without filling in
* orchestrator constraints), the DB default is bypassed and MySQL raises:
*
* SQLSTATE[23000]: Integrity constraint violation: 1048
* Column 'orchestrator_priority' cannot be null
*
* This migration makes the column nullable so that existing installations
* that have already run the original migration are also protected. The
* application layer (Order model + controllers) already coerces null to 50,
* so NULL values will not appear in practice; the nullable flag is a
* belt-and-suspenders safety net for any code path that may have been missed.
*/
return new class extends Migration {
public function up(): void
{
Schema::table('orders', function (Blueprint $table) {
$table->unsignedTinyInteger('orchestrator_priority')->default(50)->nullable()->change();
});
}

public function down(): void
{
// First back-fill any NULLs so the NOT NULL constraint can be restored.
\Illuminate\Support\Facades\DB::table('orders')
->whereNull('orchestrator_priority')
->update(['orchestrator_priority' => 50]);

Schema::table('orders', function (Blueprint $table) {
$table->unsignedTinyInteger('orchestrator_priority')->default(50)->nullable(false)->change();
});
}
};
12 changes: 12 additions & 0 deletions server/src/Http/Controllers/Api/v1/OrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ public function create(CreateOrderRequest $request)
$input['adhoc'] = Utils::isTrue($input['adhoc']) ? 1 : 0;
}

// Ensure orchestrator_priority is never null — the column is NOT NULL
// and the DB default is bypassed when Eloquent receives an explicit null.
if (!isset($input['orchestrator_priority']) || !is_numeric($input['orchestrator_priority'])) {
$input['orchestrator_priority'] = 50;
}

if (!isset($input['payload_uuid'])) {
return response()->apiError('Attempted to attach invalid payload to order.');
}
Expand Down Expand Up @@ -527,6 +533,12 @@ public function update($id, UpdateOrderRequest $request)
$order->dispatch();
}

// Ensure orchestrator_priority is never null on update either —
// only apply the default when the key was explicitly sent as null/empty.
if (array_key_exists('orchestrator_priority', $input) && !is_numeric($input['orchestrator_priority'])) {
$input['orchestrator_priority'] = 50;
}

// update the order
$order->update($input);
$order->flushAttributesCache();
Expand Down
6 changes: 6 additions & 0 deletions server/src/Http/Controllers/Internal/v1/OrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ function ($request, &$input) {
$input['order_config_uuid'] = $defaultOrderConfig->uuid;
}
}

// Ensure orchestrator_priority is never null — the column is NOT NULL
// and the DB default is bypassed when Eloquent receives an explicit null.
if (!isset($input['orchestrator_priority']) || !is_numeric($input['orchestrator_priority'])) {
$input['orchestrator_priority'] = 50;
}
},
function (&$request, Order &$order, &$requestInput) {
$input = $request->input('order');
Expand Down
26 changes: 26 additions & 0 deletions server/src/Models/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ class Order extends Model
'orchestrator_priority' => 'integer',
];

/**
* The model's default attribute values.
*
* Ensures that `orchestrator_priority` is never persisted as NULL even when
* the caller omits the field entirely (e.g. the order/form component does
* not require the user to fill in orchestrator constraints). The value
* mirrors the database column default defined in the migration.
*
* @var array<string, mixed>
*/
protected $attributes = [
'orchestrator_priority' => 50,
];

/**
* The attributes excluded from the model's JSON form.
*
Expand Down Expand Up @@ -619,6 +633,18 @@ public function getUpdatedByNameAttribute()
return data_get($this, 'updatedBy.name');
}

/**
* Set the orchestrator_priority attribute.
*
* Coerces null or non-numeric values to the default priority of 50 so that
* the NOT NULL database constraint is never violated when a user submits
* the order form without filling in the orchestrator constraints section.
*/
public function setOrchestratorPriorityAttribute($value): void
{
$this->attributes['orchestrator_priority'] = is_numeric($value) ? (int) $value : 50;
}

/**
* Set the order type attribute, which defaults to `default`.
*/
Expand Down
Loading