@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,134 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* Copyright (c) 2023, 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 { ButtonBase, Stack, TextField, Tooltip } from "@mui/material";
35
+ import { useMemo } from "react";
36
+ import { Clear as ClearIcon } from "@mui/icons-material";
37
+ import { addDays, addMinutes } from "date-fns";
38
+ import { atom, useAtom, useAtomValue } from "jotai";
39
+ import { atomWithStorage } from "jotai/utils";
40
+ const shiftStartStorage = atomWithStorage("shift-starts", [
41
+ [1, 6 * 60],
42
+ [2, 14 * 60],
43
+ [3, 22 * 60],
44
+ ]);
45
+ const shiftStartAtom = atom((get) => new Map(get(shiftStartStorage)), (get, set, update) => {
46
+ const shifts = new Map(get(shiftStartStorage));
47
+ update(shifts);
48
+ set(shiftStartStorage, Array.from(shifts.entries()));
49
+ });
50
+ export function useShifts(day) {
51
+ const shifts = useAtomValue(shiftStartAtom);
52
+ return useMemo(() => {
53
+ const starts = [];
54
+ for (let i = 1; i <= 3; i++) {
55
+ const cur = shifts.get(i);
56
+ if (cur === undefined)
57
+ continue;
58
+ if (starts.length >= 1 && starts[starts.length - 1] >= cur)
59
+ continue;
60
+ starts.push(cur);
61
+ }
62
+ if (starts.length === 0) {
63
+ return [
64
+ {
65
+ start: day,
66
+ end: addDays(day, 1),
67
+ },
68
+ ];
69
+ }
70
+ const finalShiftEnd = addMinutes(addDays(day, 1), starts[0]);
71
+ const startAndEnd = [];
72
+ for (let i = 0; i < starts.length; i++) {
73
+ startAndEnd.push({
74
+ start: addMinutes(day, starts[i]),
75
+ end: i === starts.length - 1 ? finalShiftEnd : addMinutes(day, starts[i + 1]),
76
+ });
77
+ }
78
+ return startAndEnd;
79
+ }, [shifts, day]);
80
+ }
81
+ function timespanToMinutes(t) {
82
+ const [h, m] = t.split(":");
83
+ return parseInt(h, 10) * 60 + parseInt(m, 10);
84
+ }
85
+ function minutesToTimespan(m) {
86
+ const h = Math.floor(m / 60);
87
+ const min = m % 60;
88
+ return `${h.toString().padStart(2, "0")}:${min.toString().padStart(2, "0")}`;
89
+ }
90
+ function shiftError(shiftNum, starts) {
91
+ const cur = starts.get(shiftNum);
92
+ if (cur === undefined) {
93
+ return false;
94
+ }
95
+ if (shiftNum === 1) {
96
+ const after = starts.get(2) ?? starts.get(3);
97
+ return after !== undefined && after <= cur;
98
+ }
99
+ else if (shiftNum === 2) {
100
+ const before = starts.get(1);
101
+ const after = starts.get(3);
102
+ return (before !== undefined && before >= cur) || (after !== undefined && after <= cur);
103
+ }
104
+ else if (shiftNum === 3) {
105
+ const before = starts.get(2) ?? starts.get(1);
106
+ return before !== undefined && before >= cur;
107
+ }
108
+ else {
109
+ return false;
110
+ }
111
+ }
112
+ function ShiftStartInput({ shiftNum }) {
113
+ const [shifts, setShifts] = useAtom(shiftStartAtom);
114
+ const val = shifts.get(shiftNum);
115
+ return (_jsx(TextField, { type: "time", label: `Shift ${shiftNum} Start`, error: shiftError(shiftNum, shifts), value: val === undefined ? "" : minutesToTimespan(val), onChange: (e) => {
116
+ const val = e.target.value;
117
+ if (val === "") {
118
+ setShifts((draft) => draft.delete(shiftNum));
119
+ }
120
+ else {
121
+ setShifts((draft) => draft.set(shiftNum, timespanToMinutes(val)));
122
+ }
123
+ }, variant: "standard", size: "small", slotProps: {
124
+ inputLabel: { shrink: true },
125
+ input: shiftNum === 1
126
+ ? undefined
127
+ : {
128
+ endAdornment: (_jsx(Tooltip, { title: "Clear/Disable Shift", children: _jsx(ButtonBase, { sx: { mb: "4px" }, onClick: () => setShifts((draft) => draft.delete(shiftNum)), children: _jsx(ClearIcon, { fontSize: "small" }) }) })),
129
+ },
130
+ } }));
131
+ }
132
+ export function ShiftStart() {
133
+ return (_jsxs(Stack, { direction: "row", spacing: 2, children: [_jsx(ShiftStartInput, { shiftNum: 1 }), _jsx(ShiftStartInput, { shiftNum: 2 }), _jsx(ShiftStartInput, { shiftNum: 3 })] }));
134
+ }
@@ -0,0 +1 @@
1
+ export declare function SimDayUsagePage(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,133 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /* Copyright (c) 2023, 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 } from "react";
35
+ import { Box, Stack, Tooltip, Typography } from "@mui/material";
36
+ import { green, grey } from "@mui/material/colors";
37
+ import { LazySeq, OrderedSet } from "@seedtactics/immutable-collections";
38
+ import { atom, useAtomValue } from "jotai";
39
+ import { latestSimDayUsage } from "../../cell-status/sim-day-usage";
40
+ import { useSetTitle } from "../routes";
41
+ import { scaleLinear } from "d3-scale";
42
+ import { Warning as WarningIcon } from "@mui/icons-material";
43
+ const color1 = green[50];
44
+ const color2 = green[600];
45
+ const downtimeColor = grey[100];
46
+ const monthBoxSize = "3em";
47
+ const monthWidth = `calc(${monthBoxSize} * 7)`;
48
+ const groupedSimDayUsage = atom((get) => {
49
+ const usage = get(latestSimDayUsage);
50
+ if (usage === null)
51
+ return null;
52
+ return LazySeq.of(usage.usage).toLookupOrderedMap((u) => u.machineGroup, (u) => new Date(u.day.getUTCFullYear(), u.day.getUTCMonth(), u.day.getUTCDate()));
53
+ });
54
+ const machineGroups = atom((get) => {
55
+ const usage = get(latestSimDayUsage);
56
+ if (usage === null)
57
+ return OrderedSet.empty();
58
+ return OrderedSet.build(usage.usage, (u) => u.machineGroup);
59
+ });
60
+ const usageMonths = atom((get) => {
61
+ const usage = get(latestSimDayUsage);
62
+ if (usage === null)
63
+ return OrderedSet.empty();
64
+ return OrderedSet.build(usage.usage, (u) => new Date(u.day.getUTCFullYear(), u.day.getUTCMonth(), 1));
65
+ });
66
+ const maxUsage = atom((get) => {
67
+ const usage = get(latestSimDayUsage);
68
+ if (usage === null)
69
+ return 0;
70
+ return (LazySeq.of(usage.usage)
71
+ .map((u) => Math.ceil(u.usage))
72
+ .maxBy((u) => u) ?? 1);
73
+ });
74
+ const minAndMaxUsageDay = atom((get) => {
75
+ const usage = get(latestSimDayUsage);
76
+ if (usage === null)
77
+ return [null, null];
78
+ return [
79
+ LazySeq.of(usage.usage)
80
+ .map((u) => new Date(u.day.getUTCFullYear(), u.day.getUTCMonth(), u.day.getUTCDate()))
81
+ .minBy((d) => d) ?? null,
82
+ LazySeq.of(usage.usage)
83
+ .map((u) => new Date(u.day.getUTCFullYear(), u.day.getUTCMonth(), u.day.getUTCDate()))
84
+ .maxBy((d) => d) ?? null,
85
+ ];
86
+ });
87
+ function ShowMonth({ date, dayColor, tooltip, }) {
88
+ const dayStart = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
89
+ const numDaysInMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
90
+ return (_jsxs(Box, { width: monthWidth, children: [_jsx(Typography, { variant: "h6", textAlign: "center", children: date.toLocaleString("default", { month: "long", year: "numeric" }) }), _jsxs(Box, { display: "flex", flexWrap: "wrap", children: [LazySeq.ofRange(0, dayStart).map((_, i) => (_jsx(Box, { height: monthBoxSize, width: monthBoxSize }, i))), LazySeq.ofRange(1, numDaysInMonth + 1).map((d, i) => (_jsx("div", { style: {
91
+ width: monthBoxSize,
92
+ height: monthBoxSize,
93
+ cursor: "default",
94
+ backgroundColor: dayColor(new Date(date.getFullYear(), date.getMonth(), d)),
95
+ }, children: _jsx(Tooltip, { title: tooltip(new Date(date.getFullYear(), date.getMonth(), d)), children: _jsx(Box, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", children: d }) }) }, i)))] })] }));
96
+ }
97
+ function Warning() {
98
+ return (_jsxs(Stack, { direction: "row", spacing: 2, alignItems: "center", children: [_jsx(WarningIcon, { fontSize: "small" }), _jsx(Typography, { variant: "caption", children: "Projected dates are estimates" })] }));
99
+ }
100
+ function MonthHeatmap({ group, month }) {
101
+ const usage = useAtomValue(groupedSimDayUsage);
102
+ const [minDay, maxDay] = useAtomValue(minAndMaxUsageDay);
103
+ const maxUse = useAtomValue(maxUsage);
104
+ const dayColor = useMemo(() => {
105
+ const scale = scaleLinear().domain([0, maxUse]).range([color1, color2]);
106
+ return (d) => {
107
+ if (maxDay && d > maxDay) {
108
+ return "white";
109
+ }
110
+ if (minDay && d < minDay) {
111
+ return "white";
112
+ }
113
+ const u = usage?.get(group)?.get(d);
114
+ if (u) {
115
+ return scale(u.usage);
116
+ }
117
+ else {
118
+ return downtimeColor;
119
+ }
120
+ };
121
+ }, [usage, maxUse, minDay, maxDay, group]);
122
+ function tooltip(d) {
123
+ const u = usage?.get(group)?.get(d);
124
+ return (_jsxs(_Fragment, { children: [_jsx("div", { children: d.toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric" }) }), maxDay && d > maxDay ? (_jsx("div", { children: "Not Simulated" })) : minDay && d < minDay ? (_jsx("div", {})) : u ? (_jsxs("div", { children: ["Usage: ", u.usage.toFixed(2)] })) : (_jsx("div", { children: "Downtime" }))] }));
125
+ }
126
+ return _jsx(ShowMonth, { date: month, dayColor: dayColor, tooltip: tooltip });
127
+ }
128
+ export function SimDayUsagePage() {
129
+ useSetTitle("Projected Machine Usage");
130
+ const groups = useAtomValue(machineGroups);
131
+ const months = useAtomValue(usageMonths);
132
+ return (_jsx(Box, { component: "main", padding: "24px", children: _jsxs(Stack, { direction: "column", spacing: 5, children: [_jsx(Warning, {}), groups.toAscLazySeq().map((g) => (_jsxs("div", { children: [_jsx(Typography, { variant: "h4", children: g }), _jsx(Box, { display: "flex", flexWrap: "wrap", columnGap: "50px", children: months.toAscLazySeq().map((m) => (_jsx(MonthHeatmap, { group: g, month: m }, m.getTime()))) })] }, g)))] }) }));
133
+ }
@@ -0,0 +1,3 @@
1
+ import { ReactNode } from "react";
2
+ export declare function ToolSummaryTable(): ReactNode;
3
+ export declare function ToolReportPage(): ReactNode;
@@ -0,0 +1,233 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } 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 { useState, Fragment } from "react";
35
+ import { Fab, styled, Box, FormControl } from "@mui/material";
36
+ import { CircularProgress } from "@mui/material";
37
+ import TimeAgo from "react-timeago";
38
+ import { Table } from "@mui/material";
39
+ import { TableHead } from "@mui/material";
40
+ import { TableCell } from "@mui/material";
41
+ import { TableRow } from "@mui/material";
42
+ import { Tooltip } from "@mui/material";
43
+ import { TableBody } from "@mui/material";
44
+ import { IconButton } from "@mui/material";
45
+ import { Select } from "@mui/material";
46
+ import { MenuItem } from "@mui/material";
47
+ import { Collapse } from "@mui/material";
48
+ import { Refresh as RefreshIcon, ImportExport, KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, } from "@mui/icons-material";
49
+ import { currentToolReport, toolReportRefreshTime, machinesWithTools, toolReportHasSerial, useCopyToolReportToClipboard, toolReportEstimatedToolCounts, } from "../../data/tools-programs.js";
50
+ import { LazySeq } from "@seedtactics/immutable-collections";
51
+ import { PartIdenticon } from "../station-monitor/Material.js";
52
+ import { useIsDemo, useSetTitle } from "../routes.js";
53
+ import { DisplayLoadingAndError } from "../ErrorsAndLoading.js";
54
+ import { atom, useAtom, useAtomValue } from "jotai";
55
+ const cntFormat = new Intl.NumberFormat("en-US", {
56
+ minimumFractionDigits: 0,
57
+ maximumFractionDigits: 1,
58
+ });
59
+ const ToolTableRow = styled(TableRow, { shouldForwardProp: (prop) => prop.toString()[0] !== "$" })(({ theme, $noBorderBottom, $highlightedRow, $noticeRow }) => ({
60
+ ...($noBorderBottom && {
61
+ "& > *": {
62
+ borderBottom: "unset",
63
+ },
64
+ }),
65
+ [theme.breakpoints.up("lg")]: {
66
+ "& td:not(:last-child), & th:not(:last-child)": {
67
+ whiteSpace: "nowrap",
68
+ },
69
+ "& td:last-child, & th:last-child": {
70
+ width: "100%",
71
+ },
72
+ },
73
+ backgroundColor: $highlightedRow ? "#BDBDBD" : $noticeRow ? "#E0E0E0" : undefined,
74
+ }));
75
+ const MachineDetailTableRow = styled(TableRow, { shouldForwardProp: (prop) => prop.toString()[0] !== "$" })(({ $borderBottom }) => ({
76
+ ...($borderBottom && {
77
+ "&:not(:last-child)": {
78
+ borderBottom: "2px solid black",
79
+ },
80
+ }),
81
+ }));
82
+ const VerticalSeperator = styled("span")({
83
+ fontSize: "x-large",
84
+ fontWeight: "lighter",
85
+ });
86
+ function FormatMinAndCnt({ min, cnt, showZero, extraMin, extraCnt, }) {
87
+ min ??= 0;
88
+ cnt ??= 0;
89
+ const minSpan = extraMin ? (_jsx(Tooltip, { title: extraMin, children: _jsxs("span", { children: [min.toFixed(1), " min"] }) })) : (min.toFixed(1) + " min");
90
+ const cntSpan = extraCnt ? (_jsx(Tooltip, { title: extraCnt, children: _jsxs("span", { children: [cntFormat.format(cnt), " cnt"] }) })) : (cntFormat.format(cnt) + " cnt");
91
+ if (min === 0 && cnt === 0) {
92
+ if (showZero) {
93
+ return "0";
94
+ }
95
+ else {
96
+ return "";
97
+ }
98
+ }
99
+ else if (min > 0 && cnt === 0) {
100
+ return minSpan;
101
+ }
102
+ else if (min === 0 && cnt > 0) {
103
+ return cntSpan;
104
+ }
105
+ else {
106
+ return (_jsxs("span", { children: [minSpan, " ", _jsx(VerticalSeperator, { children: "|" }), " ", cntSpan] }));
107
+ }
108
+ }
109
+ function PartDetailTable({ tool, machine }) {
110
+ const parts = machine
111
+ ? LazySeq.of(tool.parts).filter((p) => p.machines.has(machine))
112
+ : LazySeq.of(tool.parts);
113
+ return (_jsxs(Table, { size: "small", sx: {
114
+ width: "auto",
115
+ ml: "10em",
116
+ mb: "1em",
117
+ }, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Part" }), _jsx(TableCell, { children: "Program" }), !machine ? _jsx(TableCell, { children: "Machines" }) : undefined, _jsx(TableCell, { align: "right", children: "Quantity" }), _jsx(TableCell, { align: "right", children: "Use/Cycle (min)" }), _jsx(TableCell, { align: "right", children: "Use/Cycle (cnt)" })] }) }), _jsx(TableBody, { children: parts.isEmpty() ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 5, children: "No programs use this machine" }) })) : (parts.map((p, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs(Box, { sx: {
118
+ display: "flex",
119
+ alignItems: "center",
120
+ }, children: [_jsx(PartIdenticon, { part: p.partAndProg.part, size: 20 }), _jsx("span", { children: p.partAndProg.part })] }) }), _jsx(TableCell, { children: p.partAndProg.operation }), !machine ? (_jsx(TableCell, { children: p.machines.foldl((acc, m) => (acc.length > 0 ? acc + ", " : "") + m, "") })) : undefined, _jsx(TableCell, { align: "right", children: p.quantity }), _jsx(TableCell, { align: "right", children: p.scheduledUseMinutes > 0 ? p.scheduledUseMinutes.toFixed(1) : "" }), _jsx(TableCell, { align: "right", children: p.scheduledUseCnt > 0 ? cntFormat.format(p.scheduledUseCnt) : "" })] }, idx)))) })] }));
121
+ }
122
+ function MachineDetailTable({ machines }) {
123
+ const showSerial = useAtomValue(toolReportHasSerial);
124
+ const byMachine = LazySeq.of(machines).toLookupOrderedMap((m) => m.machineName, (m) => m.pocket);
125
+ const anyHasSubtotal = byMachine.size > 1 && byMachine.valuesToAscLazySeq().some((tools) => tools.size > 1);
126
+ return (_jsxs(Table, { size: "small", sx: {
127
+ width: "auto",
128
+ ml: "10em",
129
+ mb: "1em",
130
+ }, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Machine" }), _jsx(TableCell, { align: "right", children: "Pocket" }), showSerial ? _jsx(TableCell, { children: "Serial" }) : undefined, _jsx(TableCell, { align: "right", children: "Current Use " }), _jsx(TableCell, { align: "right", children: "Lifetime " }), _jsx(TableCell, { align: "right", children: "Remaining Use " })] }) }), _jsxs(TableBody, { children: [byMachine.toAscLazySeq().map(([mach, tools]) => (_jsxs(Fragment, { children: [tools.valuesToAscLazySeq().map((m, idx) => (_jsxs(MachineDetailTableRow, { "$borderBottom": anyHasSubtotal && tools.size === 1, children: [_jsx(TableCell, { children: m.machineName }), _jsx(TableCell, { align: "right", children: m.pocket }), showSerial ? _jsx(TableCell, { children: m.serial ?? "" }) : undefined, _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: m.currentUseMinutes, cnt: m.currentUseCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: m.lifetimeMinutes, cnt: m.lifetimeCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: m.remainingMinutes, cnt: m.remainingCnt, showZero: true }) })] }, idx))), byMachine.size > 1 && tools.size > 1 ? (_jsxs(MachineDetailTableRow, { "$borderBottom": true, children: [_jsx(TableCell, { colSpan: showSerial ? 4 : 3 }), _jsx(TableCell, { children: "Subtotal" }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: tools.valuesToAscLazySeq().sumBy((m) => m.remainingMinutes ?? 0), cnt: tools.valuesToAscLazySeq().sumBy((m) => m.remainingCnt ?? 0) }) })] })) : undefined] }, mach))), _jsxs(TableRow, { children: [_jsx(TableCell, { colSpan: showSerial ? 4 : 3 }), _jsx(TableCell, { children: "Total" }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: LazySeq.of(machines).sumBy((m) => m.remainingMinutes ?? 0), cnt: LazySeq.of(machines).sumBy((m) => m.remainingCnt ?? 0) }) })] })] })] }));
131
+ }
132
+ function ToolSummaryHeader() {
133
+ const cntsWereEstimated = useAtomValue(toolReportEstimatedToolCounts);
134
+ return (_jsxs(ToolTableRow, { children: [_jsx(TableCell, {}), _jsx(TableCell, { children: "Tool" }), _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Expected use for all currently scheduled parts." +
135
+ (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Scheduled Use" }) }) }), _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Remaining use summed over all machines which have a scheduled part." +
136
+ (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Total Remaining Use" }) }) }), _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Machine with the least remaining use." + (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Smallest Remaining Use" }) }) }), _jsx(TableCell, {})] }));
137
+ }
138
+ function ToolSummaryRow({ tool }) {
139
+ const [open, setOpen] = useState(false);
140
+ const machinesWithSomePart = LazySeq.of(tool.machines).filter((m) => tool.parts.some((p) => p.machines.has(m.machineName)));
141
+ const schUseMin = LazySeq.of(tool.parts).sumBy((p) => p.scheduledUseMinutes * p.quantity);
142
+ const schUseCnt = LazySeq.of(tool.parts).sumBy((p) => p.scheduledUseCnt * p.quantity);
143
+ const totalRemainMin = machinesWithSomePart.sumBy((m) => m.remainingMinutes ?? 0);
144
+ const totalRemainCnt = machinesWithSomePart.sumBy((m) => m.remainingCnt ?? 0);
145
+ const minRemainMin = machinesWithSomePart
146
+ .groupBy((m) => m.machineName)
147
+ .map(([mach, tools]) => ({ mach, remainMin: LazySeq.of(tools).sumBy((m) => m.remainingMinutes ?? 0) }))
148
+ .minBy(({ remainMin }) => remainMin);
149
+ const minRemainCnt = machinesWithSomePart
150
+ .groupBy((m) => m.machineName)
151
+ .map(([mach, tools]) => ({ mach, remainCnt: LazySeq.of(tools).sumBy((m) => m.remainingCnt ?? 0) }))
152
+ .minBy(({ remainCnt }) => remainCnt);
153
+ const numCols = 6;
154
+ return (_jsxs(_Fragment, { children: [_jsxs(ToolTableRow, { "$noBorderBottom": true, "$highlightedRow": schUseMin > totalRemainMin || schUseCnt > totalRemainCnt, "$noticeRow": schUseMin <= totalRemainMin &&
155
+ schUseCnt <= totalRemainCnt &&
156
+ ((minRemainMin && schUseMin > minRemainMin.remainMin) ||
157
+ (minRemainCnt && schUseCnt > minRemainCnt.remainCnt)), children: [_jsx(TableCell, { children: _jsx(IconButton, { size: "small", onClick: () => setOpen(!open), children: open ? _jsx(KeyboardArrowUpIcon, {}) : _jsx(KeyboardArrowDownIcon, {}) }) }), _jsx(TableCell, { children: tool.toolName }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: schUseMin, cnt: schUseCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: totalRemainMin, cnt: totalRemainCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: minRemainMin?.remainMin, cnt: minRemainCnt?.remainCnt, showZero: true, extraMin: minRemainMin?.mach, extraCnt: minRemainCnt?.mach }) }), _jsx(TableCell, {})] }), _jsx(TableRow, { children: _jsx(TableCell, { sx: { pb: "0", pt: "0" }, colSpan: numCols, children: _jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: _jsxs(Box, { sx: {
158
+ display: "flex",
159
+ flexWrap: "wrap",
160
+ justifyContent: "space-around",
161
+ ml: "1em",
162
+ mr: "1em",
163
+ }, children: [_jsx("div", { children: _jsx(MachineDetailTable, { machines: tool.machines }) }), tool.parts.length === 0 ? undefined : (_jsx("div", { children: _jsx(PartDetailTable, { tool: tool }) }))] }) }) }) })] }));
164
+ }
165
+ function ToolMachineHeader({ machine }) {
166
+ const cntsWereEstimated = useAtomValue(toolReportEstimatedToolCounts);
167
+ const showSerial = useAtomValue(toolReportHasSerial);
168
+ return (_jsxs(ToolTableRow, { children: [_jsx(TableCell, {}), _jsxs(TableCell, { children: ["Tool In ", machine] }), _jsx(TableCell, { align: "right", children: "Pocket" }), showSerial ? _jsx(TableCell, { children: "Serial" }) : undefined, _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Expected use for all currently scheduled parts." +
169
+ (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Scheduled Use" }) }) }), _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Current recorded usage of this tool." + (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Current Use" }) }) }), _jsxs(TableCell, { align: "right", children: [_jsx(Tooltip, { title: "Current configured lifetime of this tool." + (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Lifetime" }) }), " "] }), _jsx(TableCell, { align: "right", children: _jsx(Tooltip, { title: "Lifetime minus current use." + (cntsWereEstimated ? " Counts are estimates." : ""), children: _jsx("span", { children: "Remaining Use" }) }) }), _jsx(TableCell, {})] }));
170
+ }
171
+ function ToolMachineRow({ report, pocket }) {
172
+ const [open, setOpen] = useState(false);
173
+ const showSerial = useAtomValue(toolReportHasSerial);
174
+ const numCols = showSerial ? 9 : 8;
175
+ const schMins = LazySeq.of(report.parts)
176
+ .filter((p) => p.machines.has(pocket.machineName))
177
+ .sumBy((p) => p.scheduledUseMinutes * p.quantity);
178
+ const schCnts = LazySeq.of(report.parts)
179
+ .filter((p) => p.machines.has(pocket.machineName))
180
+ .sumBy((p) => p.scheduledUseCnt * p.quantity);
181
+ return (_jsxs(_Fragment, { children: [_jsxs(ToolTableRow, { "$noBorderBottom": true, children: [_jsx(TableCell, { children: _jsx(IconButton, { size: "small", onClick: () => setOpen(!open), children: open ? _jsx(KeyboardArrowUpIcon, {}) : _jsx(KeyboardArrowDownIcon, {}) }) }), _jsx(TableCell, { children: report.toolName }), _jsx(TableCell, { align: "right", children: pocket.pocket }), showSerial ? _jsx(TableCell, { children: pocket.serial ?? "" }) : undefined, _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: schMins, cnt: schCnts }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: pocket.currentUseMinutes, cnt: pocket.currentUseCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: pocket.lifetimeMinutes, cnt: pocket.lifetimeCnt }) }), _jsx(TableCell, { align: "right", children: _jsx(FormatMinAndCnt, { min: pocket.remainingMinutes, cnt: pocket.remainingCnt }) }), _jsx(TableCell, {})] }), _jsx(TableRow, { children: _jsx(TableCell, { sx: { pb: "0", pt: "0" }, colSpan: numCols, children: _jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: _jsx(PartDetailTable, { tool: report, machine: pocket.machineName }) }) }) })] }));
182
+ }
183
+ const FilterAnyMachineKey = "__Insight__FilterAnyMachine__";
184
+ const toolReportMachineFilter = atom(null);
185
+ export function ToolSummaryTable() {
186
+ const machineFilter = useAtomValue(toolReportMachineFilter);
187
+ const tools = useAtomValue(currentToolReport);
188
+ if (tools === null) {
189
+ return _jsx("div", {});
190
+ }
191
+ return (_jsxs(Table, { stickyHeader: true, children: [_jsx(TableHead, { children: machineFilter === null ? _jsx(ToolSummaryHeader, {}) : _jsx(ToolMachineHeader, { machine: machineFilter }) }), _jsx(TableBody, { children: tools.map((tool) => machineFilter === null ? (_jsx(ToolSummaryRow, { tool: tool }, tool.toolName)) : (_jsx(Fragment, { children: tool.machines
192
+ .filter((m) => m.machineName === machineFilter)
193
+ .map((m) => (_jsx(ToolMachineRow, { report: tool, pocket: m }, m.pocket))) }, tool.toolName))) })] }));
194
+ }
195
+ function ToolNavHeader() {
196
+ const [machineFilter, setMachineFilter] = useAtom(toolReportMachineFilter);
197
+ const [reloadTime, refreshReport] = useAtom(toolReportRefreshTime);
198
+ const [loading, setLoading] = useState(false);
199
+ const machineNames = useAtomValue(machinesWithTools);
200
+ const copyToolReportToClipboard = useCopyToolReportToClipboard();
201
+ const demo = useIsDemo();
202
+ function refresh() {
203
+ setLoading(true);
204
+ refreshReport(new Date())
205
+ .catch(console.log)
206
+ .finally(() => setLoading(false));
207
+ }
208
+ if (demo) {
209
+ return _jsx("div", {});
210
+ }
211
+ else if (reloadTime === null) {
212
+ return (_jsx("main", { style: { margin: "2em", display: "flex", justifyContent: "center" }, children: _jsx(Fab, { color: "secondary", size: "large", variant: "extended", style: { margin: "2em" }, onClick: refresh, disabled: loading, children: _jsxs(_Fragment, { children: [loading ? (_jsx(CircularProgress, { size: 10, style: { marginRight: "1em" } })) : (_jsx(RefreshIcon, { fontSize: "inherit", style: { marginRight: "1em" } })), "Load Tools"] }) }) }));
213
+ }
214
+ else {
215
+ return (_jsxs(Box, { component: "nav", sx: {
216
+ display: "flex",
217
+ minHeight: "2.5em",
218
+ alignItems: "center",
219
+ maxWidth: "calc(100vw - 24px - 24px)",
220
+ }, children: [_jsx(Tooltip, { title: "Refresh Tools", children: _jsx("div", { children: _jsx(IconButton, { onClick: refresh, disabled: loading, size: "small", children: loading ? _jsx(CircularProgress, { size: 10 }) : _jsx(RefreshIcon, { fontSize: "inherit" }) }) }) }), _jsxs("span", { style: { marginLeft: "1em" }, children: ["Tools from ", _jsx(TimeAgo, { date: reloadTime })] }), _jsx("div", { style: { flexGrow: "1" } }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: machineFilter ?? FilterAnyMachineKey, style: { marginLeft: "1em" }, onChange: (e) => {
221
+ if (e.target.value === FilterAnyMachineKey) {
222
+ setMachineFilter(null);
223
+ }
224
+ else {
225
+ setMachineFilter(e.target.value);
226
+ }
227
+ }, children: [_jsx(MenuItem, { value: FilterAnyMachineKey, children: _jsx("em", { children: "All Machines" }) }), machineNames.map((n) => (_jsx(MenuItem, { value: n, children: _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("span", { style: { marginRight: "1em" }, children: n }) }) }, n)))] }) }), _jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, onClick: copyToolReportToClipboard, size: "large", children: _jsx(ImportExport, {}) }) })] }));
228
+ }
229
+ }
230
+ export function ToolReportPage() {
231
+ useSetTitle("Tool Report");
232
+ return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsx(ToolNavHeader, {}), _jsx("main", { children: _jsx(DisplayLoadingAndError, { children: _jsx(ToolSummaryTable, {}) }) })] }));
233
+ }
@@ -0,0 +1 @@
1
+ export declare function WorkorderGantt(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,124 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /* Copyright (c) 2023, 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 { useRef, useCallback, useMemo } from "react";
35
+ import { atom, useAtomValue, useSetAtom } from "jotai";
36
+ import { green } from "@mui/material/colors";
37
+ import { LazySeq } from "@seedtactics/immutable-collections";
38
+ import { addDays, differenceInDays } from "date-fns";
39
+ import { currentStatus } from "../../cell-status/current-status";
40
+ import { Box, Stack } from "@mui/material";
41
+ import { PartIdenticon } from "../station-monitor/Material";
42
+ import { localPoint } from "../../util/chart-helpers.js";
43
+ import { AxisTop, GridCols } from "../AxisAndGrid";
44
+ import { scaleBand, scaleTime } from "d3-scale";
45
+ import { Tooltip } from "../ChartTooltip";
46
+ const tooltipData = atom(null);
47
+ const namesWidth = 150;
48
+ const marginTop = 40;
49
+ const marginBottom = 10;
50
+ const marginLeft = 20;
51
+ const marginRight = 10;
52
+ const rowSize = 80;
53
+ function workorderKey(work) {
54
+ return `${work.workorderId}-${work.part}`;
55
+ }
56
+ function utcDateOnlyToLocal(d) {
57
+ if (d) {
58
+ return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
59
+ }
60
+ else {
61
+ return null;
62
+ }
63
+ }
64
+ function useScales(workorders) {
65
+ const workKeys = workorders.map(workorderKey);
66
+ const dates = LazySeq.of(workorders)
67
+ .flatMap((w) => {
68
+ const filled = utcDateOnlyToLocal(w.simulatedFilled);
69
+ return [utcDateOnlyToLocal(w.simulatedStart), filled ? addDays(filled, 2) : null];
70
+ })
71
+ .collect((t) => t);
72
+ const start = dates.minBy((t) => t) ?? new Date();
73
+ const end = dates.maxBy((t) => t) ?? addDays(new Date(), 7);
74
+ const xMax = Math.max(differenceInDays(end, start) * 50, 30);
75
+ const yMax = Math.max(workKeys.length * rowSize, rowSize);
76
+ const xScale = scaleTime().domain([start, end]).range([0, xMax]);
77
+ const yScale = scaleBand().domain(workKeys).range([0, yMax]);
78
+ return { xScale, yScale };
79
+ }
80
+ function WorkorderTooltip({ tooltip }) {
81
+ return (_jsxs(Stack, { children: [_jsxs("div", { children: ["Workorder: ", tooltip.data.workorderId] }), _jsxs("div", { children: ["Part: ", tooltip.data.part] }), _jsxs("div", { children: ["Due Date: ", tooltip.data.dueDate.toLocaleDateString()] }), _jsxs("div", { children: ["Priority: ", tooltip.data.priority] }), _jsxs("div", { children: ["Planned Quantity: ", tooltip.data.plannedQuantity] }), _jsxs("div", { children: ["Completed Quantity: ", tooltip.data.completedQuantity] }), _jsxs("div", { children: ["Projected Start: ", utcDateOnlyToLocal(tooltip.data.simulatedStart)?.toLocaleDateString()] }), _jsxs("div", { children: ["Projected Filled: ", utcDateOnlyToLocal(tooltip.data.simulatedFilled)?.toLocaleDateString()] })] }));
82
+ }
83
+ function YAxis({ workorders }) {
84
+ return (_jsx("div", { children: workorders.map((work) => (_jsxs(Stack, { height: rowSize, direction: "column", alignItems: "flex-end", paddingRight: "10px", justifyContent: "center", children: [_jsx(Box, { children: work.workorderId }), _jsxs(Box, { display: "flex", alignItems: "center", children: [_jsx(PartIdenticon, { part: work.part, size: 18 }), _jsx(Box, { ml: "3px", children: work.part })] })] }, workorderKey(work)))) }));
85
+ }
86
+ function XAxis({ xScale, yScale }) {
87
+ return (_jsxs(_Fragment, { children: [_jsx(AxisTop, { scale: xScale, top: 0 }), _jsx(GridCols, { scale: xScale, height: yScale.range()[1] - yScale.range()[0] })] }));
88
+ }
89
+ function Series({ workorders, xScale, yScale, }) {
90
+ const setTooltip = useSetAtom(tooltipData);
91
+ const hideTooltipRef = useRef(null);
92
+ function showTooltip(w) {
93
+ return (e) => {
94
+ const pt = localPoint(e);
95
+ if (!pt)
96
+ return;
97
+ if (hideTooltipRef.current !== null) {
98
+ clearTimeout(hideTooltipRef.current);
99
+ hideTooltipRef.current = null;
100
+ }
101
+ setTooltip({
102
+ left: pt.x,
103
+ top: pt.y,
104
+ data: w,
105
+ });
106
+ };
107
+ }
108
+ const hideTooltip = useCallback(() => {
109
+ hideTooltipRef.current = setTimeout(() => {
110
+ setTooltip(null);
111
+ }, 300);
112
+ }, [hideTooltipRef, setTooltip]);
113
+ return (_jsx("g", { children: workorders.map((work) => {
114
+ const key = workorderKey(work);
115
+ return (_jsx("g", { onMouseOver: showTooltip(work), onMouseLeave: hideTooltip, children: work.simulatedStart && work.simulatedFilled ? (_jsx("rect", { x: xScale(utcDateOnlyToLocal(work.simulatedStart)), y: (yScale(key) ?? 0) + 20, width: xScale(addDays(utcDateOnlyToLocal(work.simulatedFilled), 1)) -
116
+ xScale(utcDateOnlyToLocal(work.simulatedStart)), height: rowSize - 40, fill: green[600] })) : undefined }, key));
117
+ }) }));
118
+ }
119
+ export function WorkorderGantt() {
120
+ const currentSt = useAtomValue(currentStatus);
121
+ const sortedWorkorders = useMemo(() => LazySeq.of(currentSt.workorders ?? []).toSortedArray((w) => w.simulatedFilled?.getTime() ?? null, (w) => w.simulatedStart?.getTime() ?? null, (w) => w.workorderId, (w) => w.part), [currentSt.workorders]);
122
+ const { xScale, yScale } = useScales(sortedWorkorders);
123
+ return (_jsxs(Box, { display: "flex", children: [_jsx(Box, { height: yScale.range()[1] + marginTop + marginBottom, width: namesWidth, paddingTop: `${marginTop}px`, children: _jsx(YAxis, { workorders: sortedWorkorders }) }), _jsxs(Box, { flexGrow: 1, width: 0, position: "relative", children: [_jsx("div", { style: { overflowX: "visible" }, children: _jsx("svg", { height: yScale.range()[1] + marginTop + marginBottom, width: xScale.range()[1] + marginRight + marginLeft, children: _jsxs("g", { transform: `translate(${marginLeft}, ${marginTop})`, children: [_jsx(XAxis, { yScale: yScale, xScale: xScale }), _jsx(Series, { workorders: sortedWorkorders, xScale: xScale, yScale: yScale })] }) }) }), _jsx(Tooltip, { atom: tooltipData, TooltipContent: WorkorderTooltip, chartHeight: yScale.range()[1] + marginTop + marginBottom, chartWidth: xScale.range()[1] + marginRight + marginLeft })] })] }));
124
+ }
@@ -0,0 +1,2 @@
1
+ export declare function PartLookupStepper(): import("react/jsx-runtime").JSX.Element;
2
+ export declare function QualityMaterialPage(): import("react/jsx-runtime").JSX.Element;