@fleetbase/fleetops-engine 0.4.16 → 0.4.17
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/.php-cs-fixer.php +2 -0
- package/addon/components/activity-event-selector.hbs +35 -0
- package/addon/components/activity-event-selector.js +85 -0
- package/addon/components/activity-form-panel.hbs +23 -0
- package/addon/components/activity-form-panel.js +90 -0
- package/addon/components/activity-logic-builder.hbs +80 -0
- package/addon/components/activity-logic-builder.js +260 -0
- package/addon/components/contact-form-panel.hbs +1 -1
- package/addon/components/contact-panel.hbs +1 -1
- package/addon/components/custom-entity-form-panel.hbs +43 -0
- package/addon/components/custom-entity-form-panel.js +129 -0
- package/addon/components/custom-field-form-panel/options-input.hbs +12 -0
- package/addon/components/custom-field-form-panel/options-input.js +139 -0
- package/addon/components/custom-field-form-panel.hbs +77 -0
- package/addon/components/custom-field-form-panel.js +144 -0
- package/addon/components/custom-field.hbs +63 -41
- package/addon/components/custom-field.js +123 -25
- package/addon/components/driver-form-panel.hbs +1 -1
- package/addon/components/driver-panel.hbs +1 -1
- package/addon/components/edit-order-route-panel.hbs +1 -1
- package/addon/components/fleet-form-panel.hbs +1 -1
- package/addon/components/fleet-panel.hbs +1 -1
- package/addon/components/fuel-report-form-panel.hbs +1 -1
- package/addon/components/fuel-report-panel.hbs +1 -1
- package/addon/components/issue-form-panel.hbs +1 -1
- package/addon/components/issue-panel.hbs +1 -1
- package/addon/components/joint-graph.hbs +1 -0
- package/addon/components/joint-graph.js +103 -0
- package/addon/components/layout/fleet-ops-sidebar.hbs +3 -3
- package/addon/components/layout/fleet-ops-sidebar.js +1 -0
- package/addon/components/live-map.js +71 -28
- package/addon/components/modals/new-custom-field-group.hbs +5 -0
- package/addon/components/modals/new-order-config.hbs +3 -3
- package/addon/components/modals/order-new-activity.hbs +1 -1
- package/addon/components/order-config-manager/activity-flow.hbs +11 -0
- package/addon/components/order-config-manager/activity-flow.js +964 -0
- package/addon/components/order-config-manager/custom-fields.hbs +50 -0
- package/addon/components/order-config-manager/custom-fields.js +276 -0
- package/addon/components/order-config-manager/details.hbs +23 -0
- package/addon/components/order-config-manager/details.js +97 -0
- package/addon/components/order-config-manager/entities.hbs +54 -0
- package/addon/components/order-config-manager/entities.js +227 -0
- package/addon/components/order-config-manager-overlay.hbs +26 -0
- package/addon/components/order-config-manager-overlay.js +60 -0
- package/addon/components/order-config-manager.hbs +15 -0
- package/addon/components/order-config-manager.js +285 -0
- package/addon/components/order-flow.hbs +1 -0
- package/addon/components/order-flow.js +3 -0
- package/addon/components/place-form-panel.hbs +1 -1
- package/addon/components/place-panel.hbs +1 -1
- package/addon/components/vehicle-form-panel.hbs +1 -1
- package/addon/components/vehicle-panel.hbs +1 -1
- package/addon/components/vendor-form-panel.hbs +1 -1
- package/addon/components/vendor-panel.hbs +1 -1
- package/addon/controllers/application.js +5 -1
- package/addon/controllers/operations/order-config.js +42 -0
- package/addon/controllers/operations/orders/index/new.js +125 -21
- package/addon/controllers/operations/orders/index/view.js +87 -4
- package/addon/controllers/operations/orders/index.js +2 -2
- package/addon/engine.js +10 -1
- package/addon/initializers/load-jointjs.js +16 -0
- package/addon/routes/application.js +1 -1
- package/addon/routes/operations/order-config.js +28 -0
- package/addon/routes/operations/orders/index/new.js +2 -3
- package/addon/routes/operations/orders/index/view.js +1 -1
- package/addon/routes.js +1 -0
- package/addon/services/context-panel.js +65 -3
- package/addon/styles/fleetops-engine.css +268 -0
- package/addon/templates/application.hbs +1 -1
- package/addon/templates/operations/order-config.hbs +55 -0
- package/addon/templates/operations/orders/index/new.hbs +98 -339
- package/addon/templates/operations/orders/index/view.hbs +36 -96
- package/addon/templates/operations/orders/index.hbs +0 -1
- package/addon/utils/apply-context-component-arguments.js +4 -2
- package/addon/utils/create-custom-entity.js +22 -0
- package/addon/utils/create-flow-activity.js +31 -0
- package/addon/utils/get-custom-field-type-map.js +34 -0
- package/app/components/activity-event-selector.js +1 -0
- package/app/components/activity-form-panel.js +1 -0
- package/app/components/activity-logic-builder.js +1 -0
- package/app/components/custom-entity-form-panel.js +1 -0
- package/app/components/custom-field-form-panel/options-input.js +1 -0
- package/app/components/custom-field-form-panel.js +1 -0
- package/app/components/joint-graph.js +1 -0
- package/app/components/modals/new-custom-field-group.js +1 -0
- package/app/components/order-config-manager/activity-flow.js +1 -0
- package/app/components/order-config-manager/custom-fields.js +1 -0
- package/app/components/order-config-manager/details.js +1 -0
- package/app/components/order-config-manager/entities.js +1 -0
- package/app/components/order-config-manager-overlay.js +1 -0
- package/app/components/order-config-manager.js +1 -0
- package/app/components/order-flow.js +1 -0
- package/app/controllers/operations/order-config.js +1 -0
- package/app/routes/operations/order-config.js +1 -0
- package/app/templates/operations/order-config.js +1 -0
- package/app/utils/create-custom-entity.js +1 -0
- package/app/utils/create-flow-activity.js +1 -0
- package/app/utils/get-custom-field-type-map.js +1 -0
- package/composer.json +4 -3
- package/config/environment.js +1 -0
- package/extension.json +1 -1
- package/index.js +20 -0
- package/package.json +7 -5
- package/server/migrations/2023_04_27_053456_create_contacts_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_drivers_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_entities_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_fleet_drivers_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_fleets_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_fuel_reports_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_integrated_vendors_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_issues_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_orders_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_payloads_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_places_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_positions_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_proofs_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_purchase_rates_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_routes_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_areas_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_quote_items_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_quotes_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_rate_fees_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_rate_parcel_fees_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_service_rates_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_tracking_numbers_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_tracking_statuses_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_vehicles_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_vendors_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_waypoints_table.php +1 -2
- package/server/migrations/2023_04_27_053456_create_zones_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_companies_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_contacts_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_drivers_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_entities_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleet_drivers_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleets_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fuel_reports_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_integrated_vendors_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_issues_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_orders_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_payloads_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_places_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_positions_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_proofs_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_purchase_rates_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_routes_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_areas_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quote_items_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quotes_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_fees_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_parcel_fees_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rates_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_numbers_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_statuses_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vehicles_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vendors_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_waypoints_table.php +1 -2
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_zones_table.php +1 -2
- package/server/migrations/2023_09_14_074512_update_vehicles_table.php +1 -2
- package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +35 -36
- package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +1 -2
- package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +1 -2
- package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +1 -2
- package/server/migrations/2023_10_05_074811_update_vehicle.php +1 -2
- package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +1 -2
- package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +1 -2
- package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +1 -2
- package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +1 -2
- package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +1 -2
- package/server/migrations/2023_11_17_053001_add_category_uuid_to_entities_table.php +1 -2
- package/server/migrations/2023_11_28_074244_add_supplier_uuid_column_to_entities_table.php +1 -2
- package/server/migrations/2023_12_14_100209_add_meta_column_on_driver_table copy.php +1 -2
- package/server/migrations/2024_02_18_100209_add_avatar_url_columns_table.php +3 -4
- package/server/migrations/2024_02_27_093648_create_order_configs_table.php +43 -0
- package/server/migrations/2024_03_07_075508_add_order_config_uuid_column_to_orders_table.php +28 -0
- package/server/seeders/OrderConfigSeeder.php +151 -0
- package/server/src/Casts/OrderConfigEntities.php +53 -0
- package/server/src/Console/Commands/FixLegacyOrderConfigs.php +66 -0
- package/server/src/Events/DriverLocationChanged.php +1 -1
- package/server/src/Events/DriverSimulatedLocationChanged.php +1 -1
- package/server/src/Flow/Activity.php +232 -6
- package/server/src/Flow/Condition.php +84 -0
- package/server/src/Flow/Event.php +88 -0
- package/server/src/Flow/Flow.php +50 -0
- package/server/src/Flow/FlowResource.php +143 -0
- package/server/src/Flow/Logic.php +57 -1
- package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/IssueController.php +132 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +130 -57
- package/server/src/Http/Controllers/Api/v1/OrganizationController.php +27 -0
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +2 -3
- package/server/src/Http/Controllers/Controller.php +9 -0
- package/server/src/Http/Controllers/FleetOpsController.php +7 -0
- package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +5 -259
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +46 -26
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +20 -0
- package/server/src/Http/Filter/OrderConfigFilter.php +13 -0
- package/server/src/Http/Requests/CreateIssueRequest.php +19 -0
- package/server/src/Http/Requests/UpdateIssueRequest.php +7 -0
- package/server/src/Http/Resources/v1/Order.php +3 -0
- package/server/src/Listeners/HandleOrderCanceled.php +8 -4
- package/server/src/Listeners/HandleOrderDispatched.php +14 -12
- package/server/src/Models/Order.php +527 -31
- package/server/src/Models/OrderConfig.php +419 -0
- package/server/src/Models/Payload.php +6 -7
- package/server/src/Notifications/OrderAssigned.php +1 -1
- package/server/src/Notifications/OrderCanceled.php +1 -1
- package/server/src/Notifications/OrderDispatchFailed.php +1 -1
- package/server/src/Notifications/OrderDispatched.php +1 -1
- package/server/src/Notifications/OrderPing.php +1 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +3 -1
- package/server/src/Providers/NotificationServiceProvider.php +2 -1
- package/server/src/Support/Utils.php +17 -0
- package/server/src/Traits/HasTrackingNumber.php +9 -9
- package/server/src/routes.php +19 -11
- package/translations/en-us.yaml +137 -0
- package/server/src/Flow/Config.php +0 -7
- package/server/src/Support/Flow.php +0 -653
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
import Component from '@glimmer/component';
|
|
3
|
+
import ObjectProxy from '@ember/object/proxy';
|
|
4
|
+
import { tracked } from '@glimmer/tracking';
|
|
5
|
+
import { inject as service } from '@ember/service';
|
|
6
|
+
import { action } from '@ember/object';
|
|
7
|
+
import { isArray } from '@ember/array';
|
|
8
|
+
import { later } from '@ember/runloop';
|
|
9
|
+
import { task } from 'ember-concurrency-decorators';
|
|
10
|
+
import generateUUID from '@fleetbase/ember-core/utils/generate-uuid';
|
|
11
|
+
import createFlowActivity from '../../utils/create-flow-activity';
|
|
12
|
+
import contextComponentCallback from '../../utils/context-component-callback';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Manages the activity flow for order configuration, allowing users to create, edit, and view a sequence of activities.
|
|
16
|
+
* @extends Component
|
|
17
|
+
*/
|
|
18
|
+
export default class OrderConfigManagerActivityFlowComponent extends Component {
|
|
19
|
+
/**
|
|
20
|
+
* Service to manage context panel interactions.
|
|
21
|
+
* @type {Service}
|
|
22
|
+
*/
|
|
23
|
+
@service contextPanel;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Service to fire notifications.
|
|
27
|
+
* @type {Service}
|
|
28
|
+
*/
|
|
29
|
+
@service notifications;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Service for internationalization.
|
|
33
|
+
* @type {Service}
|
|
34
|
+
*/
|
|
35
|
+
@service intl;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Represents the current state of the activity flow.
|
|
39
|
+
* @type {Object}
|
|
40
|
+
*/
|
|
41
|
+
@tracked flow = {};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* An array of activity codes that should not be modified.
|
|
45
|
+
* @type {Array.<string>}
|
|
46
|
+
*/
|
|
47
|
+
@tracked immutableActivities = ['created', 'dispatched', 'started'];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The configuration data for the activity flow.
|
|
51
|
+
* @type {Object}
|
|
52
|
+
*/
|
|
53
|
+
@tracked config;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* JointJS paper instance where the graph is rendered.
|
|
57
|
+
* @type {Object}
|
|
58
|
+
*/
|
|
59
|
+
@tracked paper;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* JointJS graph instance representing the activity flow.
|
|
63
|
+
* @type {Object}
|
|
64
|
+
*/
|
|
65
|
+
@tracked graph;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Initializes the component with the given configuration.
|
|
69
|
+
* @param {Object} owner - The owner of the component instance.
|
|
70
|
+
* @param {Object} config - The configuration data for the activity flow.
|
|
71
|
+
*/
|
|
72
|
+
constructor(owner, { config, configManagerContext }) {
|
|
73
|
+
super(...arguments);
|
|
74
|
+
this.config = config;
|
|
75
|
+
|
|
76
|
+
configManagerContext.on('onConfigChanged', (newConfig) => {
|
|
77
|
+
this.changeConfig(newConfig);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Action to initialize the graph on the JointJS paper instance.
|
|
83
|
+
* @param {Object} paper - The JointJS paper instance.
|
|
84
|
+
* @param {Object} graph - The JointJS graph instance.
|
|
85
|
+
*/
|
|
86
|
+
@action initializeGraph({ paper, graph }) {
|
|
87
|
+
this.paper = paper;
|
|
88
|
+
this.graph = graph;
|
|
89
|
+
this.initializeActivityJointModel();
|
|
90
|
+
this.initializeActivityFlow();
|
|
91
|
+
this.listenForElementClicks();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Zooms in by scaling the paper.
|
|
96
|
+
*
|
|
97
|
+
* @return {void}
|
|
98
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
99
|
+
*/
|
|
100
|
+
@action zoomIn() {
|
|
101
|
+
const currentScale = this.paper.scale();
|
|
102
|
+
const currentScaleSx = currentScale.sx;
|
|
103
|
+
if (currentScaleSx >= 1.2) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.paper.scale(currentScaleSx + 0.2);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Zooms out by scaling the paper.
|
|
112
|
+
*
|
|
113
|
+
* @return {void}
|
|
114
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
115
|
+
*/
|
|
116
|
+
@action zoomOut() {
|
|
117
|
+
const currentScale = this.paper.scale();
|
|
118
|
+
const currentScaleSx = currentScale.sx;
|
|
119
|
+
if (currentScaleSx <= 0.2) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.paper.scale(currentScaleSx - 0.2);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Handles the reset of the config.
|
|
128
|
+
*
|
|
129
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
130
|
+
*/
|
|
131
|
+
@action resetConfig() {
|
|
132
|
+
this.clearGraph({
|
|
133
|
+
onAfter: () => {
|
|
134
|
+
this.flow = {};
|
|
135
|
+
const defaultActivities = this.getDefaultActivities();
|
|
136
|
+
this.addActivityToGraph(defaultActivities);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Handles the change of a config.
|
|
143
|
+
*
|
|
144
|
+
* @param {OrderConfigModel} newConfig
|
|
145
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
146
|
+
*/
|
|
147
|
+
changeConfig(newConfig) {
|
|
148
|
+
this.clearGraph({
|
|
149
|
+
onAfter: () => {
|
|
150
|
+
this.config = newConfig;
|
|
151
|
+
this.initializeActivityFlow();
|
|
152
|
+
this.listenForElementClicks();
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Handles the reset of the config.
|
|
159
|
+
*
|
|
160
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
161
|
+
*/
|
|
162
|
+
clearGraph(options = {}) {
|
|
163
|
+
if (typeof options.onBefore === 'function') {
|
|
164
|
+
options.onBefore();
|
|
165
|
+
}
|
|
166
|
+
for (let activityCode in this.flow) {
|
|
167
|
+
const activity = this.flow[activityCode];
|
|
168
|
+
const node = activity.get('node');
|
|
169
|
+
if (node) {
|
|
170
|
+
node.remove();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (typeof options.onAfter === 'function') {
|
|
174
|
+
options.onAfter();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Listens for element click events within the JointJS paper.
|
|
180
|
+
*/
|
|
181
|
+
listenForElementClicks() {
|
|
182
|
+
this.paper.on('element:pointerdown', (elementView, event) => {
|
|
183
|
+
this.onActivityClicked(elementView);
|
|
184
|
+
contextComponentCallback(this, 'onActivityClicked', elementView, event);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Initializes the custom JointJS shapes used in the activity flow.
|
|
190
|
+
*/
|
|
191
|
+
initializeActivityJointModel() {
|
|
192
|
+
joint.shapes.fleetbase = {};
|
|
193
|
+
joint.shapes.fleetbase.Activity = joint.shapes.standard.Rectangle.define(
|
|
194
|
+
'fleetbase.Activity',
|
|
195
|
+
{
|
|
196
|
+
attrs: {
|
|
197
|
+
rect: { stroke: 'none', fillOpacity: 0 },
|
|
198
|
+
text: {
|
|
199
|
+
textVerticalAnchor: 'middle',
|
|
200
|
+
textAnchor: 'middle',
|
|
201
|
+
refX: '50%',
|
|
202
|
+
refY: '50%',
|
|
203
|
+
fontSize: 14,
|
|
204
|
+
fill: '#333',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
markup: [
|
|
210
|
+
{
|
|
211
|
+
tagName: 'rect',
|
|
212
|
+
selector: 'body',
|
|
213
|
+
className: 'flow-activity',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
tagName: 'rect',
|
|
217
|
+
selector: 'pill',
|
|
218
|
+
className: 'flow-activity-status-pill',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
tagName: 'text',
|
|
222
|
+
selector: 'code',
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
tagName: 'text',
|
|
226
|
+
selector: 'status',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
tagName: 'text',
|
|
230
|
+
selector: 'details',
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Asynchronously saves the current state of the activity flow.
|
|
239
|
+
* @returns {Generator}
|
|
240
|
+
*/
|
|
241
|
+
@task *save() {
|
|
242
|
+
const flow = this.serializeFlow();
|
|
243
|
+
this.config.set('flow', flow);
|
|
244
|
+
yield this.config.save().then((config) => {
|
|
245
|
+
this.config = config;
|
|
246
|
+
this.initializeActivityFlow();
|
|
247
|
+
this.listenForElementClicks();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* If any context is provided then initialize the state.
|
|
253
|
+
*
|
|
254
|
+
* @memberof OrderConfigManagerCustomFieldsComponent
|
|
255
|
+
*/
|
|
256
|
+
initializeContext() {
|
|
257
|
+
later(
|
|
258
|
+
this,
|
|
259
|
+
() => {
|
|
260
|
+
const { context, contextModel } = this.args;
|
|
261
|
+
if (typeof context === 'string' && contextModel === 'activity') {
|
|
262
|
+
const contextActivity = Object.values(this.flow).find((activity) => activity.get('internalId') === context);
|
|
263
|
+
if (contextActivity) {
|
|
264
|
+
this.editActivity(contextActivity);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
300
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Serializes the current activity flow into a JSON-compatible format.
|
|
274
|
+
* @returns {Object} The serialized activity flow.
|
|
275
|
+
*/
|
|
276
|
+
serializeFlow() {
|
|
277
|
+
const serialized = {};
|
|
278
|
+
const keys = Object.keys(this.flow);
|
|
279
|
+
keys.forEach((key) => {
|
|
280
|
+
const activity = this.flow[key];
|
|
281
|
+
// remove node
|
|
282
|
+
activity.set('node', undefined);
|
|
283
|
+
// remove ids
|
|
284
|
+
activity.set('id', undefined);
|
|
285
|
+
activity.set('parentId', undefined);
|
|
286
|
+
// remove internal model
|
|
287
|
+
activity.set('_internalModel', undefined);
|
|
288
|
+
// map activities into id and code string
|
|
289
|
+
const activities = activity.get('activities');
|
|
290
|
+
activity.set(
|
|
291
|
+
'activities',
|
|
292
|
+
activities.map((_activity) => {
|
|
293
|
+
return _activity.get('code');
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
serialized[key] = activity.content;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return serialized;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Deserializes the incoming activity flow and reconstructs the activity graph.
|
|
304
|
+
* @param {Object} incomingFlow - The incoming serialized activity flow.
|
|
305
|
+
*/
|
|
306
|
+
deserializeFlow(incomingFlow) {
|
|
307
|
+
const deserializedFlow = {};
|
|
308
|
+
const keys = Object.keys(incomingFlow);
|
|
309
|
+
keys.forEach((key) => {
|
|
310
|
+
const activity = this.deserializeActivity(incomingFlow[key], incomingFlow);
|
|
311
|
+
deserializedFlow[activity.get('code')] = activity;
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
this.addDeserializedActivityToGraph(deserializedFlow.created);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Deserializes a single activity.
|
|
319
|
+
* @param {Object} activityObject - Serialized activity data.
|
|
320
|
+
* @param {Object} incomingFlow - The entire incoming serialized activity flow for reference.
|
|
321
|
+
* @returns {Object} Deserialized activity object.
|
|
322
|
+
*/
|
|
323
|
+
deserializeActivity(activityObject, incomingFlow) {
|
|
324
|
+
const activity = createFlowActivity(activityObject.code, activityObject.status, activityObject.details, activityObject.sequence, activityObject.color, {
|
|
325
|
+
key: activityObject.key,
|
|
326
|
+
logic: activityObject.logic ?? [],
|
|
327
|
+
events: activityObject.events ?? [],
|
|
328
|
+
entities: activityObject.entities ?? [],
|
|
329
|
+
actions: activityObject.actions ?? [],
|
|
330
|
+
require_pod: activityObject.require_pod ?? false,
|
|
331
|
+
pod_method: activityObject.pod_method ?? 'scan',
|
|
332
|
+
complete: activityObject.complete ?? false,
|
|
333
|
+
internalId: activityObject.internalId ?? generateUUID(),
|
|
334
|
+
});
|
|
335
|
+
const { activities } = activityObject;
|
|
336
|
+
if (isArray(activities)) {
|
|
337
|
+
activity.set(
|
|
338
|
+
'activities',
|
|
339
|
+
activities
|
|
340
|
+
.map((activityKey) => {
|
|
341
|
+
return this.deserializeActivity(incomingFlow[activityKey], incomingFlow);
|
|
342
|
+
})
|
|
343
|
+
.filter(Boolean)
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return activity;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Adds deserialized activities to the graph.
|
|
352
|
+
* @param {Object} activity - The activity to add to the graph.
|
|
353
|
+
*/
|
|
354
|
+
addDeserializedActivityToGraph(activity) {
|
|
355
|
+
const positionals = this.getActivityPositioning(activity);
|
|
356
|
+
const parentActivity = this.createActivityNode(activity, positionals);
|
|
357
|
+
const childActivities = activity.get('activities');
|
|
358
|
+
|
|
359
|
+
this.addActivityNodeToGraph(parentActivity);
|
|
360
|
+
this.addActivityNodeTools(parentActivity, positionals);
|
|
361
|
+
this.addChildActivities(parentActivity, childActivities);
|
|
362
|
+
this.repositionAllActivities();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Recursively adds child activities to a parent activity on the graph. It creates nodes for each child, adds them to the graph,
|
|
367
|
+
* and creates links from the parent to each child. It then calls itself to add any children of the current child activities.
|
|
368
|
+
* Finally, it repositions all child activities to maintain visual consistency.
|
|
369
|
+
*
|
|
370
|
+
* @param {Object} parentActivity - The parent activity to which child activities will be added.
|
|
371
|
+
* @param {Array} [childActivities=[]] - An array of child activity objects to be added. Defaults to an empty array.
|
|
372
|
+
*/
|
|
373
|
+
addChildActivities(parentActivity, childActivities = []) {
|
|
374
|
+
if (!isArray(childActivities)) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
childActivities.forEach((childActivityObject) => {
|
|
378
|
+
const childPositionals = this.getActivityPositioning(childActivityObject, parentActivity);
|
|
379
|
+
const childActivity = this.createActivityNode(childActivityObject, childPositionals);
|
|
380
|
+
childActivity.set('parentId', parentActivity.get('id'));
|
|
381
|
+
|
|
382
|
+
this.addActivityNodeToGraph(childActivity);
|
|
383
|
+
this.addActivityNodeTools(childActivity, childPositionals);
|
|
384
|
+
this.addLinkToGraph(parentActivity, childActivity);
|
|
385
|
+
this.addChildActivities(childActivity, childActivity.get('activities'));
|
|
386
|
+
});
|
|
387
|
+
this.repositionActivities(parentActivity);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Repositions all activities and their child activities.
|
|
392
|
+
*
|
|
393
|
+
* @memberof OrderConfigManagerActivityFlowComponent
|
|
394
|
+
*/
|
|
395
|
+
repositionAllActivities() {
|
|
396
|
+
const activities = Object.values(this.flow);
|
|
397
|
+
activities.forEach((parentActivity) => {
|
|
398
|
+
this.repositionActivities(parentActivity);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Creates and adds a link between a parent activity and a child activity on the graph.
|
|
404
|
+
*
|
|
405
|
+
* @param {Object} parentActivity - The activity object representing the source of the link.
|
|
406
|
+
* @param {Object} childActivity - The activity object representing the target of the link.
|
|
407
|
+
* @returns {Object} - The link object that has been added to the graph.
|
|
408
|
+
*/
|
|
409
|
+
addLinkToGraph(parentActivity, childActivity) {
|
|
410
|
+
const link = new joint.shapes.standard.Link({
|
|
411
|
+
source: { id: parentActivity.get('id') },
|
|
412
|
+
target: { id: childActivity.get('id') },
|
|
413
|
+
});
|
|
414
|
+
link.addTo(this.graph);
|
|
415
|
+
return link;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Handles activity clicks within the JointJS paper.
|
|
420
|
+
* @param {Object} elementView - The JointJS element view of the clicked activity.
|
|
421
|
+
*/
|
|
422
|
+
onActivityClicked(elementView) {
|
|
423
|
+
// Disable editing activity if core service
|
|
424
|
+
if (this.config.core_service) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const { model } = elementView;
|
|
428
|
+
const activity = this.getActivityById(model.id);
|
|
429
|
+
if (activity) {
|
|
430
|
+
const parentActivity = this.getActivityById(activity.get('parentId'));
|
|
431
|
+
this.editActivity(activity, parentActivity);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get the standard default activities which apply to every order.
|
|
437
|
+
* @returns {Array}
|
|
438
|
+
*/
|
|
439
|
+
getDefaultActivities() {
|
|
440
|
+
const created = createFlowActivity('created', 'Order Created', 'New order was created.');
|
|
441
|
+
const dispatched = createFlowActivity('dispatched', 'Order Dispatched', 'Order has been dispatched.');
|
|
442
|
+
const started = createFlowActivity('started', 'Order Started', 'Order has been started');
|
|
443
|
+
return [created, [dispatched, started]];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Initializes the activity flow by either loading from configuration or creating a default flow.
|
|
448
|
+
*/
|
|
449
|
+
initializeActivityFlow() {
|
|
450
|
+
const hasFlow = Object.keys(this.config.flow).length > 0;
|
|
451
|
+
if (hasFlow) {
|
|
452
|
+
this.deserializeFlow(this.config.flow);
|
|
453
|
+
this.initializeContext();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const defaultActivities = this.getDefaultActivities();
|
|
458
|
+
this.addActivityToGraph(defaultActivities);
|
|
459
|
+
this.initializeContext();
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Adds multiple activities to the graph when provided as an array.
|
|
464
|
+
* @param {Array} activities - An array of activities to be added sequentially.
|
|
465
|
+
*/
|
|
466
|
+
addMultipleLinearActivities(activities = []) {
|
|
467
|
+
if (!isArray(activities)) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
let lastActivity = null;
|
|
472
|
+
activities.forEach((activityObject, index) => {
|
|
473
|
+
if (index > 0 && lastActivity) {
|
|
474
|
+
if (isArray(activityObject)) {
|
|
475
|
+
let lastChildActivity = null;
|
|
476
|
+
return activityObject.forEach((childActivityObject, childIndex) => {
|
|
477
|
+
if (childIndex > 0 && lastChildActivity) {
|
|
478
|
+
console.log('[lastChildActivity]', lastChildActivity);
|
|
479
|
+
console.log('[childActivityObject]', childActivityObject);
|
|
480
|
+
this.addNewLinkedActivity(lastChildActivity, childActivityObject);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
const firstChildActivity = this.addNewLinkedActivity(lastActivity, childActivityObject);
|
|
484
|
+
lastChildActivity = firstChildActivity;
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
this.addNewLinkedActivity(lastActivity, activityObject);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const firstActivity = this.addActivityToGraph(activityObject);
|
|
493
|
+
lastActivity = firstActivity;
|
|
494
|
+
});
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Adds a single activity to the graph, optionally using parent activity for positioning.
|
|
500
|
+
* @param {Object} activity - The activity to add.
|
|
501
|
+
* @param {Object} [parentActivity] - The parent activity to use for positioning.
|
|
502
|
+
* @returns {Object} The activity added to the graph.
|
|
503
|
+
*/
|
|
504
|
+
addActivityToGraph(activity, parentActivity) {
|
|
505
|
+
if (isArray(activity)) {
|
|
506
|
+
this.addMultipleLinearActivities(activity);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const positionals = this.getActivityPositioning(activity, parentActivity);
|
|
511
|
+
const newActivity = this.createActivityNode(activity, positionals);
|
|
512
|
+
if (parentActivity) {
|
|
513
|
+
this.repositionActivities(parentActivity);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
this.addActivityNodeToGraph(newActivity);
|
|
517
|
+
this.addActivityNodeTools(newActivity, positionals);
|
|
518
|
+
|
|
519
|
+
return activity;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Adds an activity node to the JointJS graph.
|
|
524
|
+
* @param {Object} activity - The activity whose node is to be added.
|
|
525
|
+
* @returns {Object} The activity added to the graph.
|
|
526
|
+
*/
|
|
527
|
+
addActivityNodeToGraph(activity) {
|
|
528
|
+
const activityNode = activity.get('node');
|
|
529
|
+
if (activityNode) {
|
|
530
|
+
activityNode.addTo(this.graph);
|
|
531
|
+
}
|
|
532
|
+
this.addActivityToFlowMap(activity);
|
|
533
|
+
return activity;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Adds the activity to the internal flow mapping.
|
|
538
|
+
* @param {Object} activity - The activity to add to the flow map.
|
|
539
|
+
* @returns {Object} The updated flow map.
|
|
540
|
+
*/
|
|
541
|
+
addActivityToFlowMap(activity) {
|
|
542
|
+
this.flow = {
|
|
543
|
+
...this.flow,
|
|
544
|
+
[activity.get('code')]: activity,
|
|
545
|
+
};
|
|
546
|
+
return this.flow;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Updates an existing activity in the flow map.
|
|
551
|
+
* @param {Object} activity - The activity to update in the flow map.
|
|
552
|
+
* @returns {Object} The updated flow map.
|
|
553
|
+
*/
|
|
554
|
+
updateActivityInFlowMap(activity) {
|
|
555
|
+
const flowClone = { ...this.flow };
|
|
556
|
+
flowClone[activity.get('code')] = activity;
|
|
557
|
+
this.flow = flowClone;
|
|
558
|
+
return this.flow;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Creates a new activity node based on the provided activity and positioning data.
|
|
563
|
+
* @param {Object} activity - The activity data.
|
|
564
|
+
* @param {Object} positionals - Positioning information for the activity node.
|
|
565
|
+
* @returns {Object} The created activity node.
|
|
566
|
+
*/
|
|
567
|
+
createActivityNode(activity, positionals = {}) {
|
|
568
|
+
const { width, height, x, y } = positionals;
|
|
569
|
+
const wrappedDetails = joint.util.breakText(activity.get('details'), { width });
|
|
570
|
+
const activityNode = new joint.shapes.fleetbase.Activity({
|
|
571
|
+
position: { x, y },
|
|
572
|
+
size: { width, height },
|
|
573
|
+
attrs: {
|
|
574
|
+
pill: {
|
|
575
|
+
ref: 'code',
|
|
576
|
+
refWidth: activity.get('code').length * 1.35,
|
|
577
|
+
refHeight: 5,
|
|
578
|
+
refX: -5,
|
|
579
|
+
refY: -2,
|
|
580
|
+
rx: 5,
|
|
581
|
+
ry: 5,
|
|
582
|
+
fill: '#374151',
|
|
583
|
+
stroke: '#374151',
|
|
584
|
+
strokeWidth: 1,
|
|
585
|
+
},
|
|
586
|
+
code: { ref: 'pill', text: activity.get('code'), fill: 'white', fontSize: 14, textAnchor: 'left', refX: 15, refY: 20, yAlignment: 'middle' },
|
|
587
|
+
status: { text: activity.get('status'), fill: 'white', fontSize: 14, fontWeight: 'bold', refY: 40, refX: 10, textAnchor: 'left' },
|
|
588
|
+
details: {
|
|
589
|
+
text: wrappedDetails,
|
|
590
|
+
fill: 'white',
|
|
591
|
+
refY: 60,
|
|
592
|
+
fontSize: 14,
|
|
593
|
+
refX: 10,
|
|
594
|
+
textAnchor: 'left',
|
|
595
|
+
},
|
|
596
|
+
body: { fill: activity.get('color'), stroke: '#374151', strokeWidth: 1, rx: 10, ry: 10 },
|
|
597
|
+
},
|
|
598
|
+
interactive: false,
|
|
599
|
+
activity: activity,
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
activity.set('id', activityNode.id);
|
|
603
|
+
activity.set('node', activityNode);
|
|
604
|
+
|
|
605
|
+
return activity;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Determines the positioning for an activity node.
|
|
610
|
+
* @param {Object} activity - The activity for which to determine positioning.
|
|
611
|
+
* @param {Object} [parentActivity] - The parent activity, if applicable.
|
|
612
|
+
* @returns {Object} Positioning information for the activity node.
|
|
613
|
+
*/
|
|
614
|
+
getActivityPositioning(activity, parentActivity) {
|
|
615
|
+
const parentActivities = parentActivity ? parentActivity.get('activities') : [];
|
|
616
|
+
const width = 250;
|
|
617
|
+
const baseHeight = 90;
|
|
618
|
+
const lineHeight = 10;
|
|
619
|
+
const wrappedDetails = joint.util.breakText(activity.get('details'), { width });
|
|
620
|
+
const numberOfLines = wrappedDetails.split('\n').length;
|
|
621
|
+
const height = baseHeight + lineHeight * (numberOfLines - 1);
|
|
622
|
+
let x = 100;
|
|
623
|
+
if (parentActivity) {
|
|
624
|
+
const parentActivityX = parentActivity.get('node').position().x;
|
|
625
|
+
x = parentActivityX + width + 100;
|
|
626
|
+
}
|
|
627
|
+
let y = this.paper.options.height / 2 - height / 2;
|
|
628
|
+
if (parentActivity) {
|
|
629
|
+
const spacing = 50;
|
|
630
|
+
|
|
631
|
+
// If there are already child activities, stack the new one below them
|
|
632
|
+
if (parentActivities.length > 0) {
|
|
633
|
+
const lastActivity = parentActivities[parentActivities.length - 1];
|
|
634
|
+
const lastActivityNode = lastActivity.get('node');
|
|
635
|
+
// only if last activity has a node if not then its not added or linked yet so skip
|
|
636
|
+
if (lastActivityNode) {
|
|
637
|
+
const lastActivityHeight = lastActivityNode.size().height;
|
|
638
|
+
const lastActivityY = lastActivityNode.position().y;
|
|
639
|
+
|
|
640
|
+
// Calculate new y position
|
|
641
|
+
y = lastActivityY + lastActivityHeight + spacing;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return {
|
|
647
|
+
width,
|
|
648
|
+
height,
|
|
649
|
+
x,
|
|
650
|
+
y,
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Adds interactive tools (like remove and add buttons) to an activity node.
|
|
656
|
+
* @param {Object} activity - The activity to which tools are to be added.
|
|
657
|
+
* @param {Object} positionals - Positioning information for the tools.
|
|
658
|
+
*/
|
|
659
|
+
addActivityNodeTools(activity, positionals = {}) {
|
|
660
|
+
const activityNode = activity.get('node');
|
|
661
|
+
if (!activityNode || this.config.core_service) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const { width } = positionals;
|
|
665
|
+
const removeButton = this.createActivityRemoveButton({ x: width });
|
|
666
|
+
const addButton = this.createAddActivityButton(activity, { x: width });
|
|
667
|
+
let tools = [];
|
|
668
|
+
|
|
669
|
+
if (activity.get('code') === 'created' || activity.get('code') === 'dispatched') {
|
|
670
|
+
tools = [];
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (activity.get('code') === 'started') {
|
|
674
|
+
tools = [addButton];
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (!this.immutableActivities.includes(activity.get('code'))) {
|
|
678
|
+
tools = [removeButton, addButton];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const activityNodeView = activityNode.findView(this.paper);
|
|
682
|
+
if (activityNodeView) {
|
|
683
|
+
activityNodeView.addTools(
|
|
684
|
+
new joint.dia.ToolsView({
|
|
685
|
+
tools,
|
|
686
|
+
})
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Creates a remove button tool for an activity node.
|
|
693
|
+
* @param {Object} props - Additional properties for the remove button tool.
|
|
694
|
+
* @returns {Object} The remove button tool.
|
|
695
|
+
*/
|
|
696
|
+
createActivityRemoveButton(props = {}) {
|
|
697
|
+
const removeButton = new joint.elementTools.Remove({
|
|
698
|
+
offset: { x: 0, y: -1 },
|
|
699
|
+
focusOpacity: 0.5,
|
|
700
|
+
rotate: true,
|
|
701
|
+
y: 0,
|
|
702
|
+
...props,
|
|
703
|
+
action: (evt, elementView, toolView) => {
|
|
704
|
+
elementView.model.remove({ ui: true, tool: toolView.cid });
|
|
705
|
+
this.removeActivityUsingElementView(elementView);
|
|
706
|
+
},
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
return removeButton;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Creates an 'Add' button tool for activity nodes, allowing users to add new linked activities.
|
|
714
|
+
*
|
|
715
|
+
* @param {Object} activity - The activity object to which the 'Add' button will be linked.
|
|
716
|
+
* @param {Object} [props={}] - Additional properties to customize the button's appearance and behavior.
|
|
717
|
+
* @returns {joint.elementTools.Button} - The configured 'Add' button tool.
|
|
718
|
+
*/
|
|
719
|
+
createAddActivityButton(activity, props = {}) {
|
|
720
|
+
const addButton = new joint.elementTools.Button({
|
|
721
|
+
markup: [
|
|
722
|
+
{
|
|
723
|
+
tagName: 'circle',
|
|
724
|
+
selector: 'button',
|
|
725
|
+
className: 'flow-activity-add-button',
|
|
726
|
+
attributes: {
|
|
727
|
+
r: 12,
|
|
728
|
+
fill: '#2563eb',
|
|
729
|
+
stroke: '#2563eb',
|
|
730
|
+
cursor: 'default',
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
tagName: 'path',
|
|
735
|
+
selector: 'icon',
|
|
736
|
+
attributes: {
|
|
737
|
+
d: 'M -4 0 L 4 0 M 0 -4 L 0 4',
|
|
738
|
+
fill: 'none',
|
|
739
|
+
stroke: '#FFFFFF',
|
|
740
|
+
strokeWidth: 2,
|
|
741
|
+
pointerEvents: 'none',
|
|
742
|
+
},
|
|
743
|
+
},
|
|
744
|
+
],
|
|
745
|
+
offset: { x: 2, y: 0 },
|
|
746
|
+
focusOpacity: 0.5,
|
|
747
|
+
rotate: true,
|
|
748
|
+
y: '50%',
|
|
749
|
+
...props,
|
|
750
|
+
action: () => {
|
|
751
|
+
this.createNewActivity(activity);
|
|
752
|
+
},
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
return addButton;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Handles the removal of an activity from the graph using its view.
|
|
760
|
+
*
|
|
761
|
+
* @param {joint.dia.ElementView} elementView - The JointJS view for the element to be removed.
|
|
762
|
+
*/
|
|
763
|
+
removeActivityUsingElementView(elementView) {
|
|
764
|
+
const deletedActivityId = elementView.model.id;
|
|
765
|
+
const deletedActivity = this.getActivityById(deletedActivityId);
|
|
766
|
+
if (deletedActivity) {
|
|
767
|
+
this.removeActivityFromFlow(deletedActivity);
|
|
768
|
+
const parentActivity = this.getActivityById(deletedActivity.get('parentId'));
|
|
769
|
+
if (parentActivity) {
|
|
770
|
+
this.removeActivityFromParentById(parentActivity, deletedActivityId);
|
|
771
|
+
this.repositionActivities(parentActivity);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Repositions all child activities in relation to the parent activity to maintain a consistent layout.
|
|
778
|
+
*
|
|
779
|
+
* @param {Object} parentActivity - The parent activity whose children will be repositioned.
|
|
780
|
+
*/
|
|
781
|
+
repositionActivities(parentActivity) {
|
|
782
|
+
const activities = parentActivity.get('activities').filter((activity) => activity.get('node'));
|
|
783
|
+
if (activities.length === 0) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const spacingY = 50; // Vertical spacing between activities
|
|
788
|
+
const parentY = parentActivity.get('node').position().y;
|
|
789
|
+
const parentHeight = parentActivity.get('node').size().height;
|
|
790
|
+
|
|
791
|
+
// Calculate the total height of all activities including spacing
|
|
792
|
+
const totalActivitiesHeight = activities.reduce((total, activity) => {
|
|
793
|
+
return total + activity.get('node').size().height + spacingY;
|
|
794
|
+
}, -spacingY); // Subtract one spacing to account for the first activity not needing a top margin
|
|
795
|
+
|
|
796
|
+
// The starting y position centers the block of activities around the parent's y position
|
|
797
|
+
let startY = parentY + parentHeight / 2 - totalActivitiesHeight / 2;
|
|
798
|
+
|
|
799
|
+
activities.forEach((activity, index) => {
|
|
800
|
+
const activityHeight = activity.get('node').size().height;
|
|
801
|
+
const yPos = startY + (activityHeight + spacingY) * index;
|
|
802
|
+
activity.get('node').position(activity.get('node').position().x, yPos);
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
// If there is only one activity, it should be aligned with the parent's y position
|
|
806
|
+
if (activities.length === 1) {
|
|
807
|
+
const singleActivity = activities[0];
|
|
808
|
+
singleActivity.get('node').position(singleActivity.get('node').position().x, parentY + parentHeight / 2 - singleActivity.get('node').size().height / 2);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Retrieves an activity by its ID from the current flow.
|
|
814
|
+
*
|
|
815
|
+
* @param {string} id - The unique identifier for the activity.
|
|
816
|
+
* @returns {Object|null} - The activity object if found, otherwise null.
|
|
817
|
+
*/
|
|
818
|
+
getActivityById(id) {
|
|
819
|
+
if (!id) {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
const activities = Object.values(this.flow);
|
|
824
|
+
return activities.find((activity) => {
|
|
825
|
+
return activity.get('id') === id;
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Removes an activity from its parent's list of activities by ID.
|
|
831
|
+
*
|
|
832
|
+
* @param {Object} parentActivity - The parent activity object.
|
|
833
|
+
* @param {string} id - The unique identifier of the child activity to be removed.
|
|
834
|
+
*/
|
|
835
|
+
removeActivityFromParentById(parentActivity, id) {
|
|
836
|
+
const activities = parentActivity.get('activities');
|
|
837
|
+
const filteredActivities = activities.filter((activity) => activity.get('id') !== id);
|
|
838
|
+
parentActivity.set('activities', filteredActivities);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Removes an activity from the current flow.
|
|
843
|
+
*
|
|
844
|
+
* @param {Object} activity - The activity object to be removed from the flow.
|
|
845
|
+
*/
|
|
846
|
+
removeActivityFromFlow(activity) {
|
|
847
|
+
const flowClone = { ...this.flow };
|
|
848
|
+
delete flowClone[activity.get('code')];
|
|
849
|
+
this.flow = flowClone;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Initializes the process to create a new activity, focusing the context panel on the new activity object.
|
|
854
|
+
*
|
|
855
|
+
* @param {Object} targetActivity - The activity object that will serve as the reference for the new activity.
|
|
856
|
+
* @returns {Object} - The newly created activity object.
|
|
857
|
+
*/
|
|
858
|
+
createNewActivity(targetActivity) {
|
|
859
|
+
const activity = createFlowActivity();
|
|
860
|
+
return this.editActivity(activity, targetActivity);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Initiates the editing process for a given activity, handling immutable activities accordingly.
|
|
865
|
+
*
|
|
866
|
+
* @param {Object} activity - The activity object to be edited.
|
|
867
|
+
* @param {Object} targetActivity - The target activity object that may be linked to the activity being edited.
|
|
868
|
+
*/
|
|
869
|
+
editActivity(activity, targetActivity) {
|
|
870
|
+
// if immutable do nothing
|
|
871
|
+
if (this.immutableActivities.includes(activity.get('code'))) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
contextComponentCallback(this, 'onContextChanged', this._createContextualActivity(activity));
|
|
876
|
+
this.contextPanel.focus(activity, 'editing', {
|
|
877
|
+
args: {
|
|
878
|
+
targetActivity,
|
|
879
|
+
onPressCancel: () => {
|
|
880
|
+
this.contextPanel.clear();
|
|
881
|
+
contextComponentCallback(this, 'onContextChanged', null);
|
|
882
|
+
},
|
|
883
|
+
onSave: (activity) => {
|
|
884
|
+
const existingActivity = this.flow[activity.get('code')];
|
|
885
|
+
|
|
886
|
+
// Check if the activity exists and if it's not the same instance being updated
|
|
887
|
+
if (existingActivity && existingActivity !== activity) {
|
|
888
|
+
this.notifications.warning(this.intl.t('fleet-ops.component.order-config-manager.activity-flow.edit-activity-unique-code-warning'));
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
contextComponentCallback(this, 'onContextChanged', null);
|
|
893
|
+
this.contextPanel.clear();
|
|
894
|
+
this.updateActivityInFlowMap(activity);
|
|
895
|
+
if (targetActivity) {
|
|
896
|
+
this.addNewLinkedActivity(targetActivity, activity);
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
},
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Creates a contextual activity using ObjectProxy.
|
|
905
|
+
*
|
|
906
|
+
* This function wraps the content of a given activity inside an ObjectProxy,
|
|
907
|
+
* allowing for proxy-based interaction with the activity's content. The function
|
|
908
|
+
* also sets the 'id' of the newly created proxy to the 'internalId' of the activity.
|
|
909
|
+
* This can be useful for tracking or referencing the original activity.
|
|
910
|
+
*
|
|
911
|
+
* @param {Object} activity - The activity object whose content needs to be proxied.
|
|
912
|
+
* @returns {ObjectProxy} The created contextual activity, which is an ObjectProxy instance with the same content as the original activity, but with a reassigned 'id'.
|
|
913
|
+
*/
|
|
914
|
+
_createContextualActivity(activity) {
|
|
915
|
+
const contextualActivity = ObjectProxy.create({ content: { ...activity.get('content') } });
|
|
916
|
+
// set persited id to id
|
|
917
|
+
contextualActivity.set('id', activity.get('internalId'));
|
|
918
|
+
return contextualActivity;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Adds a new linked activity to the target activity and updates the graph accordingly.
|
|
923
|
+
*
|
|
924
|
+
* @param {Object} targetActivity - The activity to which the new activity will be linked.
|
|
925
|
+
* @param {Object} activity - The new activity object to be added.
|
|
926
|
+
* @returns {Object} - The newly linked activity object.
|
|
927
|
+
*/
|
|
928
|
+
addNewLinkedActivity(targetActivity, activity) {
|
|
929
|
+
// Add the new activity at the top of the stack
|
|
930
|
+
const newActivity = this.addActivityToGraph(activity, targetActivity);
|
|
931
|
+
newActivity.set('parentId', targetActivity.get('id'));
|
|
932
|
+
|
|
933
|
+
// Check if target activity has this activity if not add it
|
|
934
|
+
if (!this.parentHasActivity(targetActivity, newActivity)) {
|
|
935
|
+
targetActivity.get('activities').unshiftObject(newActivity);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Update positions to stack activities vertically with spacing
|
|
939
|
+
this.repositionActivities(targetActivity);
|
|
940
|
+
|
|
941
|
+
// Link the new activity
|
|
942
|
+
const link = new joint.shapes.standard.Link({
|
|
943
|
+
source: { id: targetActivity.get('id') },
|
|
944
|
+
target: { id: newActivity.get('id') },
|
|
945
|
+
});
|
|
946
|
+
link.addTo(this.graph);
|
|
947
|
+
|
|
948
|
+
return newActivity;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Checks if a parent activity already contains a specific child activity.
|
|
953
|
+
*
|
|
954
|
+
* @param {Object} parentActivity - The parent activity object.
|
|
955
|
+
* @param {Object} childActivity - The child activity object to check for.
|
|
956
|
+
* @returns {boolean} - True if the parent has the child activity, false otherwise.
|
|
957
|
+
*/
|
|
958
|
+
parentHasActivity(parentActivity, childActivity) {
|
|
959
|
+
const activities = parentActivity.get('activities');
|
|
960
|
+
return activities.find((activity) => {
|
|
961
|
+
return childActivity.get('id') === activity.get('id');
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|