@seedtactics/insight-client 16.4.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 (298) hide show
  1. package/README.md +37 -0
  2. package/dist/cell-status/buffers.d.ts +36 -0
  3. package/dist/cell-status/buffers.js +127 -0
  4. package/dist/cell-status/current-status.d.ts +30 -0
  5. package/dist/cell-status/current-status.js +200 -0
  6. package/dist/cell-status/estimated-cycle-times.d.ts +41 -0
  7. package/dist/cell-status/estimated-cycle-times.js +257 -0
  8. package/dist/cell-status/inspections.d.ts +55 -0
  9. package/dist/cell-status/inspections.js +213 -0
  10. package/dist/cell-status/loading.d.ts +26 -0
  11. package/dist/cell-status/loading.js +112 -0
  12. package/dist/cell-status/material-details.d.ts +116 -0
  13. package/dist/cell-status/material-details.js +422 -0
  14. package/dist/cell-status/material-summary.d.ts +52 -0
  15. package/dist/cell-status/material-summary.js +312 -0
  16. package/dist/cell-status/names.d.ts +19 -0
  17. package/dist/cell-status/names.js +134 -0
  18. package/dist/cell-status/pallet-cycles.d.ts +24 -0
  19. package/dist/cell-status/pallet-cycles.js +78 -0
  20. package/dist/cell-status/rebookings.d.ts +30 -0
  21. package/dist/cell-status/rebookings.js +139 -0
  22. package/dist/cell-status/scheduled-jobs.d.ts +18 -0
  23. package/dist/cell-status/scheduled-jobs.js +94 -0
  24. package/dist/cell-status/sim-day-usage.d.ts +14 -0
  25. package/dist/cell-status/sim-day-usage.js +54 -0
  26. package/dist/cell-status/sim-production.d.ts +22 -0
  27. package/dist/cell-status/sim-production.js +91 -0
  28. package/dist/cell-status/sim-station-use.d.ts +25 -0
  29. package/dist/cell-status/sim-station-use.js +71 -0
  30. package/dist/cell-status/station-cycles.d.ts +34 -0
  31. package/dist/cell-status/station-cycles.js +145 -0
  32. package/dist/cell-status/tool-replacements.d.ts +44 -0
  33. package/dist/cell-status/tool-replacements.js +155 -0
  34. package/dist/cell-status/tool-usage.d.ts +25 -0
  35. package/dist/cell-status/tool-usage.js +95 -0
  36. package/dist/components/App.d.ts +15 -0
  37. package/dist/components/App.js +549 -0
  38. package/dist/components/AxisAndGrid.d.ts +51 -0
  39. package/dist/components/AxisAndGrid.js +47 -0
  40. package/dist/components/BarcodeScanning.d.ts +6 -0
  41. package/dist/components/BarcodeScanning.js +150 -0
  42. package/dist/components/ChartTooltip.d.ts +28 -0
  43. package/dist/components/ChartTooltip.js +95 -0
  44. package/dist/components/ChooseMode.d.ts +18 -0
  45. package/dist/components/ChooseMode.js +136 -0
  46. package/dist/components/ChooseOperator.d.ts +1 -0
  47. package/dist/components/ChooseOperator.js +93 -0
  48. package/dist/components/ErrorsAndLoading.d.ts +9 -0
  49. package/dist/components/ErrorsAndLoading.js +55 -0
  50. package/dist/components/LoadingIcon.d.ts +1 -0
  51. package/dist/components/LoadingIcon.js +48 -0
  52. package/dist/components/LogEntry.d.ts +16 -0
  53. package/dist/components/LogEntry.js +365 -0
  54. package/dist/components/ManualSerialEntry.d.ts +5 -0
  55. package/dist/components/ManualSerialEntry.js +91 -0
  56. package/dist/components/MonthSelect.d.ts +6 -0
  57. package/dist/components/MonthSelect.js +67 -0
  58. package/dist/components/Navigation.d.ts +23 -0
  59. package/dist/components/Navigation.js +120 -0
  60. package/dist/components/VerboseLogging.d.ts +1 -0
  61. package/dist/components/VerboseLogging.js +47 -0
  62. package/dist/components/analysis/AnalysisSelectToolbar.d.ts +1 -0
  63. package/dist/components/analysis/AnalysisSelectToolbar.js +55 -0
  64. package/dist/components/analysis/BufferChart.d.ts +1 -0
  65. package/dist/components/analysis/BufferChart.js +139 -0
  66. package/dist/components/analysis/CostPerPiece.d.ts +2 -0
  67. package/dist/components/analysis/CostPerPiece.js +175 -0
  68. package/dist/components/analysis/CycleChart.d.ts +42 -0
  69. package/dist/components/analysis/CycleChart.js +281 -0
  70. package/dist/components/analysis/DataTable.d.ts +83 -0
  71. package/dist/components/analysis/DataTable.js +215 -0
  72. package/dist/components/analysis/EfficiencyPage.d.ts +2 -0
  73. package/dist/components/analysis/EfficiencyPage.js +138 -0
  74. package/dist/components/analysis/HeatChart.d.ts +22 -0
  75. package/dist/components/analysis/HeatChart.js +161 -0
  76. package/dist/components/analysis/InspectionDataTable.d.ts +10 -0
  77. package/dist/components/analysis/InspectionDataTable.js +148 -0
  78. package/dist/components/analysis/InspectionSankey.d.ts +12 -0
  79. package/dist/components/analysis/InspectionSankey.js +140 -0
  80. package/dist/components/analysis/PalletCycleCards.d.ts +1 -0
  81. package/dist/components/analysis/PalletCycleCards.js +137 -0
  82. package/dist/components/analysis/PartCycleCards.d.ts +2 -0
  83. package/dist/components/analysis/PartCycleCards.js +331 -0
  84. package/dist/components/analysis/QualityPage.d.ts +1 -0
  85. package/dist/components/analysis/QualityPage.js +49 -0
  86. package/dist/components/analysis/ScheduleHistory.d.ts +3 -0
  87. package/dist/components/analysis/ScheduleHistory.js +108 -0
  88. package/dist/components/analysis/StationDataTable.d.ts +25 -0
  89. package/dist/components/analysis/StationDataTable.js +246 -0
  90. package/dist/components/analysis/ToolReplacements.d.ts +1 -0
  91. package/dist/components/analysis/ToolReplacements.js +370 -0
  92. package/dist/components/operations/AllMaterial.d.ts +5 -0
  93. package/dist/components/operations/AllMaterial.js +267 -0
  94. package/dist/components/operations/ChartRangeEdit.d.ts +4 -0
  95. package/dist/components/operations/ChartRangeEdit.js +148 -0
  96. package/dist/components/operations/CloseoutReport.d.ts +2 -0
  97. package/dist/components/operations/CloseoutReport.js +172 -0
  98. package/dist/components/operations/CompletedParts.d.ts +2 -0
  99. package/dist/components/operations/CompletedParts.js +286 -0
  100. package/dist/components/operations/CurrentWorkorders.d.ts +3 -0
  101. package/dist/components/operations/CurrentWorkorders.js +368 -0
  102. package/dist/components/operations/Dashboard.d.ts +2 -0
  103. package/dist/components/operations/Dashboard.js +90 -0
  104. package/dist/components/operations/OEEChart.d.ts +10 -0
  105. package/dist/components/operations/OEEChart.js +173 -0
  106. package/dist/components/operations/Outliers.d.ts +4 -0
  107. package/dist/components/operations/Outliers.js +69 -0
  108. package/dist/components/operations/ProgramHighlight.d.ts +1 -0
  109. package/dist/components/operations/ProgramHighlight.js +9 -0
  110. package/dist/components/operations/Programs.d.ts +5 -0
  111. package/dist/components/operations/Programs.js +363 -0
  112. package/dist/components/operations/Rebookings.d.ts +1 -0
  113. package/dist/components/operations/Rebookings.js +213 -0
  114. package/dist/components/operations/RecentCycleChart.d.ts +4 -0
  115. package/dist/components/operations/RecentCycleChart.js +240 -0
  116. package/dist/components/operations/RecentProduction.d.ts +2 -0
  117. package/dist/components/operations/RecentProduction.js +213 -0
  118. package/dist/components/operations/RecentSchedules.d.ts +12 -0
  119. package/dist/components/operations/RecentSchedules.js +180 -0
  120. package/dist/components/operations/RecentStationCycles.d.ts +4 -0
  121. package/dist/components/operations/RecentStationCycles.js +159 -0
  122. package/dist/components/operations/ShiftSettings.d.ts +6 -0
  123. package/dist/components/operations/ShiftSettings.js +134 -0
  124. package/dist/components/operations/SimDayUsage.d.ts +1 -0
  125. package/dist/components/operations/SimDayUsage.js +133 -0
  126. package/dist/components/operations/ToolReport.d.ts +3 -0
  127. package/dist/components/operations/ToolReport.js +233 -0
  128. package/dist/components/operations/WorkorderGantt.d.ts +1 -0
  129. package/dist/components/operations/WorkorderGantt.js +124 -0
  130. package/dist/components/quality/QualityMaterial.d.ts +2 -0
  131. package/dist/components/quality/QualityMaterial.js +169 -0
  132. package/dist/components/quality/QualityPaths.d.ts +1 -0
  133. package/dist/components/quality/QualityPaths.js +53 -0
  134. package/dist/components/quality/RecentFailedInspections.d.ts +1 -0
  135. package/dist/components/quality/RecentFailedInspections.js +123 -0
  136. package/dist/components/routes.d.ts +170 -0
  137. package/dist/components/routes.js +301 -0
  138. package/dist/components/station-monitor/BulkRawMaterial.d.ts +11 -0
  139. package/dist/components/station-monitor/BulkRawMaterial.js +251 -0
  140. package/dist/components/station-monitor/Closeout.d.ts +5 -0
  141. package/dist/components/station-monitor/Closeout.js +162 -0
  142. package/dist/components/station-monitor/CustomStationMonitorDialog.d.ts +1 -0
  143. package/dist/components/station-monitor/CustomStationMonitorDialog.js +55 -0
  144. package/dist/components/station-monitor/Inspection.d.ts +8 -0
  145. package/dist/components/station-monitor/Inspection.js +164 -0
  146. package/dist/components/station-monitor/InvalidateCycle.d.ts +33 -0
  147. package/dist/components/station-monitor/InvalidateCycle.js +262 -0
  148. package/dist/components/station-monitor/JobDetails.d.ts +7 -0
  149. package/dist/components/station-monitor/JobDetails.js +108 -0
  150. package/dist/components/station-monitor/LoadStation.d.ts +10 -0
  151. package/dist/components/station-monitor/LoadStation.js +450 -0
  152. package/dist/components/station-monitor/Material.d.ts +77 -0
  153. package/dist/components/station-monitor/Material.js +489 -0
  154. package/dist/components/station-monitor/MoveMaterialArrows.d.ts +11 -0
  155. package/dist/components/station-monitor/MoveMaterialArrows.js +118 -0
  156. package/dist/components/station-monitor/PrintedLabel.d.ts +29 -0
  157. package/dist/components/station-monitor/PrintedLabel.js +166 -0
  158. package/dist/components/station-monitor/QuarantineButton.d.ts +4 -0
  159. package/dist/components/station-monitor/QuarantineButton.js +184 -0
  160. package/dist/components/station-monitor/Queues.d.ts +23 -0
  161. package/dist/components/station-monitor/Queues.js +312 -0
  162. package/dist/components/station-monitor/QueuesAddMaterial.d.ts +30 -0
  163. package/dist/components/station-monitor/QueuesAddMaterial.js +248 -0
  164. package/dist/components/station-monitor/SelectInspType.d.ts +2 -0
  165. package/dist/components/station-monitor/SelectInspType.js +99 -0
  166. package/dist/components/station-monitor/SelectWorkorder.d.ts +4 -0
  167. package/dist/components/station-monitor/SelectWorkorder.js +100 -0
  168. package/dist/components/station-monitor/StationToolbar.d.ts +3 -0
  169. package/dist/components/station-monitor/StationToolbar.js +168 -0
  170. package/dist/components/station-monitor/SystemOverview.d.ts +46 -0
  171. package/dist/components/station-monitor/SystemOverview.js +439 -0
  172. package/dist/components/station-monitor/Whiteboard.d.ts +10 -0
  173. package/dist/components/station-monitor/Whiteboard.js +67 -0
  174. package/dist/data/all-material-bins.d.ts +45 -0
  175. package/dist/data/all-material-bins.js +224 -0
  176. package/dist/data/chart-times.d.ts +20 -0
  177. package/dist/data/chart-times.js +99 -0
  178. package/dist/data/cost-per-piece.d.ts +32 -0
  179. package/dist/data/cost-per-piece.js +183 -0
  180. package/dist/data/current-cycles.d.ts +13 -0
  181. package/dist/data/current-cycles.js +144 -0
  182. package/dist/data/inspection-sankey.d.ts +15 -0
  183. package/dist/data/inspection-sankey.js +147 -0
  184. package/dist/data/move-arrows.d.ts +48 -0
  185. package/dist/data/move-arrows.js +217 -0
  186. package/dist/data/operators.d.ts +2 -0
  187. package/dist/data/operators.js +44 -0
  188. package/dist/data/part-summary.d.ts +17 -0
  189. package/dist/data/part-summary.js +107 -0
  190. package/dist/data/path-lookup.d.ts +13 -0
  191. package/dist/data/path-lookup.js +107 -0
  192. package/dist/data/queue-material.d.ts +46 -0
  193. package/dist/data/queue-material.js +256 -0
  194. package/dist/data/results.bufferchart.d.ts +10 -0
  195. package/dist/data/results.bufferchart.js +90 -0
  196. package/dist/data/results.completed-parts.d.ts +26 -0
  197. package/dist/data/results.completed-parts.js +181 -0
  198. package/dist/data/results.cycles.d.ts +86 -0
  199. package/dist/data/results.cycles.js +454 -0
  200. package/dist/data/results.inspection.d.ts +36 -0
  201. package/dist/data/results.inspection.js +188 -0
  202. package/dist/data/results.oee.d.ts +40 -0
  203. package/dist/data/results.oee.js +330 -0
  204. package/dist/data/results.schedules.d.ts +23 -0
  205. package/dist/data/results.schedules.js +157 -0
  206. package/dist/data/tools-programs.d.ts +78 -0
  207. package/dist/data/tools-programs.js +376 -0
  208. package/dist/index.d.ts +1 -0
  209. package/dist/index.js +60 -0
  210. package/dist/network/api.d.ts +1390 -0
  211. package/dist/network/api.js +4971 -0
  212. package/dist/network/backend-mock.d.ts +11 -0
  213. package/dist/network/backend-mock.js +512 -0
  214. package/dist/network/backend.d.ts +57 -0
  215. package/dist/network/backend.js +77 -0
  216. package/dist/network/load-specific-month.d.ts +13 -0
  217. package/dist/network/load-specific-month.js +77 -0
  218. package/dist/network/server-settings.d.ts +12 -0
  219. package/dist/network/server-settings.js +92 -0
  220. package/dist/network/websocket.d.ts +4 -0
  221. package/dist/network/websocket.js +165 -0
  222. package/dist/renderer.d.ts +8 -0
  223. package/dist/renderer.js +55 -0
  224. package/dist/seedtactics-logo.d.ts +2 -0
  225. package/dist/seedtactics-logo.js +4 -0
  226. package/dist/util/chart-colors.d.ts +1 -0
  227. package/dist/util/chart-colors.js +116 -0
  228. package/dist/util/chart-helpers.d.ts +3 -0
  229. package/dist/util/chart-helpers.js +51 -0
  230. package/dist/util/parseISODuration.d.ts +4 -0
  231. package/dist/util/parseISODuration.js +40 -0
  232. package/docs/client-efficiency.md +355 -0
  233. package/docs/client-engineering.md +54 -0
  234. package/docs/client-launch.md +55 -0
  235. package/docs/client-operations.md +88 -0
  236. package/docs/client-quality.md +74 -0
  237. package/docs/client-sales.md +61 -0
  238. package/docs/client-scanners.md +41 -0
  239. package/docs/client-station-monitor.md +149 -0
  240. package/docs/client-tools-programs.md +74 -0
  241. package/docs/improve-fms.md +141 -0
  242. package/docs/makino.md +40 -0
  243. package/docs/material-quarantine.md +82 -0
  244. package/docs/material-tracking.md +236 -0
  245. package/docs/mazak.md +115 -0
  246. package/docs/niigata.md +228 -0
  247. package/docs/operator-procedures.md +106 -0
  248. package/docs/part-instructions.md +63 -0
  249. package/docs/screenshots/insight-all-material.png +0 -0
  250. package/docs/screenshots/insight-analysis-pallets.png +0 -0
  251. package/docs/screenshots/insight-analysis-part-completed.png +0 -0
  252. package/docs/screenshots/insight-analysis-sankey.png +0 -0
  253. package/docs/screenshots/insight-analysis-station-oee.png +0 -0
  254. package/docs/screenshots/insight-buffer-occupancy.png +0 -0
  255. package/docs/screenshots/insight-choose-analysis-month.png +0 -0
  256. package/docs/screenshots/insight-closeout.png +0 -0
  257. package/docs/screenshots/insight-cost-percentages.png +0 -0
  258. package/docs/screenshots/insight-dashboard.png +0 -0
  259. package/docs/screenshots/insight-event-custom-view.jpg +0 -0
  260. package/docs/screenshots/insight-event-viewer.jpg +0 -0
  261. package/docs/screenshots/insight-inspection.png +0 -0
  262. package/docs/screenshots/insight-load-station-details.png +0 -0
  263. package/docs/screenshots/insight-load-station.png +0 -0
  264. package/docs/screenshots/insight-loadcycle-graph.png +0 -0
  265. package/docs/screenshots/insight-loadstation-small.jpg +0 -0
  266. package/docs/screenshots/insight-machinecycle-graph.png +0 -0
  267. package/docs/screenshots/insight-machinecycle-table.png +0 -0
  268. package/docs/screenshots/insight-machinecycles.png +0 -0
  269. package/docs/screenshots/insight-machinehours.png +0 -0
  270. package/docs/screenshots/insight-machineoutliers.png +0 -0
  271. package/docs/screenshots/insight-monthly-schedules.png +0 -0
  272. package/docs/screenshots/insight-operations-material.png +0 -0
  273. package/docs/screenshots/insight-operations-overview.png +0 -0
  274. package/docs/screenshots/insight-operations-reports.png +0 -0
  275. package/docs/screenshots/insight-part-cost.png +0 -0
  276. package/docs/screenshots/insight-program-report.png +0 -0
  277. package/docs/screenshots/insight-quality-material-details.png +0 -0
  278. package/docs/screenshots/insight-quality-material.png +0 -0
  279. package/docs/screenshots/insight-quality-quarantine.png +0 -0
  280. package/docs/screenshots/insight-quality-sankey.png +0 -0
  281. package/docs/screenshots/insight-quality-similar-paths.png +0 -0
  282. package/docs/screenshots/insight-queue-details.png +0 -0
  283. package/docs/screenshots/insight-queues-jobs-table.png +0 -0
  284. package/docs/screenshots/insight-queues.png +0 -0
  285. package/docs/screenshots/insight-sim-day-usage.png +0 -0
  286. package/docs/screenshots/insight-station-system-overview-buttons.png +0 -0
  287. package/docs/screenshots/insight-station-system-overview.png +0 -0
  288. package/docs/screenshots/insight-system-overview.png +0 -0
  289. package/docs/screenshots/insight-tool-replacements.png +0 -0
  290. package/docs/screenshots/insight-tool-report.png +0 -0
  291. package/docs/screenshots/insight-toolbar-btns.png +0 -0
  292. package/docs/screenshots/insight-workorder-gantt.png +0 -0
  293. package/docs/screenshots/insight-workorders.png +0 -0
  294. package/docs/security.md +131 -0
  295. package/docs/server-config.md +56 -0
  296. package/docs/server-errors.md +44 -0
  297. package/package.json +90 -0
  298. package/src/index.ts +65 -0
@@ -0,0 +1,213 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /* Copyright (c) 2024, John Lenz
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials provided
15
+ with the distribution.
16
+
17
+ * Neither the name of John Lenz, Black Maple Software, SeedTactics,
18
+ nor the names of other contributors may be used to endorse or
19
+ promote products derived from this software without specific
20
+ prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ */
34
+ import { Autocomplete, Box, Button, Checkbox, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, Divider, Fab, FormControlLabel, InputAdornment, Stack, Table, TextField, Tooltip, Typography, } from "@mui/material";
35
+ import { atom, useAtom, useAtomValue } from "jotai";
36
+ import { fmsInformation } from "../../network/server-settings.js";
37
+ import { DataTableActions, DataTableBody, DataTableHead, useColSort, useTablePage, } from "../analysis/DataTable.js";
38
+ import { useSetTitle } from "../routes.js";
39
+ import { memo, useMemo, useState } from "react";
40
+ import { canceledRebookings, last30Rebookings, last30ScheduledBookings, useCancelRebooking, useNewRebooking, } from "../../cell-status/rebookings.js";
41
+ import { LazySeq } from "@seedtactics/immutable-collections";
42
+ import { Add } from "@mui/icons-material";
43
+ import { currentStatus } from "../../cell-status/current-status.js";
44
+ import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
45
+ import { PartIdenticon } from "../station-monitor/Material.js";
46
+ var ColumnId;
47
+ (function (ColumnId) {
48
+ ColumnId[ColumnId["BookingId"] = 0] = "BookingId";
49
+ ColumnId[ColumnId["Part"] = 1] = "Part";
50
+ ColumnId[ColumnId["Quantity"] = 2] = "Quantity";
51
+ ColumnId[ColumnId["RequestTime"] = 3] = "RequestTime";
52
+ ColumnId[ColumnId["Priority"] = 4] = "Priority";
53
+ ColumnId[ColumnId["Workorder"] = 5] = "Workorder";
54
+ ColumnId[ColumnId["Canceled"] = 6] = "Canceled";
55
+ ColumnId[ColumnId["Job"] = 7] = "Job";
56
+ ColumnId[ColumnId["SchTime"] = 8] = "SchTime";
57
+ // Procs
58
+ // Notes
59
+ })(ColumnId || (ColumnId = {}));
60
+ const filterDialogOpen = atom(false);
61
+ const hideScheduledAtom = atom(false);
62
+ const hideCanceledAtom = atom(false);
63
+ const columns = [
64
+ {
65
+ id: ColumnId.BookingId,
66
+ numeric: false,
67
+ label: "ID",
68
+ getDisplay: (r) => r.bookingId,
69
+ Cell: ({ row }) => row.canceled ? (_jsx(Typography, { sx: { textDecoration: "line-through", fontSize: "inherit" }, children: row.bookingId })) : (row.bookingId),
70
+ },
71
+ {
72
+ id: ColumnId.Part,
73
+ numeric: false,
74
+ label: "Part",
75
+ getDisplay: (r) => r.partName,
76
+ Cell: ({ row }) => (_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(PartIdenticon, { part: row.partName, size: 25 }), row.partName] })),
77
+ },
78
+ {
79
+ id: ColumnId.Quantity,
80
+ numeric: true,
81
+ label: "Quantity",
82
+ getDisplay: (r) => r.quantity.toString(),
83
+ getForSort: (r) => r.quantity,
84
+ },
85
+ {
86
+ id: ColumnId.RequestTime,
87
+ numeric: false,
88
+ label: "Request Time",
89
+ getDisplay: (r) => r.timeUTC.toLocaleString(),
90
+ getForSort: (r) => r.timeUTC.getTime(),
91
+ },
92
+ {
93
+ id: ColumnId.Priority,
94
+ numeric: false,
95
+ label: "Priority",
96
+ getDisplay: (r) => (r.priority ? r.priority.toString() : ""),
97
+ getForSort: (r) => r.priority ?? 0,
98
+ },
99
+ {
100
+ id: ColumnId.Workorder,
101
+ numeric: false,
102
+ label: "Workorder",
103
+ getDisplay: (r) => r.workorder ?? "",
104
+ },
105
+ {
106
+ id: ColumnId.Canceled,
107
+ numeric: false,
108
+ label: "Canceled",
109
+ getDisplay: (r) => r.canceled?.toLocaleString() ?? "",
110
+ getForSort: (r) => r.canceled?.getTime() ?? 0,
111
+ openFilterDialog: filterDialogOpen,
112
+ },
113
+ {
114
+ id: ColumnId.Job,
115
+ numeric: false,
116
+ label: "Scheduled Job",
117
+ getDisplay: (r) => r.job ?? "",
118
+ openFilterDialog: filterDialogOpen,
119
+ },
120
+ {
121
+ id: ColumnId.SchTime,
122
+ numeric: false,
123
+ label: "Scheduled Time",
124
+ getDisplay: (r) => (r.schTime ? r.schTime.toLocaleString() : ""),
125
+ getForSort: (r) => (r.schTime ? r.schTime.getTime() : 0),
126
+ },
127
+ ];
128
+ const BookingTable = memo(function BookingTable({ setRebookingToShow, }) {
129
+ const sort = useColSort(ColumnId.RequestTime, columns, "desc");
130
+ const tpage = useTablePage();
131
+ const rebookings = useAtomValue(last30Rebookings);
132
+ const canceled = useAtomValue(canceledRebookings);
133
+ const scheduled = useAtomValue(last30ScheduledBookings);
134
+ const unschOnly = useAtomValue(hideScheduledAtom);
135
+ const hideCanceled = useAtomValue(hideCanceledAtom);
136
+ const rows = useMemo(() => rebookings
137
+ .adjust(scheduled, (r, sch) => r
138
+ ? {
139
+ ...r,
140
+ job: sch?.jobUnique,
141
+ schTime: sch?.scheduledTime,
142
+ }
143
+ : undefined)
144
+ .adjust(canceled, (r, t) => (r ? { ...r, canceled: t } : undefined))
145
+ .valuesToAscLazySeq()
146
+ .transform((s) => (unschOnly ? s.filter((r) => !r.job) : s))
147
+ .transform((s) => (hideCanceled ? s.filter((r) => !r.canceled) : s))
148
+ .toSortedArray(sort.sortOn), [sort.sortOn, rebookings, canceled, scheduled, unschOnly, hideCanceled]);
149
+ return (_jsxs("div", { children: [_jsxs(Table, { children: [_jsx(DataTableHead, { columns: columns, sort: sort, showDetailsCol: true, copyToClipboardRows: rows }), _jsx(DataTableBody, { columns: columns, pageData: rows, rowsPerPage: tpage.rowsPerPage, onClickDetails: (_, row) => setRebookingToShow(row) })] }), _jsx(DataTableActions, { tpage: tpage, count: rows.length })] }));
150
+ });
151
+ const longDateFormat = new Intl.DateTimeFormat(undefined, {
152
+ year: "numeric",
153
+ month: "short",
154
+ day: "numeric",
155
+ hour: "numeric",
156
+ minute: "numeric",
157
+ });
158
+ const RebookingDialog = memo(function RebookingDialog({ rebooking, close, }) {
159
+ const [sendCancel, canceling] = useCancelRebooking();
160
+ function cancel() {
161
+ if (rebooking) {
162
+ sendCancel(rebooking.bookingId)
163
+ .then(() => close(undefined))
164
+ .catch(console.log);
165
+ }
166
+ }
167
+ return (_jsxs(Dialog, { open: rebooking !== undefined, onClose: () => close(undefined), children: [_jsx(DialogTitle, { children: rebooking?.canceled ? (_jsx(Typography, { sx: { textDecoration: "line-through" }, children: rebooking?.bookingId })) : (rebooking?.bookingId) }), _jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 1, children: [rebooking?.canceled && (_jsxs(Typography, { variant: "h5", children: ["Canceled at ", longDateFormat.format(rebooking.canceled)] })), _jsxs(Stack, { direction: "row", spacing: 1, children: [_jsx("span", { children: "Part:" }), rebooking?.partName && _jsx(PartIdenticon, { part: rebooking?.partName, size: 25 }), _jsx("span", { children: rebooking?.partName })] }), _jsxs(Typography, { children: ["Quantity: ", rebooking?.quantity] }), _jsxs(Typography, { children: ["Request Time: ", longDateFormat.format(rebooking?.timeUTC)] }), _jsxs(Typography, { children: ["Priority: ", rebooking?.priority] }), rebooking?.workorder && _jsxs(Typography, { children: ["Workorder: ", rebooking?.workorder] }), _jsxs(Typography, { children: ["Note: ", rebooking?.notes] }), rebooking?.job && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsxs(Typography, { children: ["Scheduled Job: ", rebooking?.job] }), _jsxs(Typography, { children: ["Scheduled Time: ", rebooking?.schTime?.toLocaleString()] })] }))] }) }), _jsxs(DialogActions, { children: [!rebooking?.canceled && !rebooking?.job && (_jsxs(Button, { onClick: cancel, color: "secondary", disabled: canceling, children: [canceling ? _jsx(CircularProgress, { size: 24 }) : undefined, "Cancel Rebooking Request"] })), _jsx(Button, { onClick: () => close(undefined), children: "Close" })] })] }));
168
+ });
169
+ const partNamesAtom = atom((get) => LazySeq.ofObject(get(currentStatus).jobs)
170
+ .map(([_, j]) => j.partName)
171
+ .concat(get(last30Jobs)
172
+ .valuesToLazySeq()
173
+ .map((j) => j.partName))
174
+ .distinctAndSortBy((p) => p)
175
+ .toRArray());
176
+ const NewRebookingDialog = memo(function NewRebookingDialog() {
177
+ const [open, setOpen] = useState(false);
178
+ const [rebooking, setRebooking] = useState({ part: "" });
179
+ const partNames = useAtomValue(partNamesAtom);
180
+ const [createNew, creating] = useNewRebooking();
181
+ const allowCreate = rebooking.part !== "" && !!rebooking.qty && !isNaN(rebooking.qty);
182
+ function close() {
183
+ setOpen(false);
184
+ setRebooking({ part: "" });
185
+ }
186
+ function create() {
187
+ if (!allowCreate) {
188
+ return;
189
+ }
190
+ createNew(rebooking).then(close).catch(console.log);
191
+ }
192
+ return (_jsxs(_Fragment, { children: [_jsxs(Dialog, { open: open, onClose: close, children: [_jsx(DialogTitle, { children: "Create New" }), _jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 2, sx: { mt: "0.5em", minWidth: "25em" }, children: [_jsx(Autocomplete, { freeSolo: true, selectOnFocus: true, clearOnBlur: true, handleHomeEndKeys: true, disableClearable: true, options: partNames, value: rebooking.part, onChange: (_, v) => setRebooking((r) => ({ ...r, part: v })), renderInput: (params) => (_jsx(TextField, { ...params, label: "Part Name", slotProps: {
193
+ input: {
194
+ ...params.InputProps,
195
+ startAdornment: (_jsxs(_Fragment, { children: [rebooking.part !== "" ? (_jsx(InputAdornment, { position: "start", children: _jsx(PartIdenticon, { part: rebooking.part, size: 25 }) })) : undefined, params.InputProps.startAdornment] })),
196
+ },
197
+ } })), renderOption: (props, option) => (_jsx("li", { ...props, children: _jsxs(Stack, { direction: "row", spacing: "1", alignItems: "center", children: [_jsx(PartIdenticon, { part: option, size: 25 }), option] }) })), filterOptions: (options, params) => {
198
+ const filtered = options.filter((o) => o.toLowerCase().includes(params.inputValue.toLowerCase()));
199
+ return filtered.length === 0 && params.inputValue !== "" ? [params.inputValue] : filtered;
200
+ } }), _jsx(TextField, { label: "Quantity", type: "number", value: rebooking.qty && !isNaN(rebooking.qty) ? rebooking.qty : "", onChange: (e) => setRebooking((r) => ({ ...r, qty: parseInt(e.target.value) })) }), _jsx(TextField, { label: "Priority (optional)", type: "number", value: rebooking.priority && !isNaN(rebooking.priority) ? rebooking.priority : "", onChange: (e) => setRebooking((r) => ({ ...r, priority: parseInt(e.target.value) })) }), _jsx(TextField, { label: "Workorder (optional)", value: rebooking.workorder ?? "", onChange: (e) => setRebooking((r) => ({ ...r, workorder: e.target.value })) }), _jsx(TextField, { label: "Notes (optional)", multiline: true, minRows: 2, value: rebooking.notes ?? "", onChange: (e) => setRebooking((r) => ({ ...r, notes: e.target.value })) })] }) }), _jsxs(DialogActions, { children: [_jsxs(Button, { color: "secondary", onClick: create, disabled: !allowCreate || creating, children: [creating ? _jsx(CircularProgress, { size: 24 }) : undefined, "Create"] }), _jsx(Button, { onClick: close, children: "Cancel" })] })] }), _jsx(Tooltip, { title: "Add Rebooking", children: _jsx(Fab, { onClick: () => setOpen(true), sx: { position: "fixed", bottom: "24px", right: "24px" }, color: "primary", children: _jsx(Add, {}) }) })] }));
201
+ });
202
+ const FilterDialog = memo(function UnschFilterDialog() {
203
+ const [open, setOpen] = useAtom(filterDialogOpen);
204
+ const [showOnlyUnscheduled, setShowOnlyUnscheduled] = useAtom(hideScheduledAtom);
205
+ const [hideCanceled, setHideCanceled] = useAtom(hideCanceledAtom);
206
+ return (_jsxs(Dialog, { open: open, onClose: () => setOpen(false), children: [_jsx(DialogTitle, { children: "Filter" }), _jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 2, children: [_jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: showOnlyUnscheduled, onChange: (e) => setShowOnlyUnscheduled(e.target.checked) }), label: "Hide scheduled" }), _jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: hideCanceled, onChange: (e) => setHideCanceled(e.target.checked) }), label: "Hide canceled" })] }) }), _jsx(DialogActions, { children: _jsx(Button, { onClick: () => setOpen(false), children: "Close" }) })] }));
207
+ });
208
+ export function RebookingsPage() {
209
+ const fmsInfo = useAtomValue(fmsInformation);
210
+ useSetTitle(fmsInfo.supportsRebookings ?? "Rebookings");
211
+ const [rebookingToShow, setRebookingToShow] = useState(undefined);
212
+ return (_jsxs(Box, { component: "main", sx: { padding: "24px" }, children: [_jsx(BookingTable, { setRebookingToShow: setRebookingToShow }), _jsx(RebookingDialog, { rebooking: rebookingToShow, close: setRebookingToShow }), _jsx(NewRebookingDialog, {}), _jsx(FilterDialog, {})] }));
213
+ }
@@ -0,0 +1,4 @@
1
+ export declare function RecentCycleChart({ height, width }: {
2
+ height: number;
3
+ width: number;
4
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,240 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* Copyright (c) 2022, John Lenz
3
+
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials provided
15
+ with the distribution.
16
+
17
+ * Neither the name of John Lenz, Black Maple Software, SeedTactics,
18
+ nor the names of other contributors may be used to endorse or
19
+ promote products derived from this software without specific
20
+ prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ */
34
+ import { useMemo, useCallback, useState, useRef, useEffect } from "react";
35
+ import { last30StationCycles } from "../../cell-status/station-cycles.js";
36
+ import { last30EstimatedCycleTimes } from "../../cell-status/estimated-cycle-times.js";
37
+ import { recentCycles } from "../../data/results.cycles.js";
38
+ import { addHours, differenceInMinutes } from "date-fns";
39
+ import { LazySeq, OrderedSet } from "@seedtactics/immutable-collections";
40
+ import { last30SimStationUse } from "../../cell-status/sim-station-use.js";
41
+ import { red, green, grey } from "@mui/material/colors";
42
+ import { localPoint } from "../../util/chart-helpers.js";
43
+ import { Stack } from "@mui/material";
44
+ import { Tooltip } from "../ChartTooltip.js";
45
+ import { currentCycles } from "../../data/current-cycles.js";
46
+ import { currentStatus } from "../../cell-status/current-status.js";
47
+ import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
48
+ import { atom, useAtomValue, useSetAtom } from "jotai";
49
+ import { AxisBottom, AxisLeft, GridCols } from "../AxisAndGrid.js";
50
+ import { measureSvgString } from "../../util/chart-helpers.js";
51
+ import { scaleBand, scaleTime } from "d3-scale";
52
+ const projectedColor = green[200];
53
+ const activeColor = green[600];
54
+ const occupiedNonOutlierColor = green[900];
55
+ const occupiedOutlierColor = red[700];
56
+ const simColor = grey[400];
57
+ const downtimeColor = grey[100];
58
+ function useSimCycles() {
59
+ const jobs = useAtomValue(last30Jobs);
60
+ const statUse = useAtomValue(last30SimStationUse);
61
+ return useMemo(() => {
62
+ const cutoff = addHours(new Date(), -12);
63
+ return (LazySeq.of(statUse)
64
+ .filter((s) => s.end >= cutoff)
65
+ // make sure all planned downtimes come last so they are drawn over the top of any cycles
66
+ .sortBy((s) => (s.plannedDown ? 1 : 0))
67
+ .map((s) => ({
68
+ station: s.station,
69
+ start: s.start,
70
+ end: s.end,
71
+ plannedDown: s.plannedDown,
72
+ parts: LazySeq.of(s.parts ?? [])
73
+ .collect((p) => {
74
+ const j = jobs.get(p.uniq);
75
+ if (!j)
76
+ return null;
77
+ return j.partName + "-" + p.proc.toString();
78
+ })
79
+ .distinctAndSortBy((p) => p)
80
+ .toRArray(),
81
+ }))
82
+ .toRArray());
83
+ }, [jobs, statUse]);
84
+ }
85
+ const tooltipData = atom(null);
86
+ const stationFontSize = 14;
87
+ const marginBottom = 20;
88
+ const marginTop = 10;
89
+ const marginRight = 2;
90
+ function useScales(cycles, current, now, containerWidth, containerHeight) {
91
+ const stats = OrderedSet.build(cycles, (c) => c.station).union(OrderedSet.build(current, (c) => c.station));
92
+ const maxStatLen = stats
93
+ .toAscLazySeq()
94
+ .map((s) => measureSvgString(s, stationFontSize))
95
+ .maxBy((w) => w ?? 0) ?? 20;
96
+ const marginLeft = maxStatLen + 30;
97
+ const xMax = Math.max(containerWidth - marginLeft - marginRight, 5);
98
+ const yMax = Math.max(containerHeight - marginTop - marginBottom, 5);
99
+ const xScale = scaleTime()
100
+ .domain([addHours(now, -12), addHours(now, 8)])
101
+ .range([0, xMax]);
102
+ const yScale = scaleBand().domain(Array.from(stats)).range([0, yMax]).padding(0.3);
103
+ const actualPlannedScale = scaleBand()
104
+ .domain(["actual", "planned"])
105
+ .range([0, yScale.bandwidth()])
106
+ .padding(0.1);
107
+ return { xScale, yScale, actualPlannedScale, marginLeft };
108
+ }
109
+ function AxisAndGrid({ xScale, yScale }) {
110
+ return (_jsxs(_Fragment, { children: [_jsx(AxisBottom, { scale: xScale, top: yScale.range()[1] }), _jsx(AxisLeft, { scale: yScale, left: xScale.range()[0], fontSize: stationFontSize }), _jsx(GridCols, { scale: xScale, height: yScale.range()[1] - yScale.range()[0] })] }));
111
+ }
112
+ function RecentSeries({ cycles, xScale, yScale, actualPlannedScale, hideTooltipRef, }) {
113
+ const actualOffset = actualPlannedScale("actual") ?? 0;
114
+ const setTooltip = useSetAtom(tooltipData);
115
+ function showTooltip(c) {
116
+ return (e) => {
117
+ const pt = localPoint(e);
118
+ if (!pt)
119
+ return;
120
+ if (hideTooltipRef.current !== null) {
121
+ clearTimeout(hideTooltipRef.current);
122
+ hideTooltipRef.current = null;
123
+ }
124
+ setTooltip({
125
+ left: pt.x,
126
+ top: pt.y,
127
+ data: { kind: "actual", cycle: c },
128
+ });
129
+ };
130
+ }
131
+ const hideTooltip = useCallback(() => {
132
+ hideTooltipRef.current = setTimeout(() => {
133
+ setTooltip(null);
134
+ }, 300);
135
+ }, [hideTooltipRef, setTooltip]);
136
+ return (_jsx("g", { children: cycles.map((c, i) => {
137
+ if (c.endActive && c.endActive < c.endOccupied) {
138
+ return (_jsxs("g", { onMouseOver: showTooltip(c), onMouseLeave: hideTooltip, children: [_jsx("rect", { x: xScale(c.startTime), y: (yScale(c.station) ?? 0) + actualOffset, width: xScale(c.endOccupied) - xScale(c.startTime), height: actualPlannedScale.bandwidth(), fill: activeColor }), _jsx("rect", { x: xScale(c.endActive), y: (yScale(c.station) ?? 0) + actualOffset + actualPlannedScale.bandwidth() / 10, width: xScale(c.endOccupied) - xScale(c.endActive), height: (actualPlannedScale.bandwidth() * 8) / 10, fill: c.outlier ? occupiedOutlierColor : occupiedNonOutlierColor })] }, i));
139
+ }
140
+ else {
141
+ // no active time known, so just assume whole thing is ok.
142
+ return (_jsx("g", { onMouseOver: showTooltip(c), onMouseLeave: hideTooltip, children: _jsx("rect", { x: xScale(c.startTime), y: (yScale(c.station) ?? 0) + actualOffset, width: xScale(c.endOccupied) - xScale(c.startTime), height: actualPlannedScale.bandwidth(), fill: activeColor }) }, i));
143
+ }
144
+ }) }));
145
+ }
146
+ function halfCirclePath(x, y, rx, ry) {
147
+ return `M ${x} ${y} A ${rx} ${ry} 0 0 1 ${x} ${y + ry}`;
148
+ }
149
+ function CurrentSeries({ now, cycles, xScale, yScale, actualPlannedScale, hideTooltipRef, }) {
150
+ const actualOffset = actualPlannedScale("actual") ?? 0;
151
+ const setTooltip = useSetAtom(tooltipData);
152
+ function showTooltip(c) {
153
+ return (e) => {
154
+ const pt = localPoint(e);
155
+ if (!pt)
156
+ return;
157
+ if (hideTooltipRef.current !== null) {
158
+ clearTimeout(hideTooltipRef.current);
159
+ hideTooltipRef.current = null;
160
+ }
161
+ setTooltip({
162
+ left: pt.x,
163
+ top: pt.y,
164
+ data: { kind: "current", cycle: c, now },
165
+ });
166
+ };
167
+ }
168
+ const hideTooltip = useCallback(() => {
169
+ hideTooltipRef.current = setTimeout(() => {
170
+ setTooltip(null);
171
+ }, 300);
172
+ }, [hideTooltipRef, setTooltip]);
173
+ return (_jsx("g", { children: cycles.map((c, i) => {
174
+ return (_jsxs("g", { onMouseOver: showTooltip(c), onMouseLeave: hideTooltip, children: [_jsx("rect", { x: xScale(c.start), y: (yScale(c.station) ?? 0) + actualOffset, width: xScale(now) - xScale(c.start), height: actualPlannedScale.bandwidth(), fill: activeColor }), c.expectedEnd < now ? (_jsxs(_Fragment, { children: [_jsx("rect", { x: xScale(c.expectedEnd), y: (yScale(c.station) ?? 0) + actualOffset + actualPlannedScale.bandwidth() / 10, width: xScale(now) - xScale(c.expectedEnd), height: (actualPlannedScale.bandwidth() * 8) / 10, fill: c.isOutlier ? occupiedOutlierColor : occupiedNonOutlierColor }), _jsx("path", { d: halfCirclePath(xScale(now), (yScale(c.station) ?? 0) + actualOffset, 80, // rx
175
+ actualPlannedScale.bandwidth()), fill: projectedColor })] })) : (_jsx("rect", { x: xScale(now), y: (yScale(c.station) ?? 0) + actualOffset, width: xScale(c.expectedEnd) - xScale(now), height: actualPlannedScale.bandwidth(), fill: projectedColor }))] }, i));
176
+ }) }));
177
+ }
178
+ function SimSeries({ sim, xScale, yScale, actualPlannedScale, hideTooltipRef, }) {
179
+ const plannedOffset = actualPlannedScale("planned") ?? 0;
180
+ const setTooltip = useSetAtom(tooltipData);
181
+ function showTooltip(c) {
182
+ return (e) => {
183
+ const pt = localPoint(e);
184
+ if (!pt)
185
+ return;
186
+ if (hideTooltipRef.current !== null) {
187
+ clearTimeout(hideTooltipRef.current);
188
+ hideTooltipRef.current = null;
189
+ }
190
+ setTooltip({
191
+ left: pt.x,
192
+ top: pt.y,
193
+ data: { kind: "sim", cycle: c },
194
+ });
195
+ };
196
+ }
197
+ const hideTooltip = useCallback(() => {
198
+ hideTooltipRef.current = setTimeout(() => {
199
+ setTooltip(null);
200
+ }, 300);
201
+ }, [hideTooltipRef, setTooltip]);
202
+ return (_jsx("g", { children: sim.map((c, i) => (_jsx("g", { onMouseOver: showTooltip(c), onMouseLeave: hideTooltip, children: _jsx("rect", { x: xScale(c.start), y: (yScale(c.station) ?? 0) + plannedOffset, width: xScale(c.end) - xScale(c.start), height: actualPlannedScale.bandwidth(), fill: c.plannedDown ? downtimeColor : simColor }) }, i))) }));
203
+ }
204
+ function RecentTooltip({ tooltip }) {
205
+ return (_jsx(Stack, { children: tooltip.data.kind === "actual" ? (_jsxs(_Fragment, { children: [tooltip.data.cycle.outlier ? (_jsxs("div", { children: ["Outlier Cycle for ", tooltip.data.cycle.station] })) : (_jsx("div", { children: tooltip.data.cycle.station })), _jsxs("div", { children: ["Start: ", tooltip.data.cycle.startTime.toLocaleString()] }), _jsxs("div", { children: ["End: ", tooltip.data.cycle.endOccupied.toLocaleString()] }), tooltip.data.cycle.endActive !== undefined ? (_jsxs("div", { children: ["Active Minutes:", " ", differenceInMinutes(tooltip.data.cycle.endActive, tooltip.data.cycle.startTime)] })) : undefined, _jsxs("div", { children: ["Occupied Minutes:", " ", differenceInMinutes(tooltip.data.cycle.endOccupied, tooltip.data.cycle.startTime)] }), tooltip.data.cycle.parts.map((p, idx) => (_jsxs("div", { children: ["Part: ", p.part, " ", p.oper] }, idx)))] })) : tooltip.data.kind === "sim" ? (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["Simulation of ", tooltip.data.cycle.station] }), tooltip.data.cycle.parts.map((p, idx) => (_jsxs("div", { children: ["Part: ", p] }, idx))), _jsxs("div", { children: ["Predicted Start: ", tooltip.data.cycle.start.toLocaleString()] }), _jsxs("div", { children: ["Predicted End: ", tooltip.data.cycle.end.toLocaleString()] }), tooltip.data.cycle.plannedDown ? _jsx("div", { children: "Planned Downtime" }) : undefined] })) : (_jsxs(_Fragment, { children: [tooltip.data.cycle.isOutlier ? (_jsxs("div", { children: ["Current Outlier Cycle for ", tooltip.data.cycle.station] })) : (_jsxs("div", { children: ["Current ", tooltip.data.cycle.station] })), _jsxs("div", { children: ["Start: ", tooltip.data.cycle.start.toLocaleString()] }), _jsxs("div", { children: ["Expected End: ", tooltip.data.cycle.expectedEnd.toLocaleString()] }), tooltip.data.cycle.expectedEnd < tooltip.data.now ? (_jsxs("div", { children: ["Cycle Exceeding Expected By", " ", differenceInMinutes(tooltip.data.now, tooltip.data.cycle.expectedEnd), " Minutes"] })) : (_jsxs("div", { children: ["Expected Remaining Minutes:", " ", differenceInMinutes(tooltip.data.cycle.expectedEnd, tooltip.data.now)] })), _jsxs("div", { children: ["Occupied Minutes: ", differenceInMinutes(tooltip.data.now, tooltip.data.cycle.start)] }), tooltip.data.cycle.parts.map((p, idx) => (_jsxs("div", { children: ["Part: ", p.part, " ", p.oper] }, idx)))] })) }));
206
+ }
207
+ function NowLine({ now, xScale, yScale }) {
208
+ const x = xScale(now);
209
+ const fontSize = 11;
210
+ return (_jsxs("g", { children: [_jsx("line", { x1: x, x2: x, y1: yScale.range()[0], y2: yScale.range()[1] + 8, stroke: "black" }), _jsx("text", { x: x, y: yScale.range()[1] + 8 + fontSize, textAnchor: "middle", fontSize: fontSize, children: "Now" })] }));
211
+ }
212
+ export function RecentCycleChart({ height, width }) {
213
+ const last30Cycles = useAtomValue(last30StationCycles);
214
+ const estimated = useAtomValue(last30EstimatedCycleTimes);
215
+ const sim = useSimCycles();
216
+ const currentSt = useAtomValue(currentStatus);
217
+ const cycles = useMemo(() => {
218
+ const cutoff = addHours(new Date(), -12);
219
+ return recentCycles(last30Cycles.valuesToLazySeq().filter((e) => e.endTime >= cutoff));
220
+ }, [last30Cycles]);
221
+ const current = useMemo(() => {
222
+ return currentCycles(currentSt, estimated);
223
+ }, [currentSt, estimated]);
224
+ // ensure a re-render at least every 5 minutes, but reset the timer if the data changes
225
+ const now = new Date();
226
+ const [, forceRerender] = useState(0);
227
+ const refreshRef = useRef(null);
228
+ useEffect(() => {
229
+ if (refreshRef.current !== null)
230
+ clearTimeout(refreshRef.current);
231
+ refreshRef.current = setTimeout(() => {
232
+ forceRerender((x) => x + 1);
233
+ }, 5 * 60 * 1000);
234
+ });
235
+ const { xScale, yScale, actualPlannedScale, marginLeft } = useScales(cycles, current, now, width, height);
236
+ const hideTooltipRef = useRef(null);
237
+ if (height <= 0 || width <= 0)
238
+ return null;
239
+ return (_jsxs("div", { style: { position: "relative", overflow: "hidden" }, children: [_jsx("svg", { height: height, width: width, children: _jsxs("g", { transform: `translate(${marginLeft}, ${marginTop})`, children: [_jsx("clipPath", { id: "recent-cycle-clip-body", children: _jsx("rect", { x: 0, y: 0, width: width - marginRight - marginLeft, height: height - marginBottom - marginTop }) }), _jsx(AxisAndGrid, { xScale: xScale, yScale: yScale }), _jsxs("g", { clipPath: "url(#recent-cycle-clip-body)", children: [_jsx(RecentSeries, { cycles: cycles, xScale: xScale, yScale: yScale, hideTooltipRef: hideTooltipRef, actualPlannedScale: actualPlannedScale }), _jsx(CurrentSeries, { now: now, cycles: current, xScale: xScale, yScale: yScale, hideTooltipRef: hideTooltipRef, actualPlannedScale: actualPlannedScale }), _jsx(SimSeries, { sim: sim, xScale: xScale, yScale: yScale, actualPlannedScale: actualPlannedScale, hideTooltipRef: hideTooltipRef })] }), _jsx(NowLine, { now: now, xScale: xScale, yScale: yScale })] }) }), _jsx(Tooltip, { chartHeight: height, chartWidth: width, atom: tooltipData, TooltipContent: RecentTooltip })] }));
240
+ }
@@ -0,0 +1,2 @@
1
+ import { ReactNode } from "react";
2
+ export declare function RecentProductionPage(): ReactNode;