@fleetbase/fleetops-engine 0.4.23 → 0.4.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/components/admin/navigator-app.hbs +0 -76
- package/addon/components/admin/navigator-app.js +0 -58
- package/addon/components/driver-onboard-settings.hbs +29 -0
- package/addon/components/driver-onboard-settings.js +75 -0
- package/addon/components/entity-field-editing-settings.hbs +79 -0
- package/addon/components/entity-field-editing-settings.js +106 -0
- package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +11 -0
- package/addon/components/layout/fleet-ops-sidebar.hbs +2 -3
- package/addon/components/layout/fleet-ops-sidebar.js +3 -0
- package/addon/routes/settings/navigator-app.js +3 -0
- package/addon/routes/settings.js +3 -0
- package/addon/routes.js +3 -0
- package/addon/styles/fleetops-engine.css +24 -0
- package/addon/templates/settings/navigator-app.hbs +11 -0
- package/addon/templates/settings.hbs +1 -0
- package/app/components/driver-onboard-settings.js +1 -0
- package/app/components/entity-field-editing-settings.js +1 -0
- package/app/routes/settings/navigator-app.js +1 -0
- package/app/routes/settings.js +1 -0
- package/app/templates/settings/navigator-app.js +1 -0
- package/app/templates/settings.js +1 -0
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +2 -2
- package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -1
- package/server/src/Http/Controllers/Api/v1/DriverController.php +8 -2
- package/server/src/Http/Controllers/Api/v1/NavigatorController.php +35 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/OrganizationController.php +23 -5
- package/server/src/Http/Controllers/FleetOpsController.php +0 -1
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +8 -4
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +8 -0
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +51 -5
- package/server/src/Http/Requests/CreateContactRequest.php +1 -1
- package/server/src/Http/Requests/CreateEntityRequest.php +1 -1
- package/server/src/Http/Requests/CreateIssueRequest.php +1 -1
- package/server/src/Http/Requests/CreatePlaceRequest.php +1 -1
- package/server/src/Http/Requests/CreateVehicleRequest.php +1 -1
- package/server/src/Support/Utils.php +4 -4
- package/server/src/routes.php +7 -0
- package/translations/en-us.yaml +28 -3
|
@@ -5,80 +5,4 @@
|
|
|
5
5
|
<InputInfo>{{t "fleet-ops.component.admin.navigator-app.message" htmlSafe=true companyName=@app.name}}</InputInfo>
|
|
6
6
|
</Attach::Tooltip>
|
|
7
7
|
</InputGroup>
|
|
8
|
-
</ContentPanel>
|
|
9
|
-
|
|
10
|
-
<ContentPanel @title={{t "fleet-ops.component.admin.navigator-app.settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
11
|
-
<InputGroup>
|
|
12
|
-
<div class="flex items-center">
|
|
13
|
-
<Toggle @isToggled={{this.isEntityFieldsEditable}} @onToggle={{this.enableEditableEntityFields}} />
|
|
14
|
-
<div class="ml-2">{{t "fleet-ops.component.admin.navigator-app.select-input"}}</div>
|
|
15
|
-
</div>
|
|
16
|
-
</InputGroup>
|
|
17
|
-
{{#if this.isEntityFieldsEditable}}
|
|
18
|
-
<OrderConfigManager @onConfigChanged={{this.onConfigChanged}} as |Action Context|>
|
|
19
|
-
<div class="mt-2">
|
|
20
|
-
<InputGroup @name="Select order config" @helpText="Apply entity editing settings for an order config.">
|
|
21
|
-
<DropdownButton
|
|
22
|
-
class="order-config-select-button mr-2"
|
|
23
|
-
@disabled={{not Context.configs}}
|
|
24
|
-
@text={{if Context.currentConfig.name Context.currentConfig.name (t "fleet-ops.component.order-config-manager.select-order-config")}}
|
|
25
|
-
@textClass="text-sm mr-2"
|
|
26
|
-
@buttonClass="flex-row-reverse w-44 justify-between"
|
|
27
|
-
@icon="caret-down"
|
|
28
|
-
@iconClass="mr-0i"
|
|
29
|
-
@size="sm"
|
|
30
|
-
@iconPrefix="fas"
|
|
31
|
-
@triggerClass="hidden md:flex"
|
|
32
|
-
as |dd|
|
|
33
|
-
>
|
|
34
|
-
<div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
|
|
35
|
-
<div class="p-1">
|
|
36
|
-
{{#each Context.configs as |orderConfig|}}
|
|
37
|
-
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd Context.selectConfig orderConfig)}}>
|
|
38
|
-
<div class="flex-1 flex flex-row items-center">
|
|
39
|
-
<div class="w-6">
|
|
40
|
-
<FaIcon @icon="cogs" />
|
|
41
|
-
</div>
|
|
42
|
-
<span>{{orderConfig.name}}</span>
|
|
43
|
-
</div>
|
|
44
|
-
<div>
|
|
45
|
-
{{#if (eq Context.currentConfig.id orderConfig.id)}}
|
|
46
|
-
<FaIcon @icon="check" class="text-green-500" />
|
|
47
|
-
{{/if}}
|
|
48
|
-
</div>
|
|
49
|
-
</a>
|
|
50
|
-
{{/each}}
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</DropdownButton>
|
|
54
|
-
</InputGroup>
|
|
55
|
-
</div>
|
|
56
|
-
</OrderConfigManager>
|
|
57
|
-
{{#if this.selectedOrderConfig}}
|
|
58
|
-
<div class="bg-gray-400 border-gray-600 rounded-lg px-4 py-2 dark:bg-gray-700 dark:border-gray-800">
|
|
59
|
-
{{#let (get (get this.entityEditingSettings this.selectedOrderConfig.id) "editable_entity_fields") as |editableEntityFields|}}
|
|
60
|
-
{{#each this.entityFields as |entityField|}}
|
|
61
|
-
<div class="mt-1">
|
|
62
|
-
<Checkbox
|
|
63
|
-
@value={{includes entityField editableEntityFields}}
|
|
64
|
-
@label={{smart-humanize entityField}}
|
|
65
|
-
@onToggle={{fn this.toggleFieldEditable entityField}}
|
|
66
|
-
@helpText={{t "fleet-ops.component.admin.visibility-controls.checkbox-text"}}
|
|
67
|
-
/>
|
|
68
|
-
</div>
|
|
69
|
-
{{/each}}
|
|
70
|
-
{{/let}}
|
|
71
|
-
</div>
|
|
72
|
-
<div class="mt-3 flex items-center">
|
|
73
|
-
<Button
|
|
74
|
-
@type="primary"
|
|
75
|
-
@size="lg"
|
|
76
|
-
@icon="save"
|
|
77
|
-
@text={{t "fleet-ops.common.save-changes"}}
|
|
78
|
-
@onClick={{perform this.saveEntityEditingSettings}}
|
|
79
|
-
@isLoading={{not this.saveEntityEditingSettings.isIdle}}
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
{{/if}}
|
|
83
|
-
{{/if}}
|
|
84
8
|
</ContentPanel>
|
|
@@ -1,62 +1,15 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { inject as service } from '@ember/service';
|
|
4
|
-
import { action } from '@ember/object';
|
|
5
|
-
import { isArray } from '@ember/array';
|
|
6
4
|
import { task } from 'ember-concurrency-decorators';
|
|
7
5
|
|
|
8
6
|
export default class NavigatorAppControlsComponent extends Component {
|
|
9
7
|
@service fetch;
|
|
10
|
-
@tracked isLoading = false;
|
|
11
8
|
@tracked url;
|
|
12
|
-
@tracked selectedOrderConfig;
|
|
13
|
-
@tracked entityFields = ['name', 'description', 'sku', 'height', 'width', 'length', 'weight', 'declared_value', 'sale_price'];
|
|
14
|
-
@tracked entityEditingSettings = {};
|
|
15
|
-
@tracked isEntityFieldsEditable = false;
|
|
16
9
|
|
|
17
10
|
constructor() {
|
|
18
11
|
super(...arguments);
|
|
19
12
|
this.getAppLinkUrl.perform();
|
|
20
|
-
this.getEntityEditableSettings.perform();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@action enableEditableEntityFields(isEntityFieldsEditable) {
|
|
24
|
-
this.isEntityFieldsEditable = isEntityFieldsEditable;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@action onConfigChanged(orderConfig) {
|
|
28
|
-
this.selectedOrderConfig = orderConfig;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@action toggleFieldEditable(fieldName, isEditable) {
|
|
32
|
-
const editableFields = this.entityEditingSettings[this.selectedOrderConfig.id]?.editable_entity_fields;
|
|
33
|
-
if (isArray(editableFields)) {
|
|
34
|
-
if (isEditable) {
|
|
35
|
-
editableFields.pushObject(fieldName);
|
|
36
|
-
} else {
|
|
37
|
-
editableFields.removeObject(fieldName);
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
this.entityEditingSettings = {
|
|
41
|
-
...this.entityEditingSettings,
|
|
42
|
-
[this.selectedOrderConfig.id]: {
|
|
43
|
-
editable_entity_fields: [],
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
return this.toggleFieldEditable(...arguments);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
this.updateEditableEntityFieldsForOrderConfig(editableFields);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
updateEditableEntityFieldsForOrderConfig(editableFields = [], orderConfig = null) {
|
|
53
|
-
orderConfig = orderConfig === null ? this.selectedOrderConfig : orderConfig;
|
|
54
|
-
this.entityEditingSettings = {
|
|
55
|
-
...this.entityEditingSettings,
|
|
56
|
-
[orderConfig.id]: {
|
|
57
|
-
editable_entity_fields: editableFields,
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
13
|
}
|
|
61
14
|
|
|
62
15
|
@task *getAppLinkUrl() {
|
|
@@ -66,15 +19,4 @@ export default class NavigatorAppControlsComponent extends Component {
|
|
|
66
19
|
this.url = linkUrl;
|
|
67
20
|
}
|
|
68
21
|
}
|
|
69
|
-
|
|
70
|
-
@task *getEntityEditableSettings() {
|
|
71
|
-
const { entityEditingSettings, isEntityFieldsEditable } = yield this.fetch.get('fleet-ops/settings/entity-editing-settings');
|
|
72
|
-
this.entityEditingSettings = entityEditingSettings;
|
|
73
|
-
this.isEntityFieldsEditable = isEntityFieldsEditable;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@task *saveEntityEditingSettings() {
|
|
77
|
-
const { entityEditingSettings, isEntityFieldsEditable } = this;
|
|
78
|
-
yield this.fetch.post('fleet-ops/settings/entity-editing-settings', { entityEditingSettings, isEntityFieldsEditable });
|
|
79
|
-
}
|
|
80
22
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<ContentPanel @title={{t "fleet-ops.component.driver-onboard-settings.driver-onboard-settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800 mb-4">
|
|
2
|
+
{{#if this.driverOnboardSettingsLoaded}}
|
|
3
|
+
<InputGroup>
|
|
4
|
+
<div class="flex items-center">
|
|
5
|
+
<Toggle @isToggled={{this.driverOnboardSettings.enableDriverOnboardFromApp}} @onToggle={{this.enableDriverOnboard}} @label={{t "fleet-ops.component.driver-onboard-settings.enable-driver-onboard-from-app"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.enable-driver-onboard-from-app-help-text"}} />
|
|
6
|
+
</div>
|
|
7
|
+
</InputGroup>
|
|
8
|
+
{{#if this.driverOnboardSettings.enableDriverOnboardFromApp}}
|
|
9
|
+
<InputGroup @name={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method-help-text"}}>
|
|
10
|
+
<Select class="w-full flex-1" @value={{this.driverOnboardSettings.driverOnboardAppMethod}} @options={{this.driverOnboardMethods}} @placeholder={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method"}} @onSelect={{this.selectDriverOnboardMethod}} />
|
|
11
|
+
</InputGroup>
|
|
12
|
+
<InputGroup>
|
|
13
|
+
<div class="flex items-center">
|
|
14
|
+
<Toggle @isToggled={{this.driverOnboardSettings.driverMustProvideOnboardDocuments}} @onToggle={{this.enableDriverOnboardDocuments}} @label={{t "fleet-ops.component.driver-onboard-settings.require-driver-to-upload-onboard-documents"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.require-driver-to-upload-onboard-documents-help-text"}} />
|
|
15
|
+
</div>
|
|
16
|
+
</InputGroup>
|
|
17
|
+
{{#if this.driverOnboardSettings.driverMustProvideOnboardDocuments}}
|
|
18
|
+
<InputGroup>
|
|
19
|
+
<ArrayInput @data={{this.driverOnboardSettings.requiredOnboardDocuments}} @placeholder={{t "fleet-ops.component.driver-onboard-settings.enter-document-name"}} @onDataChanged={{this.onOnboardDocumentsChanged}} @addButtonText={{t "fleet-ops.component.driver-onboard-settings.add-onboard-document"}}>
|
|
20
|
+
<InputLabel @labelText={{t "fleet-ops.component.driver-onboard-settings.required-onboard-documents"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.required-onboard-documents-help-text"}} />
|
|
21
|
+
</ArrayInput>
|
|
22
|
+
</InputGroup>
|
|
23
|
+
{{/if}}
|
|
24
|
+
{{/if}}
|
|
25
|
+
<div class="mt-3 flex items-center mb-4">
|
|
26
|
+
<Button @type="primary" @size="lg" @icon="save" @text={{t "fleet-ops.common.save-changes"}} @onClick={{perform this.saveDriverOnboardSettings}} @isLoading={{not this.saveDriverOnboardSettings.isIdle}} />
|
|
27
|
+
</div>
|
|
28
|
+
{{/if}}
|
|
29
|
+
</ContentPanel>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { task } from 'ember-concurrency-decorators';
|
|
6
|
+
|
|
7
|
+
export default class DriverOnboardSettingsComponent extends Component {
|
|
8
|
+
@service fetch;
|
|
9
|
+
@service currentUser;
|
|
10
|
+
@tracked companyId;
|
|
11
|
+
@tracked driverOnboardSettingsLoaded = false;
|
|
12
|
+
@tracked driverOnboardSettings = {};
|
|
13
|
+
@tracked driverOnboardMethods = ['invite', 'button'];
|
|
14
|
+
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.companyId = this.currentUser.companyId;
|
|
18
|
+
this.getDriverOnboardSettings.perform();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@action enableDriverOnboard(enableDriverOnboardFromApp) {
|
|
22
|
+
this.updateDriverOnboardSettings({ enableDriverOnboardFromApp });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@action enableDriverOnboardDocuments(driverMustProvideOnboardDocuments) {
|
|
26
|
+
this.updateDriverOnboardSettings({ driverMustProvideOnboardDocuments });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@action selectDriverOnboardMethod(driverOnboardAppMethod) {
|
|
30
|
+
this.updateDriverOnboardSettings({ driverOnboardAppMethod });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@action onOnboardDocumentsChanged(requiredOnboardDocuments) {
|
|
34
|
+
requiredOnboardDocuments = requiredOnboardDocuments.filter((documentName) => typeof documentName === 'string');
|
|
35
|
+
this.updateDriverOnboardSettings({ requiredOnboardDocuments });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@task *saveDriverOnboardSettings() {
|
|
39
|
+
const { driverOnboardSettings } = this;
|
|
40
|
+
const driverOnboardSettingsResponse = yield this.fetch.post('fleet-ops/settings/driver-onboard-settings', { driverOnboardSettings });
|
|
41
|
+
if (driverOnboardSettings?.enableDriverOnboardFromApp == false) this.driverOnboardSettings = driverOnboardSettingsResponse?.driverOnboardSettings;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@task *getDriverOnboardSettings() {
|
|
45
|
+
const companyId = this.currentUser.companyId;
|
|
46
|
+
const { driverOnboardSettings } = yield this.fetch.get(`fleet-ops/settings/driver-onboard-settings/${companyId}`);
|
|
47
|
+
this.driverOnboardSettings = driverOnboardSettings;
|
|
48
|
+
|
|
49
|
+
if (this.companyDoesntHaveDriverOnboardSettings()) {
|
|
50
|
+
this.updateDriverOnboardSettings({
|
|
51
|
+
enableDriverOnboardFromApp: false,
|
|
52
|
+
driverOnboardAppMethod: 'invite',
|
|
53
|
+
driverMustProvideOnboardDocuments: false,
|
|
54
|
+
requiredOnboardDocuments: [],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.driverOnboardSettingsLoaded = true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
companyDoesntHaveDriverOnboardSettings() {
|
|
62
|
+
const companyId = this.driverOnboardSettings.companyId;
|
|
63
|
+
return companyId === undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
updateDriverOnboardSettings(props = {}) {
|
|
67
|
+
const companyId = this.currentUser.companyId;
|
|
68
|
+
const driverOnboardSettings = this.driverOnboardSettings ?? {};
|
|
69
|
+
this.driverOnboardSettings = {
|
|
70
|
+
companyId: companyId,
|
|
71
|
+
...driverOnboardSettings,
|
|
72
|
+
...props,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<ContentPanel @title={{t "fleet-ops.component.entity-field-editing-settings.entitiy-field-editing-settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800 mb-4">
|
|
2
|
+
<OrderConfigManager @onConfigChanged={{this.onConfigChanged}} as |Action Context|>
|
|
3
|
+
<div>
|
|
4
|
+
<InputGroup
|
|
5
|
+
@name={{t "fleet-ops.component.entity-field-editing-settings.select-order-config"}}
|
|
6
|
+
@helpText={{t "fleet-ops.component.entity-field-editing-settings.select-order-config-help-text"}}
|
|
7
|
+
>
|
|
8
|
+
<DropdownButton
|
|
9
|
+
class="order-config-select-button mr-2"
|
|
10
|
+
@disabled={{not Context.configs}}
|
|
11
|
+
@text={{if Context.currentConfig.name Context.currentConfig.name (t "fleet-ops.component.entity-field-editing-settings.select-order-config")}}
|
|
12
|
+
@textClass="text-sm mr-2"
|
|
13
|
+
@buttonClass="flex-row-reverse w-44 justify-between"
|
|
14
|
+
@icon="caret-down"
|
|
15
|
+
@iconClass="mr-0i"
|
|
16
|
+
@size="sm"
|
|
17
|
+
@iconPrefix="fas"
|
|
18
|
+
@triggerClass="hidden md:flex"
|
|
19
|
+
as |dd|
|
|
20
|
+
>
|
|
21
|
+
<div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
|
|
22
|
+
<div class="p-1">
|
|
23
|
+
{{#each Context.configs as |orderConfig|}}
|
|
24
|
+
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd Context.selectConfig orderConfig)}}>
|
|
25
|
+
<div class="flex-1 flex flex-row items-center">
|
|
26
|
+
<div class="w-6">
|
|
27
|
+
<FaIcon @icon="cogs" />
|
|
28
|
+
</div>
|
|
29
|
+
<span>{{orderConfig.name}}</span>
|
|
30
|
+
</div>
|
|
31
|
+
<div>
|
|
32
|
+
{{#if (eq Context.currentConfig.id orderConfig.id)}}
|
|
33
|
+
<FaIcon @icon="check" class="text-green-500" />
|
|
34
|
+
{{/if}}
|
|
35
|
+
</div>
|
|
36
|
+
</a>
|
|
37
|
+
{{/each}}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</DropdownButton>
|
|
41
|
+
</InputGroup>
|
|
42
|
+
</div>
|
|
43
|
+
</OrderConfigManager>
|
|
44
|
+
{{#if this.selectedOrderConfig}}
|
|
45
|
+
{{#let (get this.entityEditingSettings this.selectedOrderConfig.id) as |orderConfigEntityEditingSettings|}}
|
|
46
|
+
<InputGroup>
|
|
47
|
+
<div class="flex items-center">
|
|
48
|
+
<Toggle
|
|
49
|
+
@isToggled={{orderConfigEntityEditingSettings.is_editable}}
|
|
50
|
+
@onToggle={{this.enableEditableEntityFields}}
|
|
51
|
+
@label={{t "fleet-ops.component.entity-field-editing-settings.enable-driver-to-edit-entity-fields"}}
|
|
52
|
+
@helpText={{t "fleet-ops.component.entity-field-editing-settings.enable-driver-to-edit-entity-fields-help-text"}}
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
</InputGroup>
|
|
56
|
+
{{#if orderConfigEntityEditingSettings.is_editable}}
|
|
57
|
+
<div class="bg-gray-400 border-gray-600 rounded-lg px-4 py-2 dark:bg-gray-700 dark:border-gray-800">
|
|
58
|
+
{{#let (get (get this.entityEditingSettings this.selectedOrderConfig.id) "editable_entity_fields") as |editableEntityFields|}}
|
|
59
|
+
{{#each this.entityFields as |entityField|}}
|
|
60
|
+
<div class="mt-1">
|
|
61
|
+
<Checkbox @value={{includes entityField editableEntityFields}} @label={{smart-humanize entityField}} @onToggle={{fn this.toggleFieldEditable entityField}} />
|
|
62
|
+
</div>
|
|
63
|
+
{{/each}}
|
|
64
|
+
{{/let}}
|
|
65
|
+
</div>
|
|
66
|
+
{{/if}}
|
|
67
|
+
<div class="mt-4 flex items-center">
|
|
68
|
+
<Button
|
|
69
|
+
@type="primary"
|
|
70
|
+
@size="lg"
|
|
71
|
+
@icon="save"
|
|
72
|
+
@text={{t "fleet-ops.common.save-changes"}}
|
|
73
|
+
@onClick={{perform this.saveEntityEditingSettings}}
|
|
74
|
+
@isLoading={{not this.saveEntityEditingSettings.isIdle}}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
{{/let}}
|
|
78
|
+
{{/if}}
|
|
79
|
+
</ContentPanel>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { inject as service } from '@ember/service';
|
|
4
|
+
import { action } from '@ember/object';
|
|
5
|
+
import { isArray } from '@ember/array';
|
|
6
|
+
import { isNone } from '@ember/utils';
|
|
7
|
+
import { task } from 'ember-concurrency-decorators';
|
|
8
|
+
|
|
9
|
+
export default class EntityFieldEditingSettingsComponent extends Component {
|
|
10
|
+
@service notifications;
|
|
11
|
+
@service fetch;
|
|
12
|
+
@tracked selectedOrderConfig;
|
|
13
|
+
@tracked entityFields = ['name', 'description', 'sku', 'height', 'width', 'length', 'weight', 'declared_value', 'sale_price'];
|
|
14
|
+
@tracked entityEditingSettings = {};
|
|
15
|
+
@tracked settingsLoaded = false;
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
super(...arguments);
|
|
19
|
+
this.getEntityEditableSettings.perform();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@action onConfigChanged(orderConfig) {
|
|
23
|
+
if (!isNone(this.selectedOrderConfig) && this.orderConfigDoesntHaveSettings(orderConfig)) {
|
|
24
|
+
this.createSettingsForOrderConfig(orderConfig);
|
|
25
|
+
}
|
|
26
|
+
this.selectedOrderConfig = orderConfig;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@action enableEditableEntityFields(isEditable) {
|
|
30
|
+
const orderConfig = this.selectedOrderConfig;
|
|
31
|
+
if (orderConfig) {
|
|
32
|
+
if (this.orderConfigDoesntHaveSettings(orderConfig)) {
|
|
33
|
+
this.createSettingsForOrderConfig(orderConfig, isEditable);
|
|
34
|
+
} else {
|
|
35
|
+
const orderConfigSettings = this.entityEditingSettings[orderConfig.id] ?? {};
|
|
36
|
+
this.entityEditingSettings = {
|
|
37
|
+
...this.entityEditingSettings,
|
|
38
|
+
[orderConfig.id]: {
|
|
39
|
+
...orderConfigSettings,
|
|
40
|
+
is_editable: isEditable,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@action toggleFieldEditable(fieldName, isEditable) {
|
|
48
|
+
const editableFields = this.entityEditingSettings[this.selectedOrderConfig.id]?.editable_entity_fields;
|
|
49
|
+
if (isArray(editableFields)) {
|
|
50
|
+
if (isEditable) {
|
|
51
|
+
editableFields.pushObject(fieldName);
|
|
52
|
+
} else {
|
|
53
|
+
editableFields.removeObject(fieldName);
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
this.entityEditingSettings = {
|
|
57
|
+
...this.entityEditingSettings,
|
|
58
|
+
[this.selectedOrderConfig.id]: {
|
|
59
|
+
...this.entityEditingSettings[this.selectedOrderConfig.id],
|
|
60
|
+
editable_entity_fields: [],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return this.toggleFieldEditable(...arguments);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.updateEditableEntityFieldsForOrderConfig(editableFields);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@task *getEntityEditableSettings() {
|
|
70
|
+
const { entityEditingSettings } = yield this.fetch.get('fleet-ops/settings/entity-editing-settings');
|
|
71
|
+
this.entityEditingSettings = entityEditingSettings;
|
|
72
|
+
this.settingsLoaded = true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@task *saveEntityEditingSettings() {
|
|
76
|
+
const { entityEditingSettings } = this;
|
|
77
|
+
yield this.fetch.post('fleet-ops/settings/entity-editing-settings', { entityEditingSettings });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
orderConfigDoesntHaveSettings(orderConfig) {
|
|
81
|
+
return isNone(this.entityEditingSettings[orderConfig.id]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
createSettingsForOrderConfig(orderConfig, isEditable = false) {
|
|
85
|
+
if (this.orderConfigDoesntHaveSettings(orderConfig)) {
|
|
86
|
+
this.entityEditingSettings = {
|
|
87
|
+
...this.entityEditingSettings,
|
|
88
|
+
[orderConfig.id]: {
|
|
89
|
+
editable_entity_fields: [],
|
|
90
|
+
is_editable: isEditable,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
updateEditableEntityFieldsForOrderConfig(editableFields = [], orderConfig = null) {
|
|
97
|
+
orderConfig = orderConfig === null ? this.selectedOrderConfig : orderConfig;
|
|
98
|
+
this.entityEditingSettings = {
|
|
99
|
+
...this.entityEditingSettings,
|
|
100
|
+
[orderConfig.id]: {
|
|
101
|
+
...this.entityEditingSettings[orderConfig.id],
|
|
102
|
+
editable_entity_fields: editableFields,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing">
|
|
1
|
+
<Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing" @dropdownButton={{this.displayPanelDropdown}} @dropdownButtonActions={{this.panelDropdownButtonActions}} @dropdownButtonRenderInPlace={{false}} @dropdownHorizontalPosition="left" @dropdownButtonMenuLabel={{t "fleet-ops.component.layout.fleet-ops-sidebar.drivers"}}>
|
|
2
2
|
{{#each this.drivers as |driver|}}
|
|
3
3
|
<Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if driver.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onDriverClicked driver}} class="driver-nav-item" @dropdownButton={{true}} @dropdownButtonActions={{this.dropdownButtonActions}} @dropdownContext={{driver}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{false}} @dropdownButtonMenuLabel={{driver.name}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @dropdownHorizontalPosition="left" @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}}>{{driver.name}}</Layout::Sidebar::Item>
|
|
4
4
|
{{/each}}
|
|
@@ -18,6 +18,17 @@ export default class LayoutFleetOpsSidebarDriverListingComponent extends Compone
|
|
|
18
18
|
this.fetchDrivers.perform();
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
displayPanelDropdown = true;
|
|
22
|
+
panelDropdownButtonActions = [
|
|
23
|
+
{
|
|
24
|
+
label: 'Create new driver...',
|
|
25
|
+
onClick: () => {
|
|
26
|
+
const driver = this.store.createRecord('driver');
|
|
27
|
+
this.contextPanel.focus(driver, 'editing');
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
21
32
|
dropdownButtonActions = [
|
|
22
33
|
{
|
|
23
34
|
label: 'View driver details...',
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{{/if}}
|
|
10
10
|
{{/each}}
|
|
11
11
|
{{#each this.menuPanels as |menuPanel|}}
|
|
12
|
-
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
|
|
12
|
+
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}} @titleIcon={{menuPanel.icon}} @hideCaret={{menuPanel.hideCaret}} @toggleOnCaretOnly={{menuPanel.toggleOnCaretOnly}} @onClickPanelTitle={{menuPanel.onClickPanelTitle}} @wrapperClass={{menuPanel.wrapperClass}} @dropdownButton={{menuPanel.dropdownButton}} @dropdownButtonActions={{menuPanel.dropdownButtonActions}} @dropdownButtonRenderInPlace={{menuPanel.dropdownButtonRenderInPlace}} @dropdownHorizontalPosition={{menuPanel.dropdownHorizontalPosition}} @dropdownButtonMenuLabel={{menuPanel.dropdownButtonMenuLabel}}>
|
|
13
13
|
{{#each menuPanel.items as |menuItem|}}
|
|
14
14
|
{{#if menuItem.renderComponentInPlace}}
|
|
15
15
|
{{component menuItem.component menuItem=menuItem title=menuItem.title onClick=menuItem.onClick route=(concat this.routePrefix menuItem.route) icon=menuItem.icon rightSideComponent=menuItem.rightSideComponent rightSideComponentContext=menuItem.rightSideComponentContext rightSideStatus=menuItem.rightSideStatus rightSideStatusText=menuItem.rightSideStatusText hideRightSideStatusDot=menuItem.hideRightSideStatusDot rightSideStatusClass=menuItem.rightSideStatusClass disableRightSideStatusHumanize=menuItem.disableRightSideStatusHumanize dropdownButton=menuItem.dropdownButton dropdownButtonActions=menuItem.dropdownButtonActions dropdownButtonIcon=menuItem.dropdownButtonIcon dropdownButtonIconPrefix=menuItem.dropdownButtonIconPrefix dropdownButtonText=menuItem.dropdownButtonText dropdownButtonCalculatePosition=menuItem.dropdownButtonCalculatePosition dropdownButtonRenderInPlace=menuItem.dropdownButtonRenderInPlace dropdownButtonMenuLabel=menuItem.dropdownButtonMenuLabel dropdownButtonWrapperClass=menuItem.dropdownButtonWrapperClass dropdownButtonTriggerClass=menuItem.dropdownButtonTriggerClass registerDropdownButtonAPI=menuItem.registerDropdownButtonAPI}}
|
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
</Layout::Sidebar::Panel>
|
|
21
21
|
{{/each}}
|
|
22
22
|
{{#each this.universeMenuPanels as |menuPanel|}}
|
|
23
|
-
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
|
|
23
|
+
<Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}} @titleIcon={{menuPanel.icon}} @hideCaret={{menuPanel.hideCaret}} @toggleOnCaretOnly={{menuPanel.toggleOnCaretOnly}} @onClickPanelTitle={{menuPanel.onClickPanelTitle}} @wrapperClass={{menuPanel.wrapperClass}} @dropdownButton={{menuPanel.dropdownButton}} @dropdownButtonActions={{menuPanel.dropdownButtonActions}} @dropdownButtonRenderInPlace={{menuPanel.dropdownButtonRenderInPlace}} @dropdownHorizontalPosition={{menuPanel.dropdownHorizontalPosition}} @dropdownButtonMenuLabel={{menuPanel.dropdownButtonMenuLabel}}>
|
|
24
24
|
{{#each menuPanel.items as |menuItem|}}
|
|
25
25
|
<Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @menuItem={{menuItem}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
|
|
26
26
|
{{/each}}
|
|
27
27
|
</Layout::Sidebar::Panel>
|
|
28
28
|
{{/each}}
|
|
29
|
-
{{!-- <Layout::Sidebar::Item @onClick={{this.onClickSettings}} @icon="cogs">{{t "fleet-ops.component.layout.fleet-ops-sidebar.settings"}}</Layout::Sidebar::Item> --}}
|
|
30
29
|
{{yield}}
|
|
31
30
|
<Spacer @height="10px" />
|
|
@@ -66,6 +66,8 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
66
66
|
{ title: this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.issues'), icon: 'triangle-exclamation', route: 'management.issues' },
|
|
67
67
|
];
|
|
68
68
|
|
|
69
|
+
const settingsItems = [{ title: this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.navigator-app'), icon: 'location-arrow', route: 'settings.navigator-app' }];
|
|
70
|
+
|
|
69
71
|
const createPanel = (title, routePrefix, items = []) => ({
|
|
70
72
|
title,
|
|
71
73
|
open: true,
|
|
@@ -81,6 +83,7 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
|
|
|
81
83
|
this.menuPanels = [
|
|
82
84
|
createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.operations'), 'operations', operationsItems),
|
|
83
85
|
createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.resources'), 'management', resourcesItems),
|
|
86
|
+
createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.settings'), 'settings', settingsItems),
|
|
84
87
|
].filter((panel) => {
|
|
85
88
|
const isVisible = panel.visible && panel.items.length > 0;
|
|
86
89
|
return isVisible;
|
package/addon/routes.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import buildRoutes from 'ember-engines/routes';
|
|
2
2
|
|
|
3
3
|
export default buildRoutes(function () {
|
|
4
|
+
this.route('settings', function () {
|
|
5
|
+
this.route('navigator-app');
|
|
6
|
+
});
|
|
4
7
|
this.route('virtual', { path: '/:slug/:view' });
|
|
5
8
|
this.route('operations', { path: '/' }, function () {
|
|
6
9
|
this.route('dispatch');
|
|
@@ -61,6 +61,30 @@ body[data-theme='dark'] .scheduler-left-sidebar {
|
|
|
61
61
|
padding-left: 3.5rem;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
/** content panel dropdown button */
|
|
65
|
+
.next-sidebar .next-sidebar-panel-container.next-driver-listing > .next-sidebar-panel > .next-content-panel > .next-content-panel-header.next-sidebar-panel-toggle {
|
|
66
|
+
padding-right: 0.25rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.next-sidebar
|
|
70
|
+
.next-sidebar-panel-container.next-driver-listing
|
|
71
|
+
> .next-sidebar-panel
|
|
72
|
+
> .next-content-panel
|
|
73
|
+
> .next-content-panel-header.next-sidebar-panel-toggle
|
|
74
|
+
.ember-basic-dropdown
|
|
75
|
+
button,
|
|
76
|
+
.next-sidebar
|
|
77
|
+
.next-sidebar-panel-container.next-driver-listing
|
|
78
|
+
> .next-sidebar-panel
|
|
79
|
+
> .next-content-panel
|
|
80
|
+
> .next-content-panel-header.next-sidebar-panel-toggle
|
|
81
|
+
.ember-basic-dropdown-trigger
|
|
82
|
+
button {
|
|
83
|
+
padding: 0.15rem 0.625rem;
|
|
84
|
+
font-size: 10px;
|
|
85
|
+
line-height: 0.5;
|
|
86
|
+
}
|
|
87
|
+
|
|
64
88
|
.multi-drop-select-container .fleetbase-model-select.fleetbase-power-select.ember-model-select > .ember-model-select__loading {
|
|
65
89
|
background: none;
|
|
66
90
|
border: none;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<Layout::Section::Header @title={{t "fleet-ops.settings.navigator-app.navigator-app-settings"}} />
|
|
2
|
+
|
|
3
|
+
<Layout::Section::Body class="overflow-y-scroll h-full">
|
|
4
|
+
<div class="container mx-auto h-screen">
|
|
5
|
+
<div class="max-w-3xl my-10 mx-auto space-y-6">
|
|
6
|
+
<EntityFieldEditingSettings />
|
|
7
|
+
<DriverOnboardSettings />
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
<Spacer @height="600px" />
|
|
11
|
+
</Layout::Section::Body>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{{outlet}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/driver-onboard-settings';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/entity-field-editing-settings';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/routes/settings/navigator-app';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/routes/settings';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/templates/settings/navigator-app';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/templates/settings';
|
package/composer.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetbase/fleetops-api",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.25",
|
|
4
4
|
"description": "Fleet & Transport Management Extension for Fleetbase",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fleetbase-extension",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"require": {
|
|
24
24
|
"php": "^8.0",
|
|
25
|
-
"fleetbase/core-api": "^1.4.
|
|
25
|
+
"fleetbase/core-api": "^1.4.16",
|
|
26
26
|
"barryvdh/laravel-dompdf": "^2.0",
|
|
27
27
|
"brick/geo": "0.7.2",
|
|
28
28
|
"cknow/laravel-money": "^7.1",
|
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fleetbase/fleetops-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.25",
|
|
4
4
|
"description": "Fleet & Transport Management Extension for Fleetbase",
|
|
5
5
|
"fleetbase": {
|
|
6
6
|
"route": "fleet-ops"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@babel/core": "^7.23.2",
|
|
45
45
|
"@fleetbase/ember-core": "^0.2.8",
|
|
46
|
-
"@fleetbase/ember-ui": "^0.2.
|
|
46
|
+
"@fleetbase/ember-ui": "^0.2.12",
|
|
47
47
|
"@fleetbase/fleetops-data": "^0.1.14",
|
|
48
48
|
"@fleetbase/leaflet-routing-machine": "^3.2.16",
|
|
49
49
|
"@fortawesome/ember-fontawesome": "^0.4.1",
|
|
@@ -36,7 +36,7 @@ class FixInvalidPolymorphicRelationTypeNamespaces extends Command
|
|
|
36
36
|
['model' => \Fleetbase\FleetOps\Models\Order::class, 'columns' => ['customer_type', 'facilitator_type']],
|
|
37
37
|
['model' => \Fleetbase\FleetOps\Models\Place::class, 'columns' => ['owner_type']],
|
|
38
38
|
['model' => \Fleetbase\FleetOps\Models\Entity::class, 'columns' => ['customer_type']],
|
|
39
|
-
['model' => \Fleetbase\FleetOps\Models\PurchaseRate::class, 'columns' => ['customer_type']]
|
|
39
|
+
['model' => \Fleetbase\FleetOps\Models\PurchaseRate::class, 'columns' => ['customer_type']],
|
|
40
40
|
];
|
|
41
41
|
|
|
42
42
|
foreach ($models as $modelConfig) {
|
|
@@ -44,6 +44,9 @@ class DriverController extends Controller
|
|
|
44
44
|
// get request input
|
|
45
45
|
$input = $request->except(['name', 'password', 'email', 'phone', 'location', 'altitude', 'heading', 'speed', 'meta']);
|
|
46
46
|
|
|
47
|
+
// Add default status
|
|
48
|
+
$input['status'] = 'active';
|
|
49
|
+
|
|
47
50
|
// get user details for driver
|
|
48
51
|
$userDetails = $request->only(['name', 'password', 'email', 'phone', 'timezone']);
|
|
49
52
|
|
|
@@ -145,7 +148,10 @@ class DriverController extends Controller
|
|
|
145
148
|
$userDetails = $request->only(['name', 'password', 'email', 'phone']);
|
|
146
149
|
|
|
147
150
|
// update driver user details
|
|
148
|
-
$driver->
|
|
151
|
+
$driverUser = $driver->getUser();
|
|
152
|
+
if ($driverUser) {
|
|
153
|
+
$driverUser->update($userDetails);
|
|
154
|
+
}
|
|
149
155
|
|
|
150
156
|
// vehicle assignment public_id -> uuid
|
|
151
157
|
if ($request->has('vehicle')) {
|
|
@@ -773,4 +779,4 @@ class DriverController extends Controller
|
|
|
773
779
|
|
|
774
780
|
return $phone;
|
|
775
781
|
}
|
|
776
|
-
}
|
|
782
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Http\Controllers\Api\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\Controller;
|
|
6
|
+
use Fleetbase\Models\Setting;
|
|
7
|
+
|
|
8
|
+
class NavigatorController extends Controller
|
|
9
|
+
{
|
|
10
|
+
/**
|
|
11
|
+
* Retrieve the driver onboard settings.
|
|
12
|
+
*
|
|
13
|
+
* This method retrieves the driver onboard settings for the current company session. If no company session
|
|
14
|
+
* is found in the request, an error response is returned. The method retrieves the company ID from the session,
|
|
15
|
+
* then fetches the saved driver onboard settings. If settings for the current company are found, they are returned,
|
|
16
|
+
* otherwise, default settings are provided.
|
|
17
|
+
*
|
|
18
|
+
* @return \Illuminate\Http\JsonResponse
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Retrieve driver onboard settings.
|
|
23
|
+
*
|
|
24
|
+
* @return \Illuminate\Http\JsonResponse
|
|
25
|
+
*/
|
|
26
|
+
public function getDriverOnboardSettings($companyId)
|
|
27
|
+
{
|
|
28
|
+
$driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings.' . $companyId)->value('value');
|
|
29
|
+
if (!$driverOnboardSettings) {
|
|
30
|
+
$driverOnboardSettings = [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -498,7 +498,7 @@ class OrderController extends Controller
|
|
|
498
498
|
|
|
499
499
|
if ($request->filled('on')) {
|
|
500
500
|
$on = Carbon::parse($request->input('on'));
|
|
501
|
-
|
|
501
|
+
|
|
502
502
|
$query->where(function ($q) use ($on) {
|
|
503
503
|
$q->whereDate('created_at', $on);
|
|
504
504
|
$q->orWhereDate('scheduled_at', $on);
|
|
@@ -1408,4 +1408,4 @@ class OrderController extends Controller
|
|
|
1408
1408
|
|
|
1409
1409
|
return response()->json($entityEditingSettings);
|
|
1410
1410
|
}
|
|
1411
|
-
}
|
|
1411
|
+
}
|
|
@@ -5,6 +5,8 @@ namespace Fleetbase\FleetOps\Http\Controllers\Api\v1;
|
|
|
5
5
|
use Fleetbase\Http\Controllers\Controller;
|
|
6
6
|
use Fleetbase\Http\Resources\Organization;
|
|
7
7
|
use Fleetbase\Models\Company;
|
|
8
|
+
use Fleetbase\Models\Setting;
|
|
9
|
+
use Illuminate\Http\Request;
|
|
8
10
|
|
|
9
11
|
class OrganizationController extends Controller
|
|
10
12
|
{
|
|
@@ -13,15 +15,31 @@ class OrganizationController extends Controller
|
|
|
13
15
|
*
|
|
14
16
|
* @return Organization
|
|
15
17
|
*/
|
|
16
|
-
public function listOrganizations()
|
|
18
|
+
public function listOrganizations(Request $request)
|
|
17
19
|
{
|
|
18
|
-
$
|
|
20
|
+
$limit = $request->input('limit', 10);
|
|
21
|
+
$withDriverOnboardEnabled = $request->boolean('with_driver_onboard');
|
|
22
|
+
|
|
23
|
+
$companies = Company::whereHas('users')->get()->map(function ($company) {
|
|
19
24
|
return [
|
|
20
|
-
'name'
|
|
21
|
-
'
|
|
25
|
+
'name' => $company->name,
|
|
26
|
+
'uuid' => $company->uuid,
|
|
22
27
|
];
|
|
23
28
|
});
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
if ($withDriverOnboardEnabled) {
|
|
31
|
+
$driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings')->value('value');
|
|
32
|
+
|
|
33
|
+
$companies = $companies->filter(function ($company) use ($driverOnboardSettings) {
|
|
34
|
+
return $driverOnboardSettings && isset($driverOnboardSettings[$company['uuid']]) && data_get($driverOnboardSettings[$company['uuid']], 'enableDriverOnboardFromApp') === true;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// limit
|
|
39
|
+
$companies = $companies->take($limit);
|
|
40
|
+
|
|
41
|
+
$companiesArray = $companies->values()->toArray();
|
|
42
|
+
|
|
43
|
+
return response()->json($companiesArray);
|
|
26
44
|
}
|
|
27
45
|
}
|
|
@@ -255,14 +255,18 @@ class DriverController extends FleetOpsController
|
|
|
255
255
|
}
|
|
256
256
|
$input = $input->except(['name', 'password', 'email', 'phone', 'meta', 'avatar_uuid', 'photo_uuid'])->toArray();
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
$driver->
|
|
258
|
+
// Update driver user details
|
|
259
|
+
$driverUser = $driver->getUser();
|
|
260
|
+
if ($driverUser) {
|
|
261
|
+
$driverUser->update($userInput);
|
|
262
|
+
$input['slug'] = $driverUser->slug;
|
|
263
|
+
}
|
|
260
264
|
|
|
261
|
-
|
|
265
|
+
// Flush cache
|
|
266
|
+
$driver->flushAttributesCache();
|
|
262
267
|
},
|
|
263
268
|
function ($request, &$driver) {
|
|
264
269
|
$driver->load(['user']);
|
|
265
|
-
|
|
266
270
|
if ($driver->user) {
|
|
267
271
|
$driver->user->setHidden(['driver']);
|
|
268
272
|
}
|
|
@@ -6,6 +6,7 @@ use Fleetbase\Http\Controllers\Controller;
|
|
|
6
6
|
use Fleetbase\Http\Resources\Organization;
|
|
7
7
|
use Fleetbase\Models\ApiCredential;
|
|
8
8
|
use Fleetbase\Models\Company;
|
|
9
|
+
use Fleetbase\Models\Setting;
|
|
9
10
|
use Fleetbase\Models\User;
|
|
10
11
|
use Illuminate\Http\Request;
|
|
11
12
|
use Illuminate\Support\Str;
|
|
@@ -76,4 +77,11 @@ class NavigatorController extends Controller
|
|
|
76
77
|
|
|
77
78
|
return new Organization($organization);
|
|
78
79
|
}
|
|
80
|
+
|
|
81
|
+
public function getDriverOnboardSettings()
|
|
82
|
+
{
|
|
83
|
+
$onBoardSettings = Setting::where('key', 'fleet-ops.driver-onboard')->value('value');
|
|
84
|
+
|
|
85
|
+
return response()->json($onBoardSettings);
|
|
86
|
+
}
|
|
79
87
|
}
|
|
@@ -48,23 +48,69 @@ class SettingController extends Controller
|
|
|
48
48
|
return response()->json(['visibilitySettings' => $visibilitySettings]);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Save entity editing settings.
|
|
53
|
+
*
|
|
54
|
+
* @return \Illuminate\Http\JsonResponse
|
|
55
|
+
*/
|
|
51
56
|
public function saveEntityEditingSettings(Request $request)
|
|
52
57
|
{
|
|
53
58
|
$entityEditingSettings = $request->input('entityEditingSettings', []);
|
|
54
|
-
$isEntityFieldsEditable = $request->boolean('isEntityFieldsEditable');
|
|
55
59
|
|
|
56
60
|
// Save entity editing settings
|
|
57
61
|
Setting::configure('fleet-ops.entity-editing-settings', $entityEditingSettings);
|
|
58
|
-
Setting::configure('fleet-ops.entity-fields-editable', $isEntityFieldsEditable);
|
|
59
62
|
|
|
60
|
-
return response()->json(['entityEditingSettings' => $entityEditingSettings
|
|
63
|
+
return response()->json(['entityEditingSettings' => $entityEditingSettings]);
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Retrieve entity editing settings.
|
|
68
|
+
*
|
|
69
|
+
* @return \Illuminate\Http\JsonResponse
|
|
70
|
+
*/
|
|
63
71
|
public function getEntityEditingSettings()
|
|
64
72
|
{
|
|
65
73
|
$entityEditingSettings = Setting::where('key', 'fleet-ops.entity-editing-settings')->value('value');
|
|
66
|
-
|
|
74
|
+
if (!$entityEditingSettings) {
|
|
75
|
+
$entityEditingSettings = [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return response()->json(['entityEditingSettings' => $entityEditingSettings]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Retrieve driver onboard settings.
|
|
83
|
+
*
|
|
84
|
+
* @return \Illuminate\Http\JsonResponse
|
|
85
|
+
*/
|
|
86
|
+
public function getDriverOnboardSettings($companyId)
|
|
87
|
+
{
|
|
88
|
+
$driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings.' . $companyId)->value('value');
|
|
89
|
+
if (!$driverOnboardSettings) {
|
|
90
|
+
$driverOnboardSettings = [];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Save driver onboard settings.
|
|
98
|
+
*
|
|
99
|
+
* @return \Illuminate\Http\JsonResponse
|
|
100
|
+
*/
|
|
101
|
+
public function savedDriverOnboardSettings(Request $request)
|
|
102
|
+
{
|
|
103
|
+
$driverOnboardSettings = $request->input('driverOnboardSettings', []);
|
|
104
|
+
|
|
105
|
+
if ($driverOnboardSettings['enableDriverOnboardFromApp'] == false) {
|
|
106
|
+
$driverOnboardSettings['driverMustProvideOnboardDoucments'] = false;
|
|
107
|
+
$driverOnboardSettings['requiredOnboardDocuments'] = [];
|
|
108
|
+
$driverOnboardSettings['driverOnboardAppMethod'] = '';
|
|
109
|
+
$driverOnboardSettings['enableDriverOnboardFromApp'] = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
Setting::configure('fleet-ops.driver-onboard-settings.' . $driverOnboardSettings['companyId'], $driverOnboardSettings);
|
|
67
113
|
|
|
68
|
-
return response()->json(['
|
|
114
|
+
return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
|
|
69
115
|
}
|
|
70
116
|
}
|
|
@@ -14,7 +14,7 @@ class CreateContactRequest extends FleetbaseRequest
|
|
|
14
14
|
*/
|
|
15
15
|
public function authorize()
|
|
16
16
|
{
|
|
17
|
-
return request()->session()->has('storefront_key') || request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token')
|
|
17
|
+
return request()->session()->has('storefront_key') || request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -14,7 +14,7 @@ class CreateEntityRequest extends FleetbaseRequest
|
|
|
14
14
|
*/
|
|
15
15
|
public function authorize()
|
|
16
16
|
{
|
|
17
|
-
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token')
|
|
17
|
+
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -13,7 +13,7 @@ class CreateIssueRequest extends FleetbaseRequest
|
|
|
13
13
|
*/
|
|
14
14
|
public function authorize()
|
|
15
15
|
{
|
|
16
|
-
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token')
|
|
16
|
+
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -16,7 +16,7 @@ class CreatePlaceRequest extends FleetbaseRequest
|
|
|
16
16
|
*/
|
|
17
17
|
public function authorize()
|
|
18
18
|
{
|
|
19
|
-
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token')
|
|
19
|
+
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -14,7 +14,7 @@ class CreateVehicleRequest extends FleetbaseRequest
|
|
|
14
14
|
*/
|
|
15
15
|
public function authorize()
|
|
16
16
|
{
|
|
17
|
-
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token')
|
|
17
|
+
return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -851,8 +851,8 @@ class Utils extends FleetbaseUtils
|
|
|
851
851
|
* Calculates driving distance and time between two points using Vincenty's formula.
|
|
852
852
|
* Returns distance in meters and time in seconds.
|
|
853
853
|
*
|
|
854
|
-
* @param \Fleetbase\FleetOps\Models\Place
|
|
855
|
-
* @param \Fleetbase\FleetOps\Models\Place
|
|
854
|
+
* @param \Fleetbase\FleetOps\Models\Place|Point|array $origin
|
|
855
|
+
* @param \Fleetbase\FleetOps\Models\Place|Point|array $destination
|
|
856
856
|
*/
|
|
857
857
|
public static function calculateDrivingDistanceAndTime($origin, $destination): DistanceMatrix
|
|
858
858
|
{
|
|
@@ -870,8 +870,8 @@ class Utils extends FleetbaseUtils
|
|
|
870
870
|
* Calculates driving distance and time between two points using Vincenty's formula.
|
|
871
871
|
* Returns distance in meters and time in seconds.
|
|
872
872
|
*
|
|
873
|
-
* @param \Fleetbase\FleetOps\Models\Place
|
|
874
|
-
* @param \Fleetbase\FleetOps\Models\Place
|
|
873
|
+
* @param \Fleetbase\FleetOps\Models\Place|Point|array $origin
|
|
874
|
+
* @param \Fleetbase\FleetOps\Models\Place|Point|array $destination
|
|
875
875
|
*/
|
|
876
876
|
public static function getPreliminaryDistanceMatrix($origin, $destination): DistanceMatrix
|
|
877
877
|
{
|
package/server/src/routes.php
CHANGED
|
@@ -179,6 +179,11 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
|
|
|
179
179
|
$router->group(['prefix' => 'labels'], function () use ($router) {
|
|
180
180
|
$router->get('{id}', 'LabelController@getLabel');
|
|
181
181
|
});
|
|
182
|
+
|
|
183
|
+
// navigator routes
|
|
184
|
+
$router->group(['prefix' => 'onboard'], function () use ($router) {
|
|
185
|
+
$router->get('driver-onboard-settings/{companyId}', 'NavigatorController@getDriverOnboardSettings');
|
|
186
|
+
});
|
|
182
187
|
});
|
|
183
188
|
|
|
184
189
|
/*
|
|
@@ -435,6 +440,8 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
|
|
|
435
440
|
$router->post('visibility', 'SettingController@saveVisibilitySettings');
|
|
436
441
|
$router->get('entity-editing-settings', 'SettingController@getEntityEditingSettings');
|
|
437
442
|
$router->post('entity-editing-settings', 'SettingController@saveEntityEditingSettings');
|
|
443
|
+
$router->post('driver-onboard-settings', 'SettingController@savedDriverOnboardSettings');
|
|
444
|
+
$router->get('driver-onboard-settings/{companyId}', 'SettingController@getDriverOnboardSettings');
|
|
438
445
|
}
|
|
439
446
|
);
|
|
440
447
|
$router->group(
|
package/translations/en-us.yaml
CHANGED
|
@@ -94,7 +94,6 @@ fleet-ops:
|
|
|
94
94
|
total: Total
|
|
95
95
|
back: Back
|
|
96
96
|
done: Done
|
|
97
|
-
|
|
98
97
|
component:
|
|
99
98
|
activity-logic-builder:
|
|
100
99
|
activity-logic: Activity Logic
|
|
@@ -238,7 +237,11 @@ fleet-ops:
|
|
|
238
237
|
message: Use this URL to link the official Navigator app to this {companyName} instance. Opening this URL on a mobile device will open the Navigator app and update it's configuration and branding.
|
|
239
238
|
settings: Entity Settings
|
|
240
239
|
select-input: Allow driver to update entity details
|
|
241
|
-
|
|
240
|
+
driver-settings: Driver Settings
|
|
241
|
+
description: Enable driver on-board
|
|
242
|
+
upload-document: Require driver to upload documents
|
|
243
|
+
upload-body: Add documents
|
|
244
|
+
document: Document
|
|
242
245
|
visibility-controls:
|
|
243
246
|
title: Visibility Controls
|
|
244
247
|
message: Visibility controls allow you to disable sections of Fleet-Ops. Toggle the checkbox to enable or disable sections to hide in Fleet-ops.
|
|
@@ -249,6 +252,25 @@ fleet-ops:
|
|
|
249
252
|
vehicles : Vehicles
|
|
250
253
|
drivers : Drivers
|
|
251
254
|
places : Places
|
|
255
|
+
entity-field-editing-settings:
|
|
256
|
+
entitiy-field-editing-settings: Entity Field Editing Settings
|
|
257
|
+
entity-field-editing-settings-help-text: These settings determine which fields of an entity are editable by a driver via Navigator App
|
|
258
|
+
select-order-config: Select Order Config
|
|
259
|
+
select-order-config-help-text: Select an order config which these settings will apply to
|
|
260
|
+
enable-driver-to-edit-entity-fields: Allow driver to edit entity details
|
|
261
|
+
enable-driver-to-edit-entity-fields-help-text: Enabling this toggle grants the driver permission to modify specific entity fields chosen below.
|
|
262
|
+
driver-onboard-settings:
|
|
263
|
+
driver-onboard-settings: Driver Onboard Settings
|
|
264
|
+
enable-driver-onboard-from-app: Enable driver onboard from Navigator App
|
|
265
|
+
enable-driver-onboard-from-app-help-text: Enabling this setting allows drivers to independently onboard (create their own account) via the Navigator App.
|
|
266
|
+
select-onboard-method: Select driver onboard method
|
|
267
|
+
select-onboard-method-help-text: This setting determines how drivers are permitted to create their accounts through the Navigator App. Choose 'Invite' if drivers need to receive an email invitation to create their account. Select 'Button' if you wish to enable a button within the app that allows anyone to create a driver account.
|
|
268
|
+
require-driver-to-upload-onboard-documents: Require driver to upload onboard documents
|
|
269
|
+
require-driver-to-upload-onboard-documents-help-text: This setting enforces documents that a driver must provide before their account can be created.
|
|
270
|
+
required-onboard-documents: Required onboard documents
|
|
271
|
+
required-onboard-documents-help-text: Input all the onboard documents required for a driver to provide below using the "Add onboard document" button.
|
|
272
|
+
enter-document-name: Enter document name
|
|
273
|
+
add-onboard-document: Add onboard document
|
|
252
274
|
cell:
|
|
253
275
|
driver-name:
|
|
254
276
|
not-assigned: No driver assigned
|
|
@@ -265,6 +287,7 @@ fleet-ops:
|
|
|
265
287
|
loading-vehicle: Loading fleet vehicles...
|
|
266
288
|
layout:
|
|
267
289
|
fleet-ops-sidebar:
|
|
290
|
+
navigator-app: Navigator App
|
|
268
291
|
resources: Resources
|
|
269
292
|
operations: Operations
|
|
270
293
|
dashboard: Dashboard
|
|
@@ -1511,4 +1534,6 @@ fleet-ops:
|
|
|
1511
1534
|
zone-label: Zone
|
|
1512
1535
|
zone-help-text: Restrict this service to order request originating from a specific zone.
|
|
1513
1536
|
zone-placeholder: Restrict to zone
|
|
1514
|
-
|
|
1537
|
+
settings:
|
|
1538
|
+
navigator-app:
|
|
1539
|
+
navigator-app-settings: Navigator App Settings
|