sgerp-frontend-lib 0.1.5 → 0.2.0

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.
Files changed (35) hide show
  1. package/dist/constants/timezones.d.ts +7 -2
  2. package/dist/constants/timezones.d.ts.map +1 -1
  3. package/dist/constants/timezones.js +17 -2
  4. package/dist/locales/locale_en.d.ts.map +1 -1
  5. package/dist/locales/locale_en.js +159 -0
  6. package/dist/locales/locale_ja.d.ts.map +1 -1
  7. package/dist/locales/locale_ja.js +112 -0
  8. package/dist/sgerp/index.d.ts +2 -2
  9. package/dist/sgerp/index.d.ts.map +1 -1
  10. package/dist/sgerp/index.js +8 -2
  11. package/dist/sgerp/simulation-logic/fetchUtils.d.ts +18 -0
  12. package/dist/sgerp/simulation-logic/fetchUtils.d.ts.map +1 -1
  13. package/dist/sgerp/simulation-logic/fetchUtils.js +194 -0
  14. package/dist/sgerp/simulation-logic/index.d.ts +4 -1
  15. package/dist/sgerp/simulation-logic/index.d.ts.map +1 -1
  16. package/dist/sgerp/simulation-logic/index.js +9 -1
  17. package/dist/sgerp/simulation-logic/vrpStatsCalculator.d.ts +52 -0
  18. package/dist/sgerp/simulation-logic/vrpStatsCalculator.d.ts.map +1 -0
  19. package/dist/sgerp/simulation-logic/vrpStatsCalculator.js +247 -0
  20. package/dist/sgerp/simulation-logic/vrpStatsUtils.d.ts +17 -0
  21. package/dist/sgerp/simulation-logic/vrpStatsUtils.d.ts.map +1 -0
  22. package/dist/sgerp/simulation-logic/vrpStatsUtils.js +48 -0
  23. package/dist/sgerp/utils/timezone.d.ts +15 -0
  24. package/dist/sgerp/utils/timezone.d.ts.map +1 -0
  25. package/dist/sgerp/utils/timezone.js +19 -0
  26. package/dist/sgerp/vrptoolbox-analyzer.d.ts +39 -0
  27. package/dist/sgerp/vrptoolbox-analyzer.d.ts.map +1 -0
  28. package/dist/sgerp/vrptoolbox-analyzer.js +210 -0
  29. package/dist/vrptoolbox/index.d.ts +1 -0
  30. package/dist/vrptoolbox/index.d.ts.map +1 -1
  31. package/dist/vrptoolbox/index.js +16 -0
  32. package/dist/vrptoolbox/vrptoolbox-utils.d.ts +133 -0
  33. package/dist/vrptoolbox/vrptoolbox-utils.d.ts.map +1 -0
  34. package/dist/vrptoolbox/vrptoolbox-utils.js +207 -0
  35. package/package.json +3 -1
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * Timezone utility functions
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getEffectiveTimezone = getEffectiveTimezone;
7
+ /**
8
+ * Get the effective timezone based on the current mode
9
+ * In VRPToolbox mode, uses the VRP timezone selector
10
+ * Otherwise, uses the project timezone (or falls back to UTC)
11
+ *
12
+ * @param mode - The current effective mode ('vrptoolbox' or other)
13
+ * @param vrpTimezone - The timezone selected in VRPToolbox mode
14
+ * @param projectTimezone - The project's configured timezone
15
+ * @returns The effective timezone string (e.g., 'UTC', 'Asia/Singapore')
16
+ */
17
+ function getEffectiveTimezone(mode, vrpTimezone, projectTimezone) {
18
+ return mode === 'vrptoolbox' ? vrpTimezone : (projectTimezone || 'UTC');
19
+ }
@@ -0,0 +1,39 @@
1
+ interface Vehicle {
2
+ agent_id: string;
3
+ characteristics?: Record<string, any>;
4
+ start_time?: number;
5
+ end_time?: number;
6
+ geofence_ids: any[];
7
+ assigned_nodes: any[];
8
+ labels?: string[];
9
+ capacity: number | Record<string, number>;
10
+ }
11
+ interface Node {
12
+ node_type: string;
13
+ vehicle_characteristics: Record<string, any>;
14
+ open_time_ts: number;
15
+ close_time_ts: number;
16
+ geofence_id: any[];
17
+ geofence_ids?: any[];
18
+ demand: number | Record<string, number>;
19
+ vehicle_labels?: {
20
+ or?: string[];
21
+ and?: string[];
22
+ };
23
+ booking_uid: string;
24
+ }
25
+ interface PipelineObject {
26
+ request: {
27
+ vehicles: Vehicle[];
28
+ nodes: Node[];
29
+ };
30
+ result: {
31
+ rejected_bookings: {
32
+ uid: string;
33
+ }[];
34
+ vehicles: Record<string, any>;
35
+ };
36
+ }
37
+ export declare function analyzePipelineObject(pipelineObject: PipelineObject): Record<string, any>;
38
+ export type { PipelineObject, Vehicle, Node };
39
+ //# sourceMappingURL=vrptoolbox-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vrptoolbox-analyzer.d.ts","sourceRoot":"","sources":["../../sgerplib/sgerp/vrptoolbox-analyzer.ts"],"names":[],"mappings":"AAAA,UAAU,OAAO;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,GAAG,EAAE,CAAC;IACpB,cAAc,EAAE,GAAG,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED,UAAU,IAAI;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,GAAG,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE;QACf,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,OAAO,EAAE;QACP,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,KAAK,EAAE,IAAI,EAAE,CAAC;KACf,CAAC;IACF,MAAM,EAAE;QACN,iBAAiB,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACrC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC/B,CAAC;CACH;AAwQD,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,GAC7B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkCrB;AAED,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzePipelineObject = analyzePipelineObject;
4
+ const DEFAULT_SEAT_TYPE = "passenger";
5
+ function getCapacity(value, defaultSeatType = DEFAULT_SEAT_TYPE) {
6
+ return typeof value === "object" ? value : { [DEFAULT_SEAT_TYPE]: value };
7
+ }
8
+ function checkCharacteristics(node, vehicle) {
9
+ const reasons = [];
10
+ const messages = [];
11
+ if (!vehicle.characteristics) {
12
+ return [reasons, messages];
13
+ }
14
+ const vehicleChars = vehicle.characteristics;
15
+ const agentId = vehicle.agent_id;
16
+ const nodeType = node.node_type;
17
+ Object.entries(node.vehicle_characteristics).forEach(([char, value]) => {
18
+ const vehicleVar = vehicleChars[char];
19
+ if (vehicleVar === undefined) {
20
+ reasons.push({
21
+ violation: `${char}_availability_violation`,
22
+ vehicle_value: vehicleVar,
23
+ char: char,
24
+ vehicle_characteristics: vehicleChars,
25
+ });
26
+ messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because characteristic ${char} is not available in vehicle ${JSON.stringify(vehicleChars)}`);
27
+ }
28
+ else if (typeof value === "object") {
29
+ const minVal = value.min;
30
+ const maxVal = value.max;
31
+ if (minVal !== undefined && vehicleVar < minVal) {
32
+ reasons.push({
33
+ violation: `${char}_min_violation`,
34
+ vehicle_value: vehicleVar,
35
+ required_min: minVal,
36
+ vehicle: agentId,
37
+ });
38
+ messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because of ${char}.min violation: ${vehicleVar} < ${minVal}`);
39
+ }
40
+ if (maxVal !== undefined && vehicleVar > maxVal) {
41
+ reasons.push({
42
+ violation: `${char}_max_violation`,
43
+ vehicle_value: vehicleVar,
44
+ required_max: maxVal,
45
+ vehicle: agentId,
46
+ });
47
+ messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because of ${char}.max violation: ${vehicleVar} > ${maxVal}`);
48
+ }
49
+ }
50
+ else if (value !== vehicleVar) {
51
+ reasons.push({
52
+ violation: `${char}_value_violation`,
53
+ required_value: value,
54
+ vehicle_value: vehicleVar,
55
+ });
56
+ messages.push(`can not be assigned to vehicle ${agentId} - ${char}_value_violation`);
57
+ }
58
+ });
59
+ return [reasons, messages];
60
+ }
61
+ function checkStartTimeEndTimeConstraints(node, vehicle) {
62
+ const reasons = [];
63
+ const messages = [];
64
+ const agentId = vehicle.agent_id;
65
+ const nodeType = node.node_type;
66
+ if (vehicle.start_time !== undefined) {
67
+ if (vehicle.start_time > node.close_time_ts) {
68
+ reasons.push({
69
+ violation: "start_time_violation",
70
+ node_close_time: node.close_time_ts,
71
+ vehicle_start_time: vehicle.start_time,
72
+ });
73
+ messages.push(`${nodeType} can not be assigned to vehicle ${agentId} - start_time_violation: ${vehicle.start_time} > ${node.close_time_ts}`);
74
+ }
75
+ }
76
+ if (vehicle.end_time !== undefined) {
77
+ if (vehicle.end_time < node.open_time_ts) {
78
+ reasons.push({
79
+ violation: "end_time_violation",
80
+ node_open_time: node.open_time_ts,
81
+ vehicle_end_time: vehicle.end_time,
82
+ });
83
+ messages.push(`${nodeType} can not be assigned to vehicle ${agentId} - end_time_violation: ${vehicle.end_time} < ${node.open_time_ts}`);
84
+ }
85
+ }
86
+ return [reasons, messages];
87
+ }
88
+ function checkGeofenceConstraints(node, vehicle) {
89
+ const reasons = [];
90
+ const messages = [];
91
+ const agentId = vehicle.agent_id;
92
+ if (node.geofence_ids === undefined && node.geofence_id) {
93
+ node.geofence_ids = [node.geofence_id];
94
+ }
95
+ if (node.geofence_ids && node.geofence_ids.length > 0 && node.geofence_ids[0] !== null) {
96
+ const vehicleGeofenceIds = new Set(vehicle.geofence_ids);
97
+ const nodeGeofenceIds = new Set(node.geofence_ids);
98
+ if (vehicleGeofenceIds.size > 0 &&
99
+ !Array.from(nodeGeofenceIds).some((id) => vehicleGeofenceIds.has(id))) {
100
+ reasons.push({
101
+ violation: "geofence_violation",
102
+ node_geofence_ids: node.geofence_ids,
103
+ vehicle_geofence_ids: vehicle.geofence_ids,
104
+ });
105
+ messages.push(`can not be assigned to vehicle ${agentId} - geofence violations: ${JSON.stringify([...vehicleGeofenceIds])} vs ${JSON.stringify([...nodeGeofenceIds])}`);
106
+ }
107
+ }
108
+ return [reasons, messages];
109
+ }
110
+ function checkVehicleAssignedNodes(node, vehicle) {
111
+ const reasons = [];
112
+ const messages = [];
113
+ const agentId = vehicle.agent_id;
114
+ if (vehicle.assigned_nodes.length > 0) {
115
+ reasons.push({
116
+ violation: "vehicle_has_assigned_nodes",
117
+ });
118
+ messages.push(`vehicle ${agentId} has assigned nodes. Possibly change the first solution strategy to 16 or clear vehicles`);
119
+ }
120
+ return [reasons, messages];
121
+ }
122
+ function checkVehicleLabels(node, vehicle) {
123
+ const reasons = [];
124
+ const messages = [];
125
+ const agentId = vehicle.agent_id;
126
+ const nodeLabels = node.vehicle_labels;
127
+ if (!nodeLabels) {
128
+ return [reasons, messages];
129
+ }
130
+ const labelOrValues = new Set(nodeLabels.or || []);
131
+ const labelAndValues = new Set(nodeLabels.and || []);
132
+ const vehicleLabels = new Set(vehicle.labels || []);
133
+ if (labelOrValues.size > 0) {
134
+ if (!Array.from(labelOrValues).some((label) => vehicleLabels.has(label))) {
135
+ reasons.push({
136
+ violation: "vehicle and booking labels do not satisfy each other",
137
+ });
138
+ messages.push(`vehicle ${agentId} has labels ${JSON.stringify([...vehicleLabels])}. Booking: ${JSON.stringify(nodeLabels)}`);
139
+ }
140
+ }
141
+ if (labelAndValues.size > 0) {
142
+ if (!Array.from(labelAndValues).every((label) => vehicleLabels.has(label))) {
143
+ reasons.push({
144
+ violation: "vehicle and booking labels do not satisfy each other",
145
+ });
146
+ messages.push(`vehicle ${agentId} has labels ${JSON.stringify([...vehicleLabels])}. Booking: ${JSON.stringify(nodeLabels)}`);
147
+ }
148
+ }
149
+ return [reasons, messages];
150
+ }
151
+ function analyzeVehicles(nodeGroup, vehicles) {
152
+ const possibleReasons = {
153
+ messages: [],
154
+ impossibleVehicles: new Set(),
155
+ comments: [],
156
+ };
157
+ nodeGroup.forEach((node) => {
158
+ vehicles.forEach((vehicle) => {
159
+ const [reasons1, messages1] = checkCharacteristics(node, vehicle);
160
+ const [reasons2, messages2] = checkStartTimeEndTimeConstraints(node, vehicle);
161
+ const [reasons3, messages3] = checkGeofenceConstraints(node, vehicle);
162
+ const [reasons4, messages4] = checkVehicleAssignedNodes(node, vehicle);
163
+ const [reasons5, messages5] = checkVehicleLabels(node, vehicle);
164
+ if (reasons1.length > 0 ||
165
+ reasons2.length > 0 ||
166
+ reasons3.length > 0 ||
167
+ reasons4.length > 0 ||
168
+ reasons5.length > 0) {
169
+ possibleReasons.messages.push(...messages1, ...messages2, ...messages3, ...messages4, ...messages5);
170
+ possibleReasons.impossibleVehicles.add(vehicle.agent_id);
171
+ }
172
+ });
173
+ });
174
+ possibleReasons.impossibleVehicles = Array.from(possibleReasons.impossibleVehicles);
175
+ possibleReasons.impossibleVehiclesCount =
176
+ possibleReasons.impossibleVehicles.length;
177
+ if (possibleReasons.impossibleVehiclesCount === vehicles.length) {
178
+ possibleReasons.comments.push("all vehicles are impossible");
179
+ }
180
+ else {
181
+ const possibleVehicles = vehicles
182
+ .filter((vehicle) => !possibleReasons.impossibleVehicles.includes(vehicle.agent_id))
183
+ .map((vehicle) => vehicle.agent_id);
184
+ possibleReasons.comments.push({ possibleVehicles });
185
+ }
186
+ return possibleReasons;
187
+ }
188
+ function analyzePipelineObject(pipelineObject) {
189
+ const { vehicles, nodes } = pipelineObject.request;
190
+ const { rejected_bookings, vehicles: resultedVehicles } = pipelineObject.result;
191
+ const rejectedUids = new Set(rejected_bookings.map((b) => b.uid));
192
+ const rejectedNodes = nodes.filter((node) => rejectedUids.has(node.booking_uid));
193
+ const emptyVehicleUids = new Set(Object.entries(resultedVehicles)
194
+ .filter(([_, item]) => !item)
195
+ .map(([key, _]) => key));
196
+ const emptyVehicles = vehicles; // .filter(v => emptyVehicleUids.has(v.agent_id));
197
+ const possibleReasons = {};
198
+ const bookingNodes = {};
199
+ rejectedNodes.forEach((node) => {
200
+ const { booking_uid } = node;
201
+ if (!bookingNodes[booking_uid]) {
202
+ bookingNodes[booking_uid] = [];
203
+ }
204
+ bookingNodes[booking_uid].push(node);
205
+ });
206
+ Object.entries(bookingNodes).forEach(([booking_uid, node_group]) => {
207
+ possibleReasons[booking_uid] = analyzeVehicles(node_group, emptyVehicles);
208
+ });
209
+ return possibleReasons;
210
+ }
@@ -3,4 +3,5 @@
3
3
  */
4
4
  export { OptimizationJobCollection } from './collection';
5
5
  export type { OptimizationJob, VRPToolboxListResponse, VRPToolboxMeta, } from './types/job';
6
+ export * from './vrptoolbox-utils';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,cAAc,oBAAoB,CAAC"}
@@ -2,7 +2,23 @@
2
2
  /**
3
3
  * VRP Toolbox library exports
4
4
  */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
5
19
  Object.defineProperty(exports, "__esModule", { value: true });
6
20
  exports.OptimizationJobCollection = void 0;
7
21
  var collection_1 = require("./collection");
8
22
  Object.defineProperty(exports, "OptimizationJobCollection", { enumerable: true, get: function () { return collection_1.OptimizationJobCollection; } });
23
+ // VRPToolbox data processing utilities
24
+ __exportStar(require("./vrptoolbox-utils"), exports);
@@ -0,0 +1,133 @@
1
+ /**
2
+ * VRPToolbox data processing utilities
3
+ * Converts VRPToolbox API response to simulation-like state for visualization
4
+ */
5
+ export interface VRPSimulation {
6
+ id: number;
7
+ name: string;
8
+ project_id: number;
9
+ stateless_api_request_data?: any;
10
+ result?: any;
11
+ }
12
+ export interface VRPVehicle {
13
+ id: number;
14
+ agent_id: string;
15
+ simulation_id: number;
16
+ registration_number?: string;
17
+ color?: string;
18
+ assigned_nodes: string[];
19
+ completed_nodes: string[];
20
+ capacity?: any;
21
+ shift_start?: string;
22
+ shift_end?: string;
23
+ start_lat?: number;
24
+ start_lon?: number;
25
+ end_lat?: number;
26
+ end_lon?: number;
27
+ vehicle_type_id?: number;
28
+ routing_engine_settings?: any;
29
+ is_active?: boolean;
30
+ [key: string]: any;
31
+ }
32
+ export interface VRPNode {
33
+ id: number;
34
+ uid: string;
35
+ simulation_id: number;
36
+ booking_id?: number;
37
+ booking_uid?: string;
38
+ lat: number;
39
+ lon: number;
40
+ node_type: string;
41
+ status: string;
42
+ scheduled_ts?: string | null;
43
+ assigned_vehicle_id?: number | null;
44
+ location_name?: string;
45
+ display_name?: string;
46
+ service_time?: number;
47
+ time_window_start?: string;
48
+ time_window_end?: string;
49
+ priority?: number;
50
+ [key: string]: any;
51
+ }
52
+ export interface VRPBooking {
53
+ id: number;
54
+ uid: string;
55
+ simulation_id: number;
56
+ pickup_lat?: number;
57
+ pickup_lon?: number;
58
+ dropoff_lat?: number;
59
+ dropoff_lon?: number;
60
+ pickup_location_name?: string;
61
+ dropoff_location_name?: string;
62
+ passenger_count?: number;
63
+ status?: string;
64
+ assigned_vehicle_id?: number | null;
65
+ [key: string]: any;
66
+ }
67
+ export interface SimulationLiveUpdateData {
68
+ simulation: VRPSimulation;
69
+ vehicles: VRPVehicle[];
70
+ nodes: VRPNode[];
71
+ bookings: VRPBooking[];
72
+ vehicleRoutes: Map<number, any>;
73
+ nodesByVehicle: Map<number, VRPNode[]>;
74
+ bookingsByVehicle: Map<number, VRPBooking[]>;
75
+ vehicleIndex: Map<number, VRPVehicle>;
76
+ nodeIndex: Map<number, VRPNode>;
77
+ bookingIndex: Map<number, VRPBooking>;
78
+ }
79
+ export interface VRPToolboxPayload {
80
+ vehicles: Array<{
81
+ agent_id: string;
82
+ assigned_nodes?: any[];
83
+ completed_nodes?: any[];
84
+ routing_engine?: any;
85
+ [key: string]: any;
86
+ }>;
87
+ nodes: Array<{
88
+ uid: string;
89
+ booking_uid?: string;
90
+ lat: number;
91
+ lon: number;
92
+ node_type?: string;
93
+ [key: string]: any;
94
+ }>;
95
+ engine_settings?: {
96
+ routing_engine?: any;
97
+ [key: string]: any;
98
+ };
99
+ }
100
+ export interface VRPToolboxResult {
101
+ vehicles: {
102
+ [vehicleAgentId: string]: Array<{
103
+ uid: string;
104
+ scheduled_ts?: string;
105
+ [key: string]: any;
106
+ }>;
107
+ };
108
+ }
109
+ export interface VRPToolboxResponse {
110
+ payload: VRPToolboxPayload;
111
+ result: VRPToolboxResult;
112
+ }
113
+ export interface VRPToolboxSimulationState {
114
+ simulation: VRPSimulation;
115
+ vehicles: VRPVehicle[];
116
+ nodes: VRPNode[];
117
+ bookings: VRPBooking[];
118
+ liveUpdateData: SimulationLiveUpdateData;
119
+ }
120
+ /**
121
+ * Fetches VRPToolbox job result with payload
122
+ */
123
+ export declare function fetchVRPToolboxJobData(vrpServer: string, taskId: string): Promise<VRPToolboxResponse>;
124
+ /**
125
+ * Converts VRPToolbox response to simulation-like state
126
+ * Based on the logic from dashviewer's createStateFromCommuteOffers
127
+ */
128
+ export declare function convertVRPToolboxToSimulationState(data: VRPToolboxResponse, taskId: string): VRPToolboxSimulationState;
129
+ /**
130
+ * Fetches and processes VRPToolbox data into simulation state
131
+ */
132
+ export declare function loadVRPToolboxSimulation(vrpServer: string, taskId: string): Promise<VRPToolboxSimulationState>;
133
+ //# sourceMappingURL=vrptoolbox-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vrptoolbox-utils.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/vrptoolbox-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ /**
3
+ * VRPToolbox data processing utilities
4
+ * Converts VRPToolbox API response to simulation-like state for visualization
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.fetchVRPToolboxJobData = fetchVRPToolboxJobData;
8
+ exports.convertVRPToolboxToSimulationState = convertVRPToolboxToSimulationState;
9
+ exports.loadVRPToolboxSimulation = loadVRPToolboxSimulation;
10
+ /**
11
+ * Fetches VRPToolbox job result with payload
12
+ */
13
+ async function fetchVRPToolboxJobData(vrpServer, taskId) {
14
+ const url = `${vrpServer}/jobs/${taskId}/result_with_payload`;
15
+ const response = await fetch(url);
16
+ if (!response.ok) {
17
+ throw new Error(`Failed to fetch VRPToolbox data: ${response.statusText}`);
18
+ }
19
+ return await response.json();
20
+ }
21
+ /**
22
+ * Converts VRPToolbox response to simulation-like state
23
+ * Based on the logic from dashviewer's createStateFromCommuteOffers
24
+ */
25
+ function convertVRPToolboxToSimulationState(data, taskId) {
26
+ const { payload, result } = data;
27
+ // Create assigned nodes cache from result
28
+ const assignedNodesCache = {};
29
+ Object.entries(result.vehicles).forEach(([vehicleAgentId, vehicleNodes]) => {
30
+ vehicleNodes.forEach((node) => {
31
+ assignedNodesCache[node.uid] = Object.assign(Object.assign({}, node), { assigned_vehicle_id: vehicleAgentId, status: 'assigned' });
32
+ });
33
+ });
34
+ // Process vehicles
35
+ const vehicles = payload.vehicles.map((vehicle) => {
36
+ var _a, _b;
37
+ const assignedNodes = vehicle.assigned_nodes || [];
38
+ const completedNodes = vehicle.completed_nodes || [];
39
+ // Map assigned node UIDs from the result
40
+ const assignedNodeIds = ((_a = result.vehicles[vehicle.agent_id]) === null || _a === void 0 ? void 0 : _a.map((n) => n.uid)) || [];
41
+ return {
42
+ id: parseInt(vehicle.agent_id),
43
+ agent_id: vehicle.agent_id,
44
+ simulation_id: parseInt(taskId),
45
+ assigned_nodes: assignedNodeIds,
46
+ completed_nodes: completedNodes.map((n) => n.uid),
47
+ routing_engine_settings: vehicle.routing_engine ||
48
+ ((_b = payload.engine_settings) === null || _b === void 0 ? void 0 : _b.routing_engine) ||
49
+ { routing_engine_name: 'osrm' },
50
+ // Map other vehicle fields
51
+ registration_number: vehicle.registration_number || vehicle.agent_id,
52
+ color: vehicle.color || '#4A90E2',
53
+ capacity: vehicle.capacity || {},
54
+ shift_start: vehicle.shift_start,
55
+ shift_end: vehicle.shift_end,
56
+ start_lat: vehicle.start_lat,
57
+ start_lon: vehicle.start_lon,
58
+ end_lat: vehicle.end_lat,
59
+ end_lon: vehicle.end_lon,
60
+ // Add other required vehicle fields with defaults
61
+ vehicle_type_id: vehicle.vehicle_type_id || 1,
62
+ is_active: true,
63
+ };
64
+ });
65
+ // Process nodes
66
+ const nodes = [];
67
+ const bookingsMap = new Map();
68
+ payload.nodes.forEach((node) => {
69
+ const assignedData = assignedNodesCache[node.uid];
70
+ const processedNode = {
71
+ id: parseInt(node.uid),
72
+ uid: node.uid,
73
+ simulation_id: parseInt(taskId),
74
+ booking_id: parseInt(node.booking_uid || '0'),
75
+ booking_uid: node.booking_uid,
76
+ lat: node.lat,
77
+ lon: node.lon,
78
+ node_type: node.node_type || 'pickup',
79
+ status: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.status) || 'rejected_by_system',
80
+ scheduled_ts: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.scheduled_ts) || null,
81
+ assigned_vehicle_id: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.assigned_vehicle_id) ?
82
+ parseInt(assignedData.assigned_vehicle_id) : null,
83
+ // Map other node fields
84
+ location_name: node.location_name || node.display_name || '',
85
+ display_name: node.display_name || '',
86
+ service_time: node.service_time || 0,
87
+ time_window_start: node.time_window_start,
88
+ time_window_end: node.time_window_end,
89
+ priority: node.priority || 1,
90
+ };
91
+ nodes.push(processedNode);
92
+ // Create or update booking
93
+ if (node.booking_uid) {
94
+ if (!bookingsMap.has(node.booking_uid)) {
95
+ bookingsMap.set(node.booking_uid, {
96
+ id: parseInt(node.booking_uid),
97
+ uid: node.booking_uid,
98
+ simulation_id: parseInt(taskId),
99
+ pickup_lat: node.node_type === 'pickup' ? node.lat : 0,
100
+ pickup_lon: node.node_type === 'pickup' ? node.lon : 0,
101
+ dropoff_lat: node.node_type === 'dropoff' ? node.lat : 0,
102
+ dropoff_lon: node.node_type === 'dropoff' ? node.lon : 0,
103
+ pickup_location_name: '',
104
+ dropoff_location_name: '',
105
+ passenger_count: 1,
106
+ status: assignedData ? 'assigned' : 'unassigned',
107
+ assigned_vehicle_id: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.assigned_vehicle_id) ?
108
+ parseInt(assignedData.assigned_vehicle_id) : null,
109
+ });
110
+ }
111
+ else {
112
+ const booking = bookingsMap.get(node.booking_uid);
113
+ if (node.node_type === 'pickup') {
114
+ booking.pickup_lat = node.lat;
115
+ booking.pickup_lon = node.lon;
116
+ booking.pickup_location_name = node.location_name || '';
117
+ }
118
+ else if (node.node_type === 'dropoff') {
119
+ booking.dropoff_lat = node.lat;
120
+ booking.dropoff_lon = node.lon;
121
+ booking.dropoff_location_name = node.location_name || '';
122
+ }
123
+ }
124
+ }
125
+ });
126
+ // Add partial route nodes that weren't in the main nodes list
127
+ payload.vehicles.forEach((vehicle) => {
128
+ const assignedNodes = vehicle.assigned_nodes || [];
129
+ assignedNodes.forEach((vehicleNode) => {
130
+ const nodeId = vehicleNode.uid;
131
+ if (!nodes.find(n => n.uid === nodeId)) {
132
+ const assignedData = assignedNodesCache[nodeId];
133
+ nodes.push({
134
+ id: parseInt(nodeId),
135
+ uid: nodeId,
136
+ simulation_id: parseInt(taskId),
137
+ booking_id: parseInt(vehicleNode.booking_uid || '0'),
138
+ booking_uid: vehicleNode.booking_uid,
139
+ lat: vehicleNode.lat || 0,
140
+ lon: vehicleNode.lon || 0,
141
+ node_type: vehicleNode.node_type || 'pickup',
142
+ status: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.status) || 'assigned',
143
+ scheduled_ts: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.scheduled_ts) || null,
144
+ assigned_vehicle_id: vehicle.agent_id ? parseInt(vehicle.agent_id) : null,
145
+ location_name: vehicleNode.location_name || '',
146
+ display_name: vehicleNode.display_name || '',
147
+ service_time: vehicleNode.service_time || 0,
148
+ priority: vehicleNode.priority || 1,
149
+ });
150
+ }
151
+ });
152
+ });
153
+ const bookings = Array.from(bookingsMap.values());
154
+ // Create simulation object
155
+ const simulation = {
156
+ id: parseInt(taskId),
157
+ name: `VRPToolbox Job ${taskId}`,
158
+ project_id: 0,
159
+ stateless_api_request_data: payload,
160
+ result: result,
161
+ };
162
+ // Create live update data structure
163
+ const liveUpdateData = {
164
+ simulation,
165
+ vehicles,
166
+ nodes,
167
+ bookings,
168
+ vehicleRoutes: new Map(),
169
+ nodesByVehicle: new Map(),
170
+ bookingsByVehicle: new Map(),
171
+ vehicleIndex: new Map(vehicles.map(v => [v.id, v])),
172
+ nodeIndex: new Map(nodes.map(n => [n.id, n])),
173
+ bookingIndex: new Map(bookings.map(b => [b.id, b])),
174
+ };
175
+ // Group nodes by vehicle
176
+ nodes.forEach(node => {
177
+ if (node.assigned_vehicle_id) {
178
+ if (!liveUpdateData.nodesByVehicle.has(node.assigned_vehicle_id)) {
179
+ liveUpdateData.nodesByVehicle.set(node.assigned_vehicle_id, []);
180
+ }
181
+ liveUpdateData.nodesByVehicle.get(node.assigned_vehicle_id).push(node);
182
+ }
183
+ });
184
+ // Group bookings by vehicle
185
+ bookings.forEach(booking => {
186
+ if (booking.assigned_vehicle_id) {
187
+ if (!liveUpdateData.bookingsByVehicle.has(booking.assigned_vehicle_id)) {
188
+ liveUpdateData.bookingsByVehicle.set(booking.assigned_vehicle_id, []);
189
+ }
190
+ liveUpdateData.bookingsByVehicle.get(booking.assigned_vehicle_id).push(booking);
191
+ }
192
+ });
193
+ return {
194
+ simulation,
195
+ vehicles,
196
+ nodes,
197
+ bookings,
198
+ liveUpdateData,
199
+ };
200
+ }
201
+ /**
202
+ * Fetches and processes VRPToolbox data into simulation state
203
+ */
204
+ async function loadVRPToolboxSimulation(vrpServer, taskId) {
205
+ const data = await fetchVRPToolboxJobData(vrpServer, taskId);
206
+ return convertVRPToolboxToSimulationState(data, taskId);
207
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sgerp-frontend-lib",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "TypeScript/React library for interacting with the SGERP API, providing client SDK, Backbone.js-style Collections, and pre-built React components",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -95,6 +95,8 @@
95
95
  "react-day-picker": "^9.11.1",
96
96
  "react-dom": "^19.0.1",
97
97
  "react-markdown": "^10.1.0",
98
+ "react-resizable-panels": "^3.0.6",
99
+ "recharts": "^2.15.4",
98
100
  "rehype-highlight": "^7.0.2",
99
101
  "rehype-slug": "^6.0.0",
100
102
  "remark-gfm": "^4.0.1",