diff --git a/addon/components/customer/form.js b/addon/components/customer/form.js
index dae725b30..553adcc41 100644
--- a/addon/components/customer/form.js
+++ b/addon/components/customer/form.js
@@ -11,12 +11,17 @@ export default class CustomerFormComponent extends Component {
@service currentUser;
@service notifications;
@service modalsManager;
+ @service('universe/extension-manager') extensionManager;
+
@tracked userAccountActionButtons = [
{
icon: 'user-plus',
size: 'xs',
permission: 'iam create user',
- onClick: () => {
+ onClick: async () => {
+ // Load IAM engine for user-form modal component
+ await this.extensionManager.ensureEngineLoaded('@fleetbase/iam-engine');
+
const user = this.store.createRecord('user', {
status: 'pending',
type: 'user',
diff --git a/addon/components/service-rate/details.hbs b/addon/components/service-rate/details.hbs
index 4eac38637..f141841cd 100644
--- a/addon/components/service-rate/details.hbs
+++ b/addon/components/service-rate/details.hbs
@@ -199,7 +199,7 @@
Algorithm Code
-
{{n-a @resource.algorithm}}
+
{{n-a @resource.algorithm}}
diff --git a/addon/components/service-rate/form.hbs b/addon/components/service-rate/form.hbs
index d949f55f1..96521689e 100644
--- a/addon/components/service-rate/form.hbs
+++ b/addon/components/service-rate/form.hbs
@@ -10,7 +10,7 @@
@disabled={{cannot-write @resource}}
/>
-
+
this.hostRouter.transitionTo('console.fleet-ops.management.contacts.customers.edit', this.model),
- },
- ];
+ @service intl;
+
+ get tabs() {
+ const registeredTabs = this.menuService.getMenuItems('fleet-ops:component:customer:details');
+ return [
+ {
+ route: 'management.contacts.index.details.index',
+ label: 'Overview',
+ },
+ ...(isArray(registeredTabs) ? registeredTabs : []),
+ ];
+ }
+
+ get actionButtons() {
+ return [
+ {
+ icon: 'pencil',
+ fn: () => this.hostRouter.transitionTo('console.fleet-ops.management.contacts.customers.edit', this.model),
+ },
+ ];
+ }
}
diff --git a/addon/controllers/management/contacts/index/details.js b/addon/controllers/management/contacts/index/details.js
index 0c6f529e5..1301937cd 100644
--- a/addon/controllers/management/contacts/index/details.js
+++ b/addon/controllers/management/contacts/index/details.js
@@ -1,19 +1,29 @@
import Controller from '@ember/controller';
-import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
+import { isArray } from '@ember/array';
export default class ManagementContactsIndexDetailsController extends Controller {
+ @service('universe/menu-service') menuService;
@service hostRouter;
- @tracked tabs = [
- {
- route: 'management.contacts.index.details.index',
- label: 'Overview',
- },
- ];
- @tracked actionButtons = [
- {
- icon: 'pencil',
- fn: () => this.hostRouter.transitionTo('console.fleet-ops.management.contacts.index.edit', this.model),
- },
- ];
+ @service intl;
+
+ get tabs() {
+ const registeredTabs = this.menuService.getMenuItems('fleet-ops:component:contact:details');
+ return [
+ {
+ route: 'management.contacts.index.details.index',
+ label: 'Overview',
+ },
+ ...(isArray(registeredTabs) ? registeredTabs : []),
+ ];
+ }
+
+ get actionButtons() {
+ return [
+ {
+ icon: 'pencil',
+ fn: () => this.hostRouter.transitionTo('console.fleet-ops.management.contacts.index.edit', this.model),
+ },
+ ];
+ }
}
diff --git a/addon/templates/operations/service-rates/index/edit.hbs b/addon/templates/operations/service-rates/index/edit.hbs
index 6bfbb6bc8..125580f7c 100644
--- a/addon/templates/operations/service-rates/index/edit.hbs
+++ b/addon/templates/operations/service-rates/index/edit.hbs
@@ -6,6 +6,7 @@
@saveTask={{this.save}}
@onPressCancel={{this.cancel}}
@onOverlayReady={{fn (mut this.overlay)}}
+ @maxResizeWidth={{1000}}
>
diff --git a/addon/templates/operations/service-rates/index/new.hbs b/addon/templates/operations/service-rates/index/new.hbs
index d0c4f9943..96163d0cc 100644
--- a/addon/templates/operations/service-rates/index/new.hbs
+++ b/addon/templates/operations/service-rates/index/new.hbs
@@ -6,6 +6,7 @@
@saveTask={{this.save}}
@onPressCancel={{transition-to "operations.service-rates.index"}}
@onOverlayReady={{fn (mut this.overlay)}}
+ @maxResizeWidth={{1000}}
>
diff --git a/server/src/Models/ServiceArea.php b/server/src/Models/ServiceArea.php
index 91ed31d32..e13ce04cc 100644
--- a/server/src/Models/ServiceArea.php
+++ b/server/src/Models/ServiceArea.php
@@ -123,7 +123,7 @@ class ServiceArea extends Model
*/
public function zones()
{
- return $this->hasMany(Zone::class)->without(['serviceArea']);
+ return $this->hasMany(Zone::class, 'service_area_uuid', 'uuid')->without(['serviceArea']);
}
/**
diff --git a/server/src/Models/Zone.php b/server/src/Models/Zone.php
index 046d601d1..951fcf726 100644
--- a/server/src/Models/Zone.php
+++ b/server/src/Models/Zone.php
@@ -118,7 +118,7 @@ public static function boot()
*/
public function serviceArea()
{
- return $this->belongsTo(ServiceArea::class);
+ return $this->belongsTo(ServiceArea::class, 'service_area_uuid', 'uuid');
}
/**
diff --git a/server/tests/ServiceAreaZoneApiShapeTest.php b/server/tests/ServiceAreaZoneApiShapeTest.php
index 0a24e5ed6..d4cd773dc 100644
--- a/server/tests/ServiceAreaZoneApiShapeTest.php
+++ b/server/tests/ServiceAreaZoneApiShapeTest.php
@@ -1,5 +1,8 @@
toContain("'public_id' => \$request->input('service_area')")
->not->toContain("->orWhere('uuid'");
});
+
+test('service area zones relationship uses the stored service area uuid foreign key', function () {
+ $relation = (new ServiceArea())->zones();
+
+ expect($relation->getForeignKeyName())->toBe('service_area_uuid')
+ ->and($relation->getLocalKeyName())->toBe('uuid');
+});
+
+test('zone service area relationship uses the stored service area uuid foreign key', function () {
+ $relation = (new Zone())->serviceArea();
+
+ expect($relation->getForeignKeyName())->toBe('service_area_uuid')
+ ->and($relation->getOwnerKeyName())->toBe('uuid');
+});
diff --git a/tests/unit/components/service-rate/form-test.js b/tests/unit/components/service-rate/form-test.js
new file mode 100644
index 000000000..07ee0e43e
--- /dev/null
+++ b/tests/unit/components/service-rate/form-test.js
@@ -0,0 +1,124 @@
+import { module, test } from 'qunit';
+import ServiceRateFormComponent from 'dummy/components/service-rate/form';
+
+function makeRule(initial = {}) {
+ return {
+ ...initial,
+ set(key, value) {
+ this[key] = value;
+ },
+ };
+}
+
+module('Unit | Component | service-rate/form', function () {
+ test('selecting zone keeps the geography type before a zone is selected', function (assert) {
+ const rule = makeRule({
+ zone: { id: 'zone_1' },
+ zone_uuid: 'zone_1',
+ service_area: { id: 'service_area_1' },
+ service_area_uuid: 'service_area_1',
+ is_fallback: true,
+ });
+
+ ServiceRateFormComponent.prototype.selectRuleGeographyType(rule, { value: 'zone' });
+
+ assert.strictEqual(rule.selected_geography_type, 'zone');
+ assert.strictEqual(rule.zone, null);
+ assert.strictEqual(rule.zone_uuid, null);
+ assert.strictEqual(rule.service_area, null);
+ assert.strictEqual(rule.service_area_uuid, null);
+ assert.false(rule.is_fallback);
+ });
+
+ test('selecting service area keeps the geography type and clears incompatible values', function (assert) {
+ const rule = makeRule({
+ zone: { id: 'zone_1' },
+ zone_uuid: 'zone_1',
+ is_fallback: true,
+ });
+
+ ServiceRateFormComponent.prototype.selectRuleGeographyType(rule, { value: 'service_area' });
+
+ assert.strictEqual(rule.selected_geography_type, 'service_area');
+ assert.strictEqual(rule.zone, null);
+ assert.strictEqual(rule.zone_uuid, null);
+ assert.strictEqual(rule.service_area, null);
+ assert.strictEqual(rule.service_area_uuid, null);
+ assert.false(rule.is_fallback);
+ });
+
+ test('selecting fallback keeps fallback mode and clears geography values', function (assert) {
+ const rule = makeRule({
+ zone: { id: 'zone_1' },
+ zone_uuid: 'zone_1',
+ service_area: { id: 'service_area_1' },
+ service_area_uuid: 'service_area_1',
+ is_fallback: false,
+ });
+
+ ServiceRateFormComponent.prototype.selectRuleGeographyType(rule, { value: 'fallback' });
+
+ assert.strictEqual(rule.selected_geography_type, 'fallback');
+ assert.strictEqual(rule.zone, null);
+ assert.strictEqual(rule.zone_uuid, null);
+ assert.strictEqual(rule.service_area, null);
+ assert.strictEqual(rule.service_area_uuid, null);
+ assert.true(rule.is_fallback);
+ });
+
+ test('selecting a zone sets zone geography and clears service area values', function (assert) {
+ const zone = { id: 'zone_1' };
+ const rule = makeRule({
+ service_area: { id: 'service_area_1' },
+ service_area_uuid: 'service_area_1',
+ is_fallback: true,
+ });
+
+ ServiceRateFormComponent.prototype.selectRuleZone(rule, zone);
+
+ assert.strictEqual(rule.selected_geography_type, 'zone');
+ assert.strictEqual(rule.zone, zone);
+ assert.strictEqual(rule.zone_uuid, 'zone_1');
+ assert.strictEqual(rule.service_area, null);
+ assert.strictEqual(rule.service_area_uuid, null);
+ assert.false(rule.is_fallback);
+ });
+
+ test('selecting a service area sets service area geography and clears zone values', function (assert) {
+ const serviceArea = { id: 'service_area_1' };
+ const rule = makeRule({
+ zone: { id: 'zone_1' },
+ zone_uuid: 'zone_1',
+ is_fallback: true,
+ });
+
+ ServiceRateFormComponent.prototype.selectRuleServiceArea(rule, serviceArea);
+
+ assert.strictEqual(rule.selected_geography_type, 'service_area');
+ assert.strictEqual(rule.service_area, serviceArea);
+ assert.strictEqual(rule.service_area_uuid, 'service_area_1');
+ assert.strictEqual(rule.zone, null);
+ assert.strictEqual(rule.zone_uuid, null);
+ assert.false(rule.is_fallback);
+ });
+
+ test('setRuleFallback stores fallback mode and clears geography values', function (assert) {
+ const rule = makeRule({
+ selected_geography_type: 'zone',
+ zone: { id: 'zone_1' },
+ zone_uuid: 'zone_1',
+ service_area: { id: 'service_area_1' },
+ service_area_uuid: 'service_area_1',
+ is_fallback: false,
+ });
+
+ ServiceRateFormComponent.prototype.setRuleFallback(rule, true);
+
+ assert.strictEqual(rule.selected_geography_type, 'fallback');
+ assert.strictEqual(rule.zone, null);
+ assert.strictEqual(rule.zone_uuid, null);
+ assert.strictEqual(rule.service_area, null);
+ assert.strictEqual(rule.service_area_uuid, null);
+ assert.true(rule.is_fallback);
+ });
+});