@burdenoff/microfe-movethewheels 2026.1031.2 → 2026.1031.4
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/dist/MoveTheWheelsRoot.js +121 -104
- package/dist/MoveTheWheelsRoutes.js +142 -133
- package/dist/components/DocumentsCard.js +11 -11
- package/dist/components/ProofOfDeliveryCard.js +13 -13
- package/dist/components/ShipmentRiskDialog.js +24 -24
- package/dist/components/ShippingQuoteResults.js +46 -46
- package/dist/components/TrackingAlertList.js +17 -17
- package/dist/generated/tracking-quality-operations.d.ts +140 -0
- package/dist/hooks/useEntityImport.js +68 -0
- package/dist/hooks/useOrderDispatch.js +17 -17
- package/dist/movethewheels/hooks/useEntityImport.d.ts +19 -0
- package/dist/movethewheels/pages/ImportExportPage.d.ts +9 -0
- package/dist/movethewheels/pages/SettingsPage.d.ts +1 -0
- package/dist/movethewheels/providers/ModuleSettingsProvider.d.ts +17 -0
- package/dist/movethewheels/utils/entityImport.d.ts +109 -0
- package/dist/movethewheels/utils/formatters.d.ts +23 -3
- package/dist/movethewheels/utils/moduleSettings.d.ts +52 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/arrow-down-up.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/bell.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js +30 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/file-up.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/key-round.js +14 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/plug.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/rotate-ccw.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/settings.js +13 -0
- package/dist/pages/AnalyticsPage.js +27 -27
- package/dist/pages/CreateOrderPage.js +340 -317
- package/dist/pages/CustomerDetailsPage.js +246 -246
- package/dist/pages/CustomersPage.js +88 -79
- package/dist/pages/DashboardPage.js +24 -24
- package/dist/pages/DeliveryCapturePage.js +74 -74
- package/dist/pages/DriverDetailsPage.js +337 -337
- package/dist/pages/DriversPage.js +119 -110
- package/dist/pages/FinancePage.js +26 -26
- package/dist/pages/ImportExportPage.js +435 -0
- package/dist/pages/InventoryPage.js +28 -28
- package/dist/pages/LiveTrackingPage.js +108 -108
- package/dist/pages/MarketplacePage.js +44 -44
- package/dist/pages/OrderDetailsPage.js +306 -306
- package/dist/pages/OrdersListPage.js +27 -27
- package/dist/pages/ProductDetailsPage.js +89 -89
- package/dist/pages/ProductsPage.js +86 -77
- package/dist/pages/RouteDetailsPage.js +282 -285
- package/dist/pages/RoutesPage.js +78 -78
- package/dist/pages/SettingsPage.js +459 -0
- package/dist/pages/TrackingPage.js +41 -41
- package/dist/pages/VehicleDetailsPage.js +207 -207
- package/dist/pages/VehiclesPage.js +100 -90
- package/dist/pages/WarehouseDetailsPage.js +132 -132
- package/dist/pages/WarehousesPage.js +97 -88
- package/dist/providers/ModuleSettingsProvider.js +74 -0
- package/dist/utils/entityImport.js +73 -0
- package/dist/utils/formatters.js +53 -26
- package/dist/utils/moduleSettings.js +132 -0
- package/package.json +4 -2
- package/src/generated/tracking-quality-operations.ts +184 -0
- package/src/movethewheels/MoveTheWheelsRoot.tsx +22 -3
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +13 -0
- package/src/movethewheels/hooks/useEntityImport.ts +108 -0
- package/src/movethewheels/pages/CreateOrderPage.tsx +38 -6
- package/src/movethewheels/pages/CustomersPage.tsx +6 -1
- package/src/movethewheels/pages/DriversPage.tsx +6 -0
- package/src/movethewheels/pages/ImportExportPage.tsx +483 -0
- package/src/movethewheels/pages/ProductsPage.tsx +16 -3
- package/src/movethewheels/pages/RouteDetailsPage.tsx +3 -6
- package/src/movethewheels/pages/RoutesPage.tsx +2 -2
- package/src/movethewheels/pages/SettingsPage.tsx +516 -0
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +4 -2
- package/src/movethewheels/pages/VehiclesPage.tsx +8 -1
- package/src/movethewheels/pages/WarehousesPage.tsx +6 -1
- package/src/movethewheels/providers/ModuleSettingsProvider.tsx +133 -0
- package/src/movethewheels/utils/entityImport.ts +239 -0
- package/src/movethewheels/utils/formatters.ts +69 -10
- package/src/movethewheels/utils/moduleSettings.ts +224 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
function e(e = "") {
|
|
2
|
+
return {
|
|
3
|
+
workspaceId: e,
|
|
4
|
+
defaultCurrency: "USD",
|
|
5
|
+
distanceUnit: "KM",
|
|
6
|
+
weightUnit: "KG",
|
|
7
|
+
timezone: null,
|
|
8
|
+
defaultOrderPriority: "MEDIUM",
|
|
9
|
+
defaultDeliveryWindowHours: 24,
|
|
10
|
+
isCustomized: !1,
|
|
11
|
+
updatedAt: null,
|
|
12
|
+
updatedBy: null
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var t = "\n workspaceId\n defaultCurrency\n distanceUnit\n weightUnit\n timezone\n defaultOrderPriority\n defaultDeliveryWindowHours\n isCustomized\n updatedAt\n updatedBy\n", n = `
|
|
16
|
+
query MtwModuleSettings {
|
|
17
|
+
mtwModuleSettings {
|
|
18
|
+
${t}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`, r = `
|
|
22
|
+
mutation UpdateMtwModuleSettings($input: UpdateMtwModuleSettingsInput!) {
|
|
23
|
+
updateMtwModuleSettings(input: $input) {
|
|
24
|
+
${t}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
function i(e) {
|
|
29
|
+
return {
|
|
30
|
+
currency: e.defaultCurrency,
|
|
31
|
+
distanceUnit: e.distanceUnit,
|
|
32
|
+
weightUnit: e.weightUnit,
|
|
33
|
+
timeZone: e.timezone
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
var a = [{
|
|
37
|
+
value: "KM",
|
|
38
|
+
label: "Kilometres (km)"
|
|
39
|
+
}, {
|
|
40
|
+
value: "MI",
|
|
41
|
+
label: "Miles (mi)"
|
|
42
|
+
}], o = [{
|
|
43
|
+
value: "KG",
|
|
44
|
+
label: "Kilograms (kg)"
|
|
45
|
+
}, {
|
|
46
|
+
value: "LB",
|
|
47
|
+
label: "Pounds (lb)"
|
|
48
|
+
}], s = [
|
|
49
|
+
{
|
|
50
|
+
value: "LOW",
|
|
51
|
+
label: "Low"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
value: "MEDIUM",
|
|
55
|
+
label: "Normal"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: "HIGH",
|
|
59
|
+
label: "High"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: "URGENT",
|
|
63
|
+
label: "Urgent"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: "CRITICAL",
|
|
67
|
+
label: "Critical"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
function c(e) {
|
|
71
|
+
switch (e) {
|
|
72
|
+
case "LOW": return "low";
|
|
73
|
+
case "HIGH": return "high";
|
|
74
|
+
case "URGENT":
|
|
75
|
+
case "CRITICAL": return "urgent";
|
|
76
|
+
default: return "normal";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
var l = [
|
|
80
|
+
"USD",
|
|
81
|
+
"EUR",
|
|
82
|
+
"GBP",
|
|
83
|
+
"INR",
|
|
84
|
+
"AED",
|
|
85
|
+
"SGD",
|
|
86
|
+
"AUD",
|
|
87
|
+
"CAD",
|
|
88
|
+
"JPY",
|
|
89
|
+
"CNY"
|
|
90
|
+
];
|
|
91
|
+
function u(e) {
|
|
92
|
+
return typeof Intl.supportedValuesOf == "function" ? Intl.supportedValuesOf(e) : [];
|
|
93
|
+
}
|
|
94
|
+
function d(e) {
|
|
95
|
+
let t = new Set([...l, ...u("currency")]);
|
|
96
|
+
e && t.add(e);
|
|
97
|
+
let n = [...t].filter((e) => !l.includes(e)).sort();
|
|
98
|
+
return [...l, ...n];
|
|
99
|
+
}
|
|
100
|
+
function f(e) {
|
|
101
|
+
try {
|
|
102
|
+
let t = new Intl.DisplayNames(["en"], { type: "currency" }).of(e);
|
|
103
|
+
return t && t !== e ? `${e} — ${t}` : e;
|
|
104
|
+
} catch {
|
|
105
|
+
return e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function p(e) {
|
|
109
|
+
let t = new Set(["UTC", ...u("timeZone")]);
|
|
110
|
+
return e && t.add(e), [...t].sort((e, t) => e === "UTC" ? -1 : t === "UTC" ? 1 : e.localeCompare(t));
|
|
111
|
+
}
|
|
112
|
+
function m() {
|
|
113
|
+
try {
|
|
114
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
115
|
+
} catch {
|
|
116
|
+
return "UTC";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function h(e) {
|
|
120
|
+
let t = Number(e);
|
|
121
|
+
return !e.trim() || !Number.isInteger(t) || t < 1 || t > 720 ? "Enter a whole number of hours between 1 and 720." : null;
|
|
122
|
+
}
|
|
123
|
+
function g(e, t) {
|
|
124
|
+
let n = {};
|
|
125
|
+
return t.defaultCurrency !== void 0 && t.defaultCurrency !== e.defaultCurrency && (n.defaultCurrency = t.defaultCurrency), t.distanceUnit !== void 0 && t.distanceUnit !== e.distanceUnit && (n.distanceUnit = t.distanceUnit), t.weightUnit !== void 0 && t.weightUnit !== e.weightUnit && (n.weightUnit = t.weightUnit), t.timezone !== void 0 && t.timezone !== e.timezone && (n.timezone = t.timezone), t.defaultOrderPriority !== void 0 && t.defaultOrderPriority !== e.defaultOrderPriority && (n.defaultOrderPriority = t.defaultOrderPriority), t.defaultDeliveryWindowHours !== void 0 && t.defaultDeliveryWindowHours !== e.defaultDeliveryWindowHours && (n.defaultDeliveryWindowHours = t.defaultDeliveryWindowHours), n;
|
|
126
|
+
}
|
|
127
|
+
function _(e, t = /* @__PURE__ */ new Date()) {
|
|
128
|
+
let n = new Date(t.getTime() + e * 3600 * 1e3), r = (e) => String(e).padStart(2, "0");
|
|
129
|
+
return `${n.getFullYear()}-${r(n.getMonth() + 1)}-${r(n.getDate())}T${r(n.getHours())}:${r(n.getMinutes())}`;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { a as DISTANCE_UNIT_OPTIONS, n as MTW_MODULE_SETTINGS_QUERY, s as ORDER_PRIORITY_OPTIONS, r as UPDATE_MTW_MODULE_SETTINGS_MUTATION, o as WEIGHT_UNIT_OPTIONS, m as browserTimeZone, g as changedSettings, f as currencyLabel, d as currencyOptions, h as deliveryWindowError, _ as deliveryWindowValue, c as orderFormPriority, e as platformDefaults, p as timeZoneOptions, i as toFormatPreferences };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-movethewheels",
|
|
3
|
-
"version": "2026.1031.
|
|
3
|
+
"version": "2026.1031.4",
|
|
4
4
|
"description": "Burdenoff MoveTheWheels Microfrontend - Logistics & Supply Chain Management Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
38
38
|
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
39
39
|
"validate:schema-drift": "graphql-schema-drift",
|
|
40
|
-
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
40
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run validate:schema-drift && bun run lint:sanity && bun run format && bun run type:check && bun run verify:live-logistics-contract && bun run verify:empty-reuse-retry && bun run verify:empty-reuse-recovery && bun run verify:trip-utilization-input && bun run verify:trip-draft-context && bun run verify:stock-binding-input && bun run verify:stock-observation-input && bun run verify:pending-pick-input && bun run verify:pick-review-ack && bun run verify:driver-license-expiry && bun run verify:tracking-alerts && bun run verify:freight-input && bun run verify:freight-recovery && bun run verify:freight-commercial && bun run verify:freight-invoice && bun run verify:procedure-input && bun run verify:consolidation && bun run verify:multimodal-single-attempt && bun run verify:workspace-predispatch && bun run verify:tracking-quality-outcomes && bun run verify:shipment-status-authority && bun run verify:free-time-permissions && bun run verify:core-codegen && bun run verify:order-vehicle-hold && bun run verify:pallet-preview && bun run verify:entity-export && bun run verify:entity-import && bun run verify:module-settings && bun run verify:consumed-fuel-preview && bun run build && bun run build-storybook'",
|
|
41
41
|
"storybook": "storybook dev -p 6006",
|
|
42
42
|
"build-storybook": "storybook build",
|
|
43
43
|
"test:storybook": "vitest run --project=storybook",
|
|
@@ -73,6 +73,8 @@
|
|
|
73
73
|
"verify:tracking-alerts": "bun test scripts/check-tracking-alerts.test.ts",
|
|
74
74
|
"verify:core-codegen": "bun test scripts/codegen.test.ts && node --test scripts/check-package-types.test.mjs",
|
|
75
75
|
"verify:entity-export": "bun test scripts/check-entity-export.test.ts",
|
|
76
|
+
"verify:entity-import": "bun test scripts/check-entity-import.test.ts",
|
|
77
|
+
"verify:module-settings": "bun test scripts/check-module-settings.test.ts",
|
|
76
78
|
"verify:pallet-preview": "bun test scripts/check-pallet-preview.test.ts && bun scripts/verify-pallet-preview-hook.mjs",
|
|
77
79
|
"verify:consumed-fuel-preview": "bun test scripts/check-consumed-fuel-preview.test.ts && bun scripts/verify-consumed-fuel-preview-hook.mjs && bun scripts/verify-consumed-fuel-preview-component.mjs"
|
|
78
80
|
},
|
|
@@ -1259,6 +1259,13 @@ export type MtwDemandForecastVariance = {
|
|
|
1259
1259
|
volumeVariance: Scalars['Int']['output'];
|
|
1260
1260
|
};
|
|
1261
1261
|
|
|
1262
|
+
/** Unit MoveTheWheels shows distances in. */
|
|
1263
|
+
export type MtwDistanceUnit =
|
|
1264
|
+
/** Kilometres */
|
|
1265
|
+
| 'KM'
|
|
1266
|
+
/** Miles */
|
|
1267
|
+
| 'MI';
|
|
1268
|
+
|
|
1262
1269
|
export type MtwDriver = {
|
|
1263
1270
|
__typename?: 'MtwDriver';
|
|
1264
1271
|
baseSalary?: Maybe<Scalars['Float']['output']>;
|
|
@@ -2443,6 +2450,91 @@ export type MtwFuelVolumeObservationInput = {
|
|
|
2443
2450
|
sourceRevision?: InputMaybe<Scalars['String']['input']>;
|
|
2444
2451
|
};
|
|
2445
2452
|
|
|
2453
|
+
export type MtwImportColumn = {
|
|
2454
|
+
__typename?: 'MtwImportColumn';
|
|
2455
|
+
allowedValues?: Maybe<Array<Scalars['String']['output']>>;
|
|
2456
|
+
description: Scalars['String']['output'];
|
|
2457
|
+
max?: Maybe<Scalars['Float']['output']>;
|
|
2458
|
+
maxLength?: Maybe<Scalars['Int']['output']>;
|
|
2459
|
+
min?: Maybe<Scalars['Float']['output']>;
|
|
2460
|
+
name: Scalars['String']['output'];
|
|
2461
|
+
required: Scalars['Boolean']['output'];
|
|
2462
|
+
type: MtwImportColumnType;
|
|
2463
|
+
};
|
|
2464
|
+
|
|
2465
|
+
export type MtwImportColumnType =
|
|
2466
|
+
| 'BOOLEAN'
|
|
2467
|
+
| 'DATE'
|
|
2468
|
+
| 'EMAIL'
|
|
2469
|
+
| 'ENUM'
|
|
2470
|
+
| 'INTEGER'
|
|
2471
|
+
| 'JSON'
|
|
2472
|
+
| 'NUMBER'
|
|
2473
|
+
| 'STRING';
|
|
2474
|
+
|
|
2475
|
+
export type MtwImportEntitySpec = {
|
|
2476
|
+
__typename?: 'MtwImportEntitySpec';
|
|
2477
|
+
columns: Array<MtwImportColumn>;
|
|
2478
|
+
entityType: MtwImportEntityType;
|
|
2479
|
+
/** Column that must be unique in the workspace, if any. */
|
|
2480
|
+
keyColumn?: Maybe<Scalars['String']['output']>;
|
|
2481
|
+
};
|
|
2482
|
+
|
|
2483
|
+
export type MtwImportEntityType =
|
|
2484
|
+
| 'CARGO_ITEM'
|
|
2485
|
+
| 'CUSTOMER'
|
|
2486
|
+
| 'DRIVER'
|
|
2487
|
+
| 'VEHICLE'
|
|
2488
|
+
| 'WAREHOUSE';
|
|
2489
|
+
|
|
2490
|
+
export type MtwImportFormat =
|
|
2491
|
+
| 'CSV'
|
|
2492
|
+
| 'JSON';
|
|
2493
|
+
|
|
2494
|
+
export type MtwImportInput = {
|
|
2495
|
+
/** Import the valid rows even when other rows are invalid. */
|
|
2496
|
+
allowPartial?: InputMaybe<Scalars['Boolean']['input']>;
|
|
2497
|
+
/** The CSV (with a header row) or JSON (array of objects) document, at most 2 MB and 1000 rows. */
|
|
2498
|
+
content: Scalars['String']['input'];
|
|
2499
|
+
/** Validate every row without writing anything. */
|
|
2500
|
+
dryRun?: InputMaybe<Scalars['Boolean']['input']>;
|
|
2501
|
+
format: MtwImportFormat;
|
|
2502
|
+
};
|
|
2503
|
+
|
|
2504
|
+
export type MtwImportResult = {
|
|
2505
|
+
__typename?: 'MtwImportResult';
|
|
2506
|
+
createdIds: Array<Scalars['ID']['output']>;
|
|
2507
|
+
dryRun: Scalars['Boolean']['output'];
|
|
2508
|
+
entityType: MtwImportEntityType;
|
|
2509
|
+
errors: Array<MtwImportRowError>;
|
|
2510
|
+
/** True when more row errors exist than are returned (the first 500 are returned). */
|
|
2511
|
+
errorsTruncated: Scalars['Boolean']['output'];
|
|
2512
|
+
failedRows: Scalars['Int']['output'];
|
|
2513
|
+
importedRows: Scalars['Int']['output'];
|
|
2514
|
+
status: MtwImportStatus;
|
|
2515
|
+
totalRows: Scalars['Int']['output'];
|
|
2516
|
+
validRows: Scalars['Int']['output'];
|
|
2517
|
+
};
|
|
2518
|
+
|
|
2519
|
+
export type MtwImportRowError = {
|
|
2520
|
+
__typename?: 'MtwImportRowError';
|
|
2521
|
+
field?: Maybe<Scalars['String']['output']>;
|
|
2522
|
+
message: Scalars['String']['output'];
|
|
2523
|
+
/** 1-based data row number (the CSV header is not counted). */
|
|
2524
|
+
row: Scalars['Int']['output'];
|
|
2525
|
+
};
|
|
2526
|
+
|
|
2527
|
+
/**
|
|
2528
|
+
* DRY_RUN: validated only, nothing written. COMPLETED: every row imported.
|
|
2529
|
+
* PARTIAL: allowPartial was set and some rows failed. REJECTED: some rows were
|
|
2530
|
+
* invalid and allowPartial was not set, so nothing was written.
|
|
2531
|
+
*/
|
|
2532
|
+
export type MtwImportStatus =
|
|
2533
|
+
| 'COMPLETED'
|
|
2534
|
+
| 'DRY_RUN'
|
|
2535
|
+
| 'PARTIAL'
|
|
2536
|
+
| 'REJECTED';
|
|
2537
|
+
|
|
2446
2538
|
/** A recorded manual issuer review; workspace privileges do not establish professional qualifications. */
|
|
2447
2539
|
export type MtwInspectorQualification = {
|
|
2448
2540
|
__typename?: 'MtwInspectorQualification';
|
|
@@ -2615,6 +2707,31 @@ export type MtwMarketplaceStats = {
|
|
|
2615
2707
|
verifiedProviders: Scalars['Int']['output'];
|
|
2616
2708
|
};
|
|
2617
2709
|
|
|
2710
|
+
/**
|
|
2711
|
+
* Workspace operational defaults for MoveTheWheels (BOFF-10488): how amounts,
|
|
2712
|
+
* distances, weights and times are shown, and what new orders start from.
|
|
2713
|
+
* Company profile, notifications, two-factor authentication and integrations
|
|
2714
|
+
* are platform settings and are not part of this type.
|
|
2715
|
+
*/
|
|
2716
|
+
export type MtwModuleSettings = {
|
|
2717
|
+
__typename?: 'MtwModuleSettings';
|
|
2718
|
+
/** ISO 4217 code amounts without their own currency are shown in. */
|
|
2719
|
+
defaultCurrency: Scalars['String']['output'];
|
|
2720
|
+
/** Hours from now a new order's suggested delivery time falls (1 to 720). */
|
|
2721
|
+
defaultDeliveryWindowHours: Scalars['Int']['output'];
|
|
2722
|
+
/** Priority a new order starts with. */
|
|
2723
|
+
defaultOrderPriority: DeliveryPriority;
|
|
2724
|
+
distanceUnit: MtwDistanceUnit;
|
|
2725
|
+
/** False until the workspace saves its settings; the values are then the platform defaults. */
|
|
2726
|
+
isCustomized: Scalars['Boolean']['output'];
|
|
2727
|
+
/** IANA time zone dates and times are shown in. Null shows each viewer their own local time. */
|
|
2728
|
+
timezone?: Maybe<Scalars['String']['output']>;
|
|
2729
|
+
updatedAt?: Maybe<Scalars['DateTime']['output']>;
|
|
2730
|
+
updatedBy?: Maybe<Scalars['ID']['output']>;
|
|
2731
|
+
weightUnit: MtwWeightUnit;
|
|
2732
|
+
workspaceId: Scalars['ID']['output'];
|
|
2733
|
+
};
|
|
2734
|
+
|
|
2618
2735
|
export type MtwMoveReviewSource = {
|
|
2619
2736
|
__typename?: 'MtwMoveReviewSource';
|
|
2620
2737
|
reference: Scalars['String']['output'];
|
|
@@ -4467,6 +4584,13 @@ export type MtwWarehouseStats = {
|
|
|
4467
4584
|
total: Scalars['Int']['output'];
|
|
4468
4585
|
};
|
|
4469
4586
|
|
|
4587
|
+
/** Unit MoveTheWheels shows weights in. */
|
|
4588
|
+
export type MtwWeightUnit =
|
|
4589
|
+
/** Kilograms */
|
|
4590
|
+
| 'KG'
|
|
4591
|
+
/** Pounds */
|
|
4592
|
+
| 'LB';
|
|
4593
|
+
|
|
4470
4594
|
export type Mutation = {
|
|
4471
4595
|
__typename?: 'Mutation';
|
|
4472
4596
|
_empty?: Maybe<Scalars['String']['output']>;
|
|
@@ -4523,6 +4647,11 @@ export type Mutation = {
|
|
|
4523
4647
|
deleteWarehouse: Scalars['Boolean']['output'];
|
|
4524
4648
|
exportMtwEntities: MtwExportJob;
|
|
4525
4649
|
holdMtwContainer: MtwContainerHold;
|
|
4650
|
+
importMtwCargoItems: MtwImportResult;
|
|
4651
|
+
importMtwCustomers: MtwImportResult;
|
|
4652
|
+
importMtwDrivers: MtwImportResult;
|
|
4653
|
+
importMtwVehicles: MtwImportResult;
|
|
4654
|
+
importMtwWarehouses: MtwImportResult;
|
|
4526
4655
|
openMtwContainerCycle: MtwContainerCycle;
|
|
4527
4656
|
openMtwFreeTimeClock: MtwFreeTimeClock;
|
|
4528
4657
|
optimizeRoute: MtwRoute;
|
|
@@ -4568,6 +4697,8 @@ export type Mutation = {
|
|
|
4568
4697
|
updateDriverStatus: MtwDriver;
|
|
4569
4698
|
updateIntegration: MtwIntegration;
|
|
4570
4699
|
updateInventoryItem: MtwInventoryItem;
|
|
4700
|
+
/** Save the workspace's MoveTheWheels operational defaults. Every field is validated. */
|
|
4701
|
+
updateMtwModuleSettings: MtwModuleSettings;
|
|
4571
4702
|
updateRoute: MtwRoute;
|
|
4572
4703
|
updateServiceOffering: MtwServiceOffering;
|
|
4573
4704
|
updateServiceProvider: MtwServiceProvider;
|
|
@@ -4791,6 +4922,31 @@ export type MutationHoldMtwContainerArgs = {
|
|
|
4791
4922
|
};
|
|
4792
4923
|
|
|
4793
4924
|
|
|
4925
|
+
export type MutationImportMtwCargoItemsArgs = {
|
|
4926
|
+
input: MtwImportInput;
|
|
4927
|
+
};
|
|
4928
|
+
|
|
4929
|
+
|
|
4930
|
+
export type MutationImportMtwCustomersArgs = {
|
|
4931
|
+
input: MtwImportInput;
|
|
4932
|
+
};
|
|
4933
|
+
|
|
4934
|
+
|
|
4935
|
+
export type MutationImportMtwDriversArgs = {
|
|
4936
|
+
input: MtwImportInput;
|
|
4937
|
+
};
|
|
4938
|
+
|
|
4939
|
+
|
|
4940
|
+
export type MutationImportMtwVehiclesArgs = {
|
|
4941
|
+
input: MtwImportInput;
|
|
4942
|
+
};
|
|
4943
|
+
|
|
4944
|
+
|
|
4945
|
+
export type MutationImportMtwWarehousesArgs = {
|
|
4946
|
+
input: MtwImportInput;
|
|
4947
|
+
};
|
|
4948
|
+
|
|
4949
|
+
|
|
4794
4950
|
export type MutationOpenMtwContainerCycleArgs = {
|
|
4795
4951
|
input: OpenMtwContainerCycleInput;
|
|
4796
4952
|
};
|
|
@@ -5026,6 +5182,11 @@ export type MutationUpdateInventoryItemArgs = {
|
|
|
5026
5182
|
};
|
|
5027
5183
|
|
|
5028
5184
|
|
|
5185
|
+
export type MutationUpdateMtwModuleSettingsArgs = {
|
|
5186
|
+
input: UpdateMtwModuleSettingsInput;
|
|
5187
|
+
};
|
|
5188
|
+
|
|
5189
|
+
|
|
5029
5190
|
export type MutationUpdateRouteArgs = {
|
|
5030
5191
|
id: Scalars['ID']['input'];
|
|
5031
5192
|
input: UpdateRouteInput;
|
|
@@ -5253,6 +5414,15 @@ export type Query = {
|
|
|
5253
5414
|
/** Null is not proof of no effect and never authorizes resubmission. Exact original actor/context only. */
|
|
5254
5415
|
mtwFreightInvoiceComparisonByRequestKey?: Maybe<MtwFreightInvoiceComparison>;
|
|
5255
5416
|
mtwFreightInvoiceComparisonPage: MtwFreightInvoiceComparisonPage;
|
|
5417
|
+
/**
|
|
5418
|
+
* Columns accepted by each import, for building templates and showing guidance.
|
|
5419
|
+
* This is static reference metadata with no workspace data in it, so it only
|
|
5420
|
+
* needs an authenticated caller; every import mutation enforces its own
|
|
5421
|
+
* entity create permission.
|
|
5422
|
+
*/
|
|
5423
|
+
mtwImportSpec: Array<MtwImportEntitySpec>;
|
|
5424
|
+
/** The workspace's MoveTheWheels operational defaults; platform defaults when none were saved. */
|
|
5425
|
+
mtwModuleSettings: MtwModuleSettings;
|
|
5256
5426
|
mtwPalletGeometryPreview: MtwPalletGeometryPreview;
|
|
5257
5427
|
mtwPickPreparation: MtwPickPreparation;
|
|
5258
5428
|
mtwPickReview: MtwPickReview;
|
|
@@ -6525,6 +6695,20 @@ export type UpdateInventoryItemInput = {
|
|
|
6525
6695
|
unitCost?: InputMaybe<Scalars['Float']['input']>;
|
|
6526
6696
|
};
|
|
6527
6697
|
|
|
6698
|
+
/**
|
|
6699
|
+
* Changes to the workspace's MoveTheWheels defaults. Omitted fields keep their
|
|
6700
|
+
* current value. `timezone: null` (or an empty string) clears the time zone so
|
|
6701
|
+
* each viewer sees their own local time.
|
|
6702
|
+
*/
|
|
6703
|
+
export type UpdateMtwModuleSettingsInput = {
|
|
6704
|
+
defaultCurrency?: InputMaybe<Scalars['String']['input']>;
|
|
6705
|
+
defaultDeliveryWindowHours?: InputMaybe<Scalars['Int']['input']>;
|
|
6706
|
+
defaultOrderPriority?: InputMaybe<DeliveryPriority>;
|
|
6707
|
+
distanceUnit?: InputMaybe<MtwDistanceUnit>;
|
|
6708
|
+
timezone?: InputMaybe<Scalars['String']['input']>;
|
|
6709
|
+
weightUnit?: InputMaybe<MtwWeightUnit>;
|
|
6710
|
+
};
|
|
6711
|
+
|
|
6528
6712
|
export type UpdateRouteInput = {
|
|
6529
6713
|
actualDistance?: InputMaybe<Scalars['Float']['input']>;
|
|
6530
6714
|
actualDuration?: InputMaybe<Scalars['Float']['input']>;
|
|
@@ -23,8 +23,11 @@ import {
|
|
|
23
23
|
DollarSign,
|
|
24
24
|
Bot,
|
|
25
25
|
Store,
|
|
26
|
+
ArrowDownUp,
|
|
27
|
+
Settings,
|
|
26
28
|
} from 'lucide-react';
|
|
27
29
|
import { MoveTheWheelsProvider } from './providers/MoveTheWheelsProvider';
|
|
30
|
+
import { ModuleSettingsProvider } from './providers/ModuleSettingsProvider';
|
|
28
31
|
import { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
29
32
|
import type { NavItem, MoveTheWheelsRootProps } from './types';
|
|
30
33
|
import { MoveTheWheelsRoutes } from './MoveTheWheelsRoutes';
|
|
@@ -241,6 +244,13 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
|
|
|
241
244
|
icon: <Store size={16} />,
|
|
242
245
|
order: 6,
|
|
243
246
|
},
|
|
247
|
+
{
|
|
248
|
+
id: 'mtw-import-export',
|
|
249
|
+
label: tr('movethewheels.root.nav.importExport', 'Import / Export'),
|
|
250
|
+
path: joinPath(basePath, 'import-export'),
|
|
251
|
+
icon: <ArrowDownUp size={16} />,
|
|
252
|
+
order: 6,
|
|
253
|
+
},
|
|
244
254
|
{
|
|
245
255
|
id: 'mtw-routes',
|
|
246
256
|
label: tr('movethewheels.root.nav.routes', 'Routes'),
|
|
@@ -297,6 +307,13 @@ const NavRegistrar: FC<Pick<MoveTheWheelsRootProps, 'registerNavItems' | 'basePa
|
|
|
297
307
|
icon: <Bot size={16} />,
|
|
298
308
|
order: 13,
|
|
299
309
|
},
|
|
310
|
+
{
|
|
311
|
+
id: 'mtw-settings',
|
|
312
|
+
label: tr('movethewheels.root.nav.settings', 'Settings'),
|
|
313
|
+
path: joinPath(basePath, 'settings'),
|
|
314
|
+
icon: <Settings size={16} />,
|
|
315
|
+
order: 99,
|
|
316
|
+
},
|
|
300
317
|
],
|
|
301
318
|
};
|
|
302
319
|
|
|
@@ -357,9 +374,11 @@ export const MoveTheWheelsRoot: FC<MoveTheWheelsRootProps> = (props) => {
|
|
|
357
374
|
<FeatureFlagProvider workspaceId={null} gateway="global" defaultEnabled={true}>
|
|
358
375
|
<NavRegistrar registerNavItems={registerNavItems} basePath={basePath} />
|
|
359
376
|
<MoveTheWheelsProvider {...props}>
|
|
360
|
-
<
|
|
361
|
-
<
|
|
362
|
-
|
|
377
|
+
<ModuleSettingsProvider>
|
|
378
|
+
<div className="movethewheels-root h-full">
|
|
379
|
+
<MoveTheWheelsRoutes />
|
|
380
|
+
</div>
|
|
381
|
+
</ModuleSettingsProvider>
|
|
363
382
|
</MoveTheWheelsProvider>
|
|
364
383
|
</FeatureFlagProvider>
|
|
365
384
|
);
|
|
@@ -9,6 +9,7 @@ import { Routes, Route, useNavigate } from 'react-router';
|
|
|
9
9
|
import { lazy, Suspense } from 'react';
|
|
10
10
|
import { NotFoundPage } from '@burdenoff/fe-libs/shared/pages';
|
|
11
11
|
import { useMoveTheWheels } from './providers/MoveTheWheelsProvider';
|
|
12
|
+
import { useModuleSettings } from './providers/ModuleSettingsProvider';
|
|
12
13
|
import { useTr } from './hooks';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -72,6 +73,8 @@ const WarehouseDetailsPage = lazy(() => import('./pages/WarehouseDetailsPage'));
|
|
|
72
73
|
const CustomersPage = lazy(() => import('./pages/CustomersPage'));
|
|
73
74
|
const CustomerDetailsPage = lazy(() => import('./pages/CustomerDetailsPage'));
|
|
74
75
|
const MarketplacePage = lazy(() => import('./pages/MarketplacePage'));
|
|
76
|
+
const ImportExportPage = lazy(() => import('./pages/ImportExportPage'));
|
|
77
|
+
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
|
|
75
78
|
const RoutesPage = lazy(() => import('./pages/RoutesPage'));
|
|
76
79
|
const RouteDetailsPage = lazy(() => import('./pages/RouteDetailsPage'));
|
|
77
80
|
const AnalyticsPage = lazy(() => import('./pages/AnalyticsPage'));
|
|
@@ -95,6 +98,10 @@ const ConsumedFuelPreviewPage = lazy(() => import('./pages/ConsumedFuelPreviewPa
|
|
|
95
98
|
const EmptyReusePage = lazy(() => import('./pages/EmptyReusePage'));
|
|
96
99
|
|
|
97
100
|
export function MoveTheWheelsRoutes() {
|
|
101
|
+
// Subscribing here re-renders every page when the workspace's display
|
|
102
|
+
// defaults load or change, so amounts, units and dates follow them
|
|
103
|
+
// (BOFF-10488). The value itself is read through the shared formatters.
|
|
104
|
+
useModuleSettings();
|
|
98
105
|
return (
|
|
99
106
|
<Suspense fallback={<PageLoader />}>
|
|
100
107
|
<Routes>
|
|
@@ -160,6 +167,12 @@ export function MoveTheWheelsRoutes() {
|
|
|
160
167
|
{/* Marketplace — service providers and offerings (BOFF-3988) */}
|
|
161
168
|
<Route path="marketplace" element={<MarketplacePage />} />
|
|
162
169
|
|
|
170
|
+
{/* Bulk CSV/JSON import and dataset export (BOFF-3990) */}
|
|
171
|
+
<Route path="import-export" element={<ImportExportPage />} />
|
|
172
|
+
|
|
173
|
+
{/* Workspace operational defaults: currency, units, time zone (BOFF-10488) */}
|
|
174
|
+
<Route path="settings" element={<SettingsPage />} />
|
|
175
|
+
|
|
163
176
|
{/* Routes */}
|
|
164
177
|
<Route path="routes" element={<RoutesPage />} />
|
|
165
178
|
<Route path="routes/trip-utilization" element={<TripUtilizationPage />} />
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
3
|
+
import { executeGraphQL } from '../utils/graphqlClient';
|
|
4
|
+
import {
|
|
5
|
+
MTW_IMPORT_MAX_BYTES,
|
|
6
|
+
MTW_IMPORT_SPEC_QUERY,
|
|
7
|
+
importEntity,
|
|
8
|
+
importMutation,
|
|
9
|
+
type MtwImportEntitySpec,
|
|
10
|
+
type MtwImportEntityType,
|
|
11
|
+
type MtwImportFormat,
|
|
12
|
+
type MtwImportResult,
|
|
13
|
+
} from '../utils/entityImport';
|
|
14
|
+
|
|
15
|
+
function useGraphQLOptions() {
|
|
16
|
+
const { apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser } =
|
|
17
|
+
useMoveTheWheels();
|
|
18
|
+
return useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
apiGatewayUrl,
|
|
21
|
+
authToken,
|
|
22
|
+
workspaceToken,
|
|
23
|
+
workspaceId,
|
|
24
|
+
tenantId,
|
|
25
|
+
actorId: currentUser?.id,
|
|
26
|
+
}),
|
|
27
|
+
[apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser?.id]
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Column specification for every importable entity. */
|
|
32
|
+
export function useImportSpec() {
|
|
33
|
+
const graphQLOptions = useGraphQLOptions();
|
|
34
|
+
const [specs, setSpecs] = useState<MtwImportEntitySpec[]>([]);
|
|
35
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
36
|
+
const [error, setError] = useState<Error | null>(null);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!graphQLOptions.workspaceId) return;
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
setIsLoading(true);
|
|
42
|
+
executeGraphQL<{ mtwImportSpec: MtwImportEntitySpec[] }>(graphQLOptions, MTW_IMPORT_SPEC_QUERY)
|
|
43
|
+
.then((data) => {
|
|
44
|
+
if (cancelled) return;
|
|
45
|
+
setSpecs(data.mtwImportSpec);
|
|
46
|
+
setError(null);
|
|
47
|
+
})
|
|
48
|
+
.catch((caught: unknown) => {
|
|
49
|
+
if (!cancelled)
|
|
50
|
+
setError(caught instanceof Error ? caught : new Error('Could not load import columns'));
|
|
51
|
+
})
|
|
52
|
+
.finally(() => {
|
|
53
|
+
if (!cancelled) setIsLoading(false);
|
|
54
|
+
});
|
|
55
|
+
return () => {
|
|
56
|
+
cancelled = true;
|
|
57
|
+
};
|
|
58
|
+
}, [graphQLOptions]);
|
|
59
|
+
|
|
60
|
+
return { specs, isLoading, error };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ImportRequest {
|
|
64
|
+
entityType: MtwImportEntityType;
|
|
65
|
+
format: MtwImportFormat;
|
|
66
|
+
content: string;
|
|
67
|
+
dryRun: boolean;
|
|
68
|
+
allowPartial: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Runs a validation or an import. Writes are sent once: a retry could create rows twice. */
|
|
72
|
+
export function useEntityImport() {
|
|
73
|
+
const graphQLOptions = useGraphQLOptions();
|
|
74
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
75
|
+
|
|
76
|
+
const run = useCallback(
|
|
77
|
+
async (request: ImportRequest): Promise<MtwImportResult> => {
|
|
78
|
+
if (new Blob([request.content]).size > MTW_IMPORT_MAX_BYTES) {
|
|
79
|
+
throw new Error('The file is larger than 2 MB. Split it into smaller files.');
|
|
80
|
+
}
|
|
81
|
+
const { field } = importEntity(request.entityType);
|
|
82
|
+
setIsRunning(true);
|
|
83
|
+
try {
|
|
84
|
+
const data = await executeGraphQL<Record<string, MtwImportResult>>(
|
|
85
|
+
graphQLOptions,
|
|
86
|
+
importMutation(request.entityType),
|
|
87
|
+
{
|
|
88
|
+
input: {
|
|
89
|
+
format: request.format,
|
|
90
|
+
content: request.content,
|
|
91
|
+
dryRun: request.dryRun,
|
|
92
|
+
allowPartial: request.allowPartial,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
request.dryRun ? 'RETRY_TRANSIENT' : 'SINGLE_ATTEMPT'
|
|
96
|
+
);
|
|
97
|
+
const result = data[field];
|
|
98
|
+
if (!result) throw new Error('The import returned no result');
|
|
99
|
+
return result;
|
|
100
|
+
} finally {
|
|
101
|
+
setIsRunning(false);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
[graphQLOptions]
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return { run, isRunning };
|
|
108
|
+
}
|