@seedtactics/insight-client 16.5.2 → 16.7.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 (110) hide show
  1. package/dist/assets/ProgramHighlight-DPTeZ8Si.js +3 -0
  2. package/dist/assets/index-bPAFn3jp.js +364 -0
  3. package/dist/cell-status/basket-cycles.d.ts +21 -0
  4. package/dist/cell-status/basket-cycles.js +80 -0
  5. package/dist/cell-status/current-status.js +11 -3
  6. package/dist/cell-status/estimated-cycle-times.js +8 -4
  7. package/dist/cell-status/inspections.js +2 -2
  8. package/dist/cell-status/loading.js +4 -0
  9. package/dist/cell-status/material-details.d.ts +12 -4
  10. package/dist/cell-status/material-details.js +24 -13
  11. package/dist/cell-status/rebookings.js +15 -17
  12. package/dist/cell-status/scheduled-jobs.d.ts +1 -1
  13. package/dist/cell-status/scheduled-jobs.js +10 -3
  14. package/dist/cell-status/sim-production.js +3 -3
  15. package/dist/cell-status/sim-station-use.d.ts +1 -0
  16. package/dist/cell-status/sim-station-use.js +14 -8
  17. package/dist/cell-status/station-cycles.d.ts +29 -2
  18. package/dist/cell-status/station-cycles.js +81 -11
  19. package/dist/cell-status/tool-replacements.js +1 -1
  20. package/dist/cell-status/tool-usage.js +1 -1
  21. package/dist/components/App.js +101 -66
  22. package/dist/components/BarcodeScanning.js +12 -2
  23. package/dist/components/ErrorsAndLoading.js +10 -1
  24. package/dist/components/LogEntry.d.ts +0 -1
  25. package/dist/components/LogEntry.js +50 -26
  26. package/dist/components/Navigation.js +30 -4
  27. package/dist/components/analysis/AnalysisSelectToolbar.js +5 -1
  28. package/dist/components/analysis/BasketCycleCards.d.ts +1 -0
  29. package/dist/components/analysis/BasketCycleCards.js +145 -0
  30. package/dist/components/analysis/BufferChart.js +10 -4
  31. package/dist/components/analysis/CostPerPiece.js +28 -8
  32. package/dist/components/analysis/CycleChart.js +1 -1
  33. package/dist/components/analysis/DataTable.js +6 -4
  34. package/dist/components/analysis/HeatChart.js +27 -14
  35. package/dist/components/analysis/InspectionSankey.js +17 -6
  36. package/dist/components/analysis/PalletCycleCards.js +15 -4
  37. package/dist/components/analysis/PartCycleCards.js +62 -18
  38. package/dist/components/analysis/StationDataTable.js +14 -11
  39. package/dist/components/analysis/ToolReplacements.js +16 -10
  40. package/dist/components/log-entry-queue-filter.d.ts +2 -0
  41. package/dist/components/log-entry-queue-filter.js +21 -0
  42. package/dist/components/operations/AllMaterial.js +26 -10
  43. package/dist/components/operations/ChartRangeEdit.js +82 -4
  44. package/dist/components/operations/CloseoutReport.js +13 -4
  45. package/dist/components/operations/CompletedParts.js +23 -11
  46. package/dist/components/operations/CurrentWorkorders.js +31 -9
  47. package/dist/components/operations/OEEChart.js +8 -2
  48. package/dist/components/operations/Outliers.js +18 -7
  49. package/dist/components/operations/ProgramHighlight.js +4 -6
  50. package/dist/components/operations/Programs.js +9 -3
  51. package/dist/components/operations/Rebookings.js +8 -4
  52. package/dist/components/operations/RecentCycleChart.js +5 -3
  53. package/dist/components/operations/RecentProduction.js +30 -13
  54. package/dist/components/operations/RecentSchedules.js +6 -2
  55. package/dist/components/operations/RecentStationCycles.js +38 -11
  56. package/dist/components/operations/ShiftSettings.js +3 -3
  57. package/dist/components/operations/SimDayUsage.js +27 -4
  58. package/dist/components/operations/ToolReport.js +5 -1
  59. package/dist/components/operations/WorkorderGantt.js +22 -2
  60. package/dist/components/quality/QualityMaterial.js +11 -8
  61. package/dist/components/quality/RecentFailedInspections.js +3 -1
  62. package/dist/components/routes.d.ts +3 -0
  63. package/dist/components/routes.js +2 -0
  64. package/dist/components/station-monitor/BulkRawMaterial.js +11 -7
  65. package/dist/components/station-monitor/Closeout.js +14 -2
  66. package/dist/components/station-monitor/CustomStationMonitorDialog.js +1 -1
  67. package/dist/components/station-monitor/Inspection.js +23 -11
  68. package/dist/components/station-monitor/InvalidateCycle.js +3 -3
  69. package/dist/components/station-monitor/JobDetails.js +15 -2
  70. package/dist/components/station-monitor/LoadStation.js +274 -31
  71. package/dist/components/station-monitor/Material.js +71 -11
  72. package/dist/components/station-monitor/MoveMaterialArrows.js +4 -4
  73. package/dist/components/station-monitor/QuarantineButton.js +11 -0
  74. package/dist/components/station-monitor/Queues.js +28 -9
  75. package/dist/components/station-monitor/QueuesAddMaterial.js +8 -6
  76. package/dist/components/station-monitor/SelectInspType.js +1 -1
  77. package/dist/components/station-monitor/SelectWorkorder.js +1 -1
  78. package/dist/components/station-monitor/StationToolbar.js +17 -5
  79. package/dist/components/station-monitor/SystemOverview.d.ts +19 -1
  80. package/dist/components/station-monitor/SystemOverview.js +439 -20
  81. package/dist/components/station-monitor/Whiteboard.js +15 -7
  82. package/dist/data/all-material-bins.d.ts +7 -0
  83. package/dist/data/all-material-bins.js +47 -1
  84. package/dist/data/cost-per-piece.js +11 -8
  85. package/dist/data/current-cycles.d.ts +1 -1
  86. package/dist/data/current-cycles.js +62 -17
  87. package/dist/data/move-arrows.d.ts +5 -1
  88. package/dist/data/move-arrows.js +54 -4
  89. package/dist/data/part-summary.js +13 -13
  90. package/dist/data/path-lookup.js +6 -23
  91. package/dist/data/queue-material.d.ts +1 -1
  92. package/dist/data/queue-material.js +18 -17
  93. package/dist/data/results.completed-parts.js +4 -3
  94. package/dist/data/results.cycles.d.ts +15 -6
  95. package/dist/data/results.cycles.js +51 -30
  96. package/dist/data/results.inspection.js +11 -6
  97. package/dist/data/results.oee.js +8 -8
  98. package/dist/data/results.schedules.js +2 -11
  99. package/dist/data/tools-programs.js +5 -6
  100. package/dist/index.html +1 -1
  101. package/dist/network/api.d.ts +22 -4
  102. package/dist/network/api.js +40 -5
  103. package/dist/network/backend-mock.js +15 -8
  104. package/dist/network/backend.js +3 -3
  105. package/dist/network/websocket.js +15 -15
  106. package/dist/util/chart-helpers.d.ts +1 -1
  107. package/dist/util/chart-helpers.js +14 -8
  108. package/package.json +29 -31
  109. package/dist/assets/ProgramHighlight-LvRM40Qr.js +0 -3
  110. package/dist/assets/index-gAFi3Oss.js +0 -364
@@ -42,16 +42,17 @@ import { ImportExport } from "@mui/icons-material";
42
42
  import { selectedAnalysisPeriod } from "../../network/load-specific-month.js";
43
43
  import { CycleChart } from "./CycleChart.js";
44
44
  import * as matDetails from "../../cell-status/material-details.js";
45
- import { filterStationCycles, FilterAnyMachineKey, copyCyclesToClipboard, plannedOperationMinutes, loadOccupancyCycles, FilterAnyLoadKey, emptyStationCycles, } from "../../data/results.cycles.js";
45
+ import { filterStationCycles, FilterAnyMachineKey, copyCyclesToClipboard, plannedOperationMinutes, loadOccupancyCycles, FilterAnyLoadKey, emptyStationCycles, normalizeCarrierKindFilter, } from "../../data/results.cycles.js";
46
46
  import { PartIdenticon } from "../station-monitor/Material.js";
47
47
  import StationDataTable from "./StationDataTable.js";
48
48
  import { useSetTitle, isDemoAtom } from "../routes.js";
49
49
  import { last30MaterialSummary, specificMonthMaterialSummary } from "../../cell-status/material-summary.js";
50
50
  import { last30EstimatedCycleTimes, PartAndStationOperation, specificMonthEstimatedCycleTimes, } from "../../cell-status/estimated-cycle-times.js";
51
- import { last30StationCycles, specificMonthStationCycles } from "../../cell-status/station-cycles.js";
51
+ import { basketDisplayName, last30HasBasketCycles, last30StationCycles, specificMonthHasBasketCycles, specificMonthStationCycles, } from "../../cell-status/station-cycles.js";
52
52
  import { LazySeq, OrderedMap } from "@seedtactics/immutable-collections";
53
53
  import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
54
54
  import { atomWithDefault } from "jotai/utils";
55
+ import { fmsInformation } from "../../network/server-settings.js";
55
56
  const dateTimeFormat = new Intl.DateTimeFormat(undefined, {
56
57
  weekday: "short",
57
58
  month: "short",
@@ -59,6 +60,12 @@ const dateTimeFormat = new Intl.DateTimeFormat(undefined, {
59
60
  hour: "numeric",
60
61
  minute: "2-digit",
61
62
  });
63
+ function isPartCycleChartData(point) {
64
+ return "material" in point && Array.isArray(point.material);
65
+ }
66
+ function hasLoadCycleOperations(point) {
67
+ return "operations" in point && (point.operations === undefined || Array.isArray(point.operations));
68
+ }
62
69
  function DisplayDateRange({ range }) {
63
70
  const period = useAtomValue(selectedAnalysisPeriod);
64
71
  if (!range)
@@ -104,9 +111,11 @@ export function PartMachineCycleChart() {
104
111
  useSetTitle("Machine Cycles");
105
112
  const setMatToShow = useSetAtom(matDetails.materialDialogOpen);
106
113
  const extraStationCycleTooltip = useCallback(function extraStationCycleTooltip(point) {
107
- const partC = point;
114
+ if (!isPartCycleChartData(point)) {
115
+ return [];
116
+ }
108
117
  const ret = [];
109
- for (const mat of partC.material) {
118
+ for (const mat of point.material) {
110
119
  ret.push({
111
120
  title: mat.serial ? mat.serial : "Material",
112
121
  value: "Open Card",
@@ -174,12 +183,18 @@ export function PartMachineCycleChart() {
174
183
  return undefined;
175
184
  }
176
185
  }, [points, curOperation]);
177
- return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsxs(Box, { component: "nav", sx: {
186
+ return (_jsxs(Box, { sx: {
187
+ paddingLeft: "24px",
188
+ paddingRight: "24px",
189
+ paddingTop: "10px",
190
+ }, children: [_jsxs(Box, { component: "nav", sx: {
178
191
  display: "flex",
179
192
  minHeight: "2.5em",
180
193
  alignItems: "center",
181
194
  maxWidth: "calc(100vw - 24px - 24px)",
182
- }, children: [_jsxs(Typography, { variant: "subtitle1", children: ["Machine Cycles for ", _jsx(DisplayDateRange, { range: zoomDateRange ?? defaultDateRange })] }), _jsx(Box, { flexGrow: 1 }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showGraph ? "graph" : "table", onChange: (e) => setShowGraph(e.target.value === "graph"), children: [_jsx(MenuItem, { value: "graph", children: "Graph" }, "graph"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPart
195
+ }, children: [_jsxs(Typography, { variant: "subtitle1", children: ["Machine Cycles for ", _jsx(DisplayDateRange, { range: zoomDateRange ?? defaultDateRange })] }), _jsx(Box, { sx: {
196
+ flexGrow: 1,
197
+ } }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showGraph ? "graph" : "table", onChange: (e) => setShowGraph(e.target.value === "graph"), children: [_jsx(MenuItem, { value: "graph", children: "Graph" }, "graph"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPart
183
198
  ? points.allPartAndProcNames.findIndex((o) => selectedPart.part === o.part && selectedPart.proc === o.proc)
184
199
  : -1, style: { marginLeft: "1em" }, onChange: (e) => {
185
200
  setSelectedPart(e.target.value === -1 ? undefined : points.allPartAndProcNames[e.target.value]);
@@ -190,9 +205,12 @@ export function PartMachineCycleChart() {
190
205
  : -1
191
206
  : selectedMachine, style: { marginLeft: "1em" }, onChange: (e) => {
192
207
  if (selectedPart) {
193
- setSelectedOperation(points.allMachineOperations[e.target.value]);
208
+ const selectedIdx = typeof e.target.value === "number" ? e.target.value : Number.parseInt(e.target.value, 10);
209
+ if (!Number.isNaN(selectedIdx)) {
210
+ setSelectedOperation(selectedIdx === -1 ? undefined : points.allMachineOperations[selectedIdx]);
211
+ }
194
212
  }
195
- else {
213
+ else if (typeof e.target.value === "string") {
196
214
  setSelectedMachine(e.target.value);
197
215
  }
198
216
  }, children: selectedPart
@@ -215,6 +233,7 @@ const loadShowGraph = atom(true);
215
233
  const loadSelectedPart = atomWithDefault((get) => get(isDemoAtom) ? { part: "aaa", proc: 2 } : undefined);
216
234
  const loadSelectedOperation = atomWithDefault((get) => get(isDemoAtom) ? "LoadOp" : "LULOccupancy");
217
235
  const loadSelectedLoad = atom(FilterAnyLoadKey);
236
+ const loadSelectedCarrier = atom("Any");
218
237
  const loadSelectedPallet = atom(undefined);
219
238
  const loadZoomDateRangeRecent = atom(undefined);
220
239
  const loadZoomDateRangeByMonth = atom(OrderedMap.empty());
@@ -240,10 +259,12 @@ export function PartLoadStationCycleChart() {
240
259
  useSetTitle("L/U Cycles");
241
260
  const setMatToShow = useSetAtom(matDetails.materialDialogOpen);
242
261
  const extraLoadCycleTooltip = useCallback(function extraLoadCycleTooltip(point) {
243
- const partC = point;
262
+ if (!hasLoadCycleOperations(point)) {
263
+ return [];
264
+ }
244
265
  const ret = [];
245
- if (partC.operations) {
246
- for (const mat of partC.operations) {
266
+ if (point.operations) {
267
+ for (const mat of point.operations) {
247
268
  ret.push({
248
269
  title: (mat.mat.serial ? mat.mat.serial : "Material") + " " + mat.operation,
249
270
  value: "Open Card",
@@ -258,13 +279,18 @@ export function PartLoadStationCycleChart() {
258
279
  const [selectedPart, setSelectedPart] = useAtom(loadSelectedPart);
259
280
  const [selectedOperation, setSelectedOperation] = useAtom(loadSelectedOperation);
260
281
  const [selectedLoadStation, setSelectedLoadStation] = useAtom(loadSelectedLoad);
282
+ const [selectedCarrier, setSelectedCarrier] = useAtom(loadSelectedCarrier);
261
283
  const [selectedPallet, setSelectedPallet] = useAtom(loadSelectedPallet);
262
284
  const [zoomDateRange, setZoomRange] = useAtom(loadZoomDateRange);
263
285
  const [yZoom, setYZoom] = useAtom(loadYZoom);
286
+ const fmsInfo = useAtomValue(fmsInformation);
287
+ const basketName = basketDisplayName(fmsInfo.basketName);
288
+ const hasBasketCycles = useAtomValue(period.type === "Last30" ? last30HasBasketCycles : specificMonthHasBasketCycles);
289
+ const carrierFilter = normalizeCarrierKindFilter(selectedCarrier, hasBasketCycles);
264
290
  const curOperation = useMemo(() => selectedPart && selectedOperation === "LoadOp"
265
- ? new PartAndStationOperation(selectedPart.part, "L/U", "LOAD" + "-" + selectedPart.proc.toString())
291
+ ? new PartAndStationOperation(selectedPart.part, "L/U", `LOAD-${selectedPart.proc}`)
266
292
  : selectedPart && selectedOperation === "UnloadOp"
267
- ? new PartAndStationOperation(selectedPart.part, "L/U", "UNLOAD" + "-" + selectedPart.proc.toString())
293
+ ? new PartAndStationOperation(selectedPart.part, "L/U", `UNLOAD-${selectedPart.proc}`)
268
294
  : null, [selectedPart, selectedOperation]);
269
295
  const defaultDateRange = period.type === "Last30"
270
296
  ? [addDays(startOfToday(), -29), addDays(startOfToday(), 1)]
@@ -273,12 +299,16 @@ export function PartLoadStationCycleChart() {
273
299
  const matSummary = useAtomValue(period.type === "Last30" ? last30MaterialSummary : specificMonthMaterialSummary);
274
300
  const estimatedCycleTimes = useAtomValue(period.type === "Last30" ? last30EstimatedCycleTimes : specificMonthEstimatedCycleTimes);
275
301
  const points = useMemo(() => {
276
- if (selectedPart || selectedPallet || selectedLoadStation !== FilterAnyLoadKey) {
302
+ if (selectedPart ||
303
+ selectedPallet ||
304
+ selectedLoadStation !== FilterAnyLoadKey ||
305
+ carrierFilter !== "Any") {
277
306
  if (curOperation) {
278
307
  return filterStationCycles(cycles.valuesToLazySeq(), {
279
308
  operation: curOperation,
280
309
  pallet: selectedPallet,
281
310
  station: selectedLoadStation,
311
+ carrierKind: carrierFilter,
282
312
  });
283
313
  }
284
314
  else if (showGraph) {
@@ -286,6 +316,7 @@ export function PartLoadStationCycleChart() {
286
316
  partAndProc: selectedPart,
287
317
  pallet: selectedPallet,
288
318
  station: selectedLoadStation,
319
+ carrierKind: carrierFilter,
289
320
  });
290
321
  }
291
322
  else {
@@ -293,13 +324,14 @@ export function PartLoadStationCycleChart() {
293
324
  partAndProc: selectedPart,
294
325
  pallet: selectedPallet,
295
326
  station: selectedLoadStation,
327
+ carrierKind: carrierFilter,
296
328
  });
297
329
  }
298
330
  }
299
331
  else {
300
332
  return emptyStationCycles(cycles.valuesToLazySeq());
301
333
  }
302
- }, [selectedPart, selectedPallet, curOperation, selectedLoadStation, cycles, showGraph]);
334
+ }, [selectedPart, selectedPallet, curOperation, selectedLoadStation, cycles, showGraph, carrierFilter]);
303
335
  const plannedMinutes = useMemo(() => {
304
336
  if (selectedOperation === "LoadOp" || selectedOperation === "UnloadOp") {
305
337
  return plannedOperationMinutes(points, true);
@@ -308,12 +340,18 @@ export function PartLoadStationCycleChart() {
308
340
  return undefined;
309
341
  }
310
342
  }, [points, selectedOperation]);
311
- return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsxs(Box, { component: "nav", sx: {
343
+ return (_jsxs(Box, { sx: {
344
+ paddingLeft: "24px",
345
+ paddingRight: "24px",
346
+ paddingTop: "10px",
347
+ }, children: [_jsxs(Box, { component: "nav", sx: {
312
348
  display: "flex",
313
349
  minHeight: "2.5em",
314
350
  alignItems: "center",
315
351
  maxWidth: "calc(100vw - 24px - 24px)",
316
- }, children: [_jsxs(Typography, { variant: "subtitle1", children: ["Load/Unload Cycles for ", _jsx(DisplayDateRange, { range: zoomDateRange ?? defaultDateRange })] }), _jsx(Box, { flexGrow: 1 }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showGraph ? "graph" : "table", onChange: (e) => setShowGraph(e.target.value === "graph"), children: [_jsx(MenuItem, { value: "graph", children: "Graph" }, "graph"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPart
352
+ }, children: [_jsxs(Typography, { variant: "subtitle1", children: ["Load/Unload Cycles for ", _jsx(DisplayDateRange, { range: zoomDateRange ?? defaultDateRange })] }), _jsx(Box, { sx: {
353
+ flexGrow: 1,
354
+ } }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showGraph ? "graph" : "table", onChange: (e) => setShowGraph(e.target.value === "graph"), children: [_jsx(MenuItem, { value: "graph", children: "Graph" }, "graph"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPart
317
355
  ? points.allPartAndProcNames.findIndex((o) => selectedPart.part === o.part && selectedPart.proc === o.proc)
318
356
  : -1, style: { marginLeft: "1em" }, onChange: (e) => {
319
357
  if (e.target.value === -1) {
@@ -325,7 +363,13 @@ export function PartLoadStationCycleChart() {
325
363
  }
326
364
  }, children: [_jsx(MenuItem, { value: -1, children: _jsx("em", { children: "Any Part" }) }, 0), points.allPartAndProcNames.map((n, idx) => (_jsx(MenuItem, { value: idx, children: _jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [_jsx(PartIdenticon, { part: n.part, size: 20 }), _jsxs("span", { style: { marginRight: "1em" }, children: [n.part, "-", n.proc] })] }) }, idx)))] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedOperation, style: { marginLeft: "1em" }, onChange: (e) => setSelectedOperation(e.target.value), children: [_jsx(MenuItem, { value: "LULOccupancy", children: "L/U Occupancy" }), selectedPart ? _jsx(MenuItem, { value: "LoadOp", children: "Load Operation (estimated)" }) : undefined, selectedPart ? _jsx(MenuItem, { value: "UnloadOp", children: "Unload Operation (estimated)" }) : undefined] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedLoadStation, style: { marginLeft: "1em" }, onChange: (e) => {
327
365
  setSelectedLoadStation(e.target.value);
328
- }, children: [_jsx(MenuItem, { value: FilterAnyLoadKey, children: _jsx("em", { children: "Any Station" }) }, -1), points.allLoadStationNames.map((n) => (_jsx(MenuItem, { value: n, children: _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("span", { style: { marginRight: "1em" }, children: n }) }) }, n)))] }) }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPallet || "", style: { marginLeft: "1em" }, onChange: (e) => setSelectedPallet(e.target.value === "" ? undefined : e.target.value), children: [_jsx(MenuItem, { value: "", children: _jsx("em", { children: "Any Pallet" }) }, 0), points.allPalletNames.map((n) => (_jsx(MenuItem, { value: n, children: _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("span", { style: { marginRight: "1em" }, children: n }) }) }, n)))] }) }), points.data.size > 0 ? (_jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { onClick: () => copyCyclesToClipboard(points, matSummary.matsById, zoomDateRange, selectedOperation === "LULOccupancy"), style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, size: "large", children: _jsx(ImportExport, {}) }) })) : undefined] }), _jsx("main", { children: showGraph ? (_jsx(CycleChart, { points: points.data, series_label: points.seriesLabel, default_date_range: defaultDateRange, extra_tooltip: extraLoadCycleTooltip, current_date_zoom: zoomDateRange, set_date_zoom_range: (z) => setZoomRange(z.zoom), yZoom: yZoom, setYZoom: setYZoom, stats: curOperation ? estimatedCycleTimes.get(curOperation) : undefined, plannedTimeMinutes: plannedMinutes })) : (_jsx(StationDataTable, { points: points.data, matsById: matSummary.matsById, period: period, current_date_zoom: zoomDateRange, set_date_zoom_range: (z) => setZoomRange(z.zoom), showWorkorderAndInspect: true, hideMedian: selectedOperation === "LULOccupancy", emptyMessage: selectedPart || selectedPallet
366
+ }, children: [_jsx(MenuItem, { value: FilterAnyLoadKey, children: _jsx("em", { children: "Any Station" }) }, -1), points.allLoadStationNames.map((n) => (_jsx(MenuItem, { value: n, children: _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("span", { style: { marginRight: "1em" }, children: n }) }) }, n)))] }) }), hasBasketCycles ? (_jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: carrierFilter, style: { marginLeft: "1em" }, onChange: (e) => {
367
+ const carrier = e.target.value;
368
+ setSelectedCarrier(carrier);
369
+ if (carrier === "Basket") {
370
+ setSelectedPallet(undefined);
371
+ }
372
+ }, children: [_jsx(MenuItem, { value: "Any", children: _jsx("em", { children: "Any Carrier" }) }), _jsx(MenuItem, { value: "Pallet", children: "Pallet" }), _jsx(MenuItem, { value: "Basket", children: basketName })] }) })) : undefined, carrierFilter !== "Basket" ? (_jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, displayEmpty: true, value: selectedPallet || "", style: { marginLeft: "1em" }, onChange: (e) => setSelectedPallet(e.target.value === "" ? undefined : e.target.value), children: [_jsx(MenuItem, { value: "", children: _jsx("em", { children: "Any Pallet" }) }, 0), points.allPalletNames.map((n) => (_jsx(MenuItem, { value: n, children: _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("span", { style: { marginRight: "1em" }, children: n }) }) }, n)))] }) })) : undefined, points.data.size > 0 ? (_jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { onClick: () => copyCyclesToClipboard(points, matSummary.matsById, zoomDateRange, selectedOperation === "LULOccupancy", fmsInfo.loadStationNames, basketName), style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, size: "large", children: _jsx(ImportExport, {}) }) })) : undefined] }), _jsx("main", { children: showGraph ? (_jsx(CycleChart, { points: points.data, series_label: points.seriesLabel, default_date_range: defaultDateRange, extra_tooltip: extraLoadCycleTooltip, current_date_zoom: zoomDateRange, set_date_zoom_range: (z) => setZoomRange(z.zoom), yZoom: yZoom, setYZoom: setYZoom, stats: curOperation ? estimatedCycleTimes.get(curOperation) : undefined, plannedTimeMinutes: plannedMinutes })) : (_jsx(StationDataTable, { points: points.data, matsById: matSummary.matsById, period: period, current_date_zoom: zoomDateRange, set_date_zoom_range: (z) => setZoomRange(z.zoom), showWorkorderAndInspect: true, hideMedian: selectedOperation === "LULOccupancy", emptyMessage: selectedPart || selectedPallet
329
373
  ? "No Cycles"
330
374
  : "Select part, operation, or pallet to see cycles." })) })] }));
331
375
  }
@@ -39,8 +39,10 @@ import { addDays, addHours, addMonths } from "date-fns";
39
39
  import { Menu } from "@mui/material";
40
40
  import { MenuItem } from "@mui/material";
41
41
  import { materialDialogOpen } from "../../cell-status/material-details.js";
42
- import { LazySeq, mkCompareByProperties, } from "@seedtactics/immutable-collections";
43
- import { useSetAtom } from "jotai";
42
+ import { basketDisplayName, carrierLabel, carrierSortKey, displayStationName, } from "../../cell-status/station-cycles.js";
43
+ import { LazySeq } from "@seedtactics/immutable-collections";
44
+ import { useAtomValue, useSetAtom } from "jotai";
45
+ import { fmsInformation } from "../../network/server-settings.js";
44
46
  var ColumnId;
45
47
  (function (ColumnId) {
46
48
  ColumnId[ColumnId["Date"] = 0] = "Date";
@@ -56,7 +58,7 @@ var ColumnId;
56
58
  ColumnId[ColumnId["MedianElapsed"] = 10] = "MedianElapsed";
57
59
  ColumnId[ColumnId["MedianDeviation"] = 11] = "MedianDeviation";
58
60
  })(ColumnId || (ColumnId = {}));
59
- function buildColumns(matIds) {
61
+ function buildColumns(matIds, loadStationNames, basketName) {
60
62
  return [
61
63
  {
62
64
  id: ColumnId.Date,
@@ -81,7 +83,7 @@ function buildColumns(matIds) {
81
83
  id: ColumnId.Station,
82
84
  numeric: false,
83
85
  label: "Station",
84
- getDisplay: (c) => c.stationGroup + " " + c.stationNumber.toString(),
86
+ getDisplay: (c) => displayStationName(c.stationGroup, c.stationNumber, loadStationNames),
85
87
  },
86
88
  {
87
89
  id: ColumnId.Operation,
@@ -92,9 +94,9 @@ function buildColumns(matIds) {
92
94
  {
93
95
  id: ColumnId.Pallet,
94
96
  numeric: false,
95
- label: "Pallet",
96
- getDisplay: (c) => c.pallet.toString(),
97
- getForSort: (c) => c.pallet,
97
+ label: "Carrier",
98
+ getDisplay: (c) => carrierLabel(c, basketName),
99
+ getForSort: (c) => carrierSortKey(c),
98
100
  },
99
101
  {
100
102
  id: ColumnId.Serial,
@@ -167,9 +169,9 @@ function extractData(points, columns, currentZoom, orderBy, order) {
167
169
  const getDataC = getData;
168
170
  const data = LazySeq.of(points.values()).flatMap((x) => x);
169
171
  const arr = currentZoom
170
- ? data.filter((p) => p.endTime >= currentZoom.start && p.endTime <= currentZoom.end).toMutableArray()
171
- : data.toMutableArray();
172
- return arr.sort(mkCompareByProperties(order === "desc" ? { desc: getDataC } : { asc: getDataC }, order === "desc" ? { desc: (a) => a.endTime.getTime() } : { asc: (a) => a.endTime.getTime() }));
172
+ ? data.filter((p) => p.endTime >= currentZoom.start && p.endTime <= currentZoom.end)
173
+ : data;
174
+ return arr.toSortedArray(order === "desc" ? { desc: getDataC } : { asc: getDataC }, order === "desc" ? { desc: (a) => a.endTime.getTime() } : { asc: (a) => a.endTime.getTime() });
173
175
  }
174
176
  function useZoom(props) {
175
177
  let zoom;
@@ -204,7 +206,8 @@ function useZoom(props) {
204
206
  };
205
207
  }
206
208
  export default memo(function StationDataTable(props) {
207
- const columns = buildColumns(props.matsById);
209
+ const fmsInfo = useAtomValue(fmsInformation);
210
+ const columns = buildColumns(props.matsById, fmsInfo.loadStationNames, basketDisplayName(fmsInfo.basketName));
208
211
  const sort = useColSort(ColumnId.Date, columns);
209
212
  const tpage = useTablePage();
210
213
  const zoom = useZoom(props);
@@ -45,14 +45,14 @@ import { localPoint } from "../../util/chart-helpers.js";
45
45
  import { useSetTitle } from "../routes.js";
46
46
  import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
47
47
  import { useResizeDetector } from "react-resize-detector";
48
- function tool_replacements_with_station_and_date(zoom, allReplacements, station) {
48
+ function tool_replacements_with_station_and_date(zoom, allReplacements, selectedStation) {
49
49
  const zoomRange = zoom?.zoomRange;
50
- if (station) {
51
- const rsForStat = allReplacements.get(station) ?? OrderedMap.empty();
50
+ if (selectedStation) {
51
+ const rsForStat = allReplacements.get(selectedStation) ?? OrderedMap.empty();
52
52
  return rsForStat
53
53
  .valuesToAscLazySeq()
54
54
  .transform((x) => zoomRange ? x.filter((rs) => rs.time >= zoomRange.start && rs.time <= zoomRange.end) : x)
55
- .flatMap((rs) => rs.replacements.map((r) => ({ ...r, station, time: rs.time })));
55
+ .flatMap((rs) => rs.replacements.map((replacement) => ({ ...replacement, station: selectedStation, time: rs.time })));
56
56
  }
57
57
  else {
58
58
  return allReplacements.toAscLazySeq().flatMap(([station, rsByStat]) => rsByStat
@@ -332,12 +332,12 @@ const AllReplacementTable = memo(function ReplacementTable(props) {
332
332
  });
333
333
  function copyToClipboard(replacements, displayType) {
334
334
  if (displayType === "summary") {
335
- const r = tool_summary(undefined, replacements, undefined, (r) => r.tool);
336
- copyTableToClipboard(summaryColumns, r);
335
+ const summaryRows = tool_summary(undefined, replacements, undefined, (replacement) => replacement.tool);
336
+ copyTableToClipboard(summaryColumns, summaryRows);
337
337
  }
338
338
  else {
339
- const r = tool_replacements_with_station_and_date(undefined, replacements, undefined).toSortedArray((r) => r.tool, (r) => r.time);
340
- copyTableToClipboard(allReplacementsColumns, r);
339
+ const detailRows = tool_replacements_with_station_and_date(undefined, replacements, undefined).toSortedArray((replacement) => replacement.tool, (replacement) => replacement.time);
340
+ copyTableToClipboard(allReplacementsColumns, detailRows);
341
341
  }
342
342
  }
343
343
  const ChooseMachine = memo(function ChooseMachineSelect(props) {
@@ -361,10 +361,16 @@ export const ToolReplacementPage = memo(function ToolReplacementCard() {
361
361
  useSetTitle("Tool Replacements");
362
362
  const [selectedMachine, setSelectedMachine] = useAtom(selectedMachineAtom);
363
363
  const [type, setType] = useAtom(selectedType);
364
- return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsxs(Box, { component: "nav", sx: {
364
+ return (_jsxs(Box, { sx: {
365
+ paddingLeft: "24px",
366
+ paddingRight: "24px",
367
+ paddingTop: "10px",
368
+ }, children: [_jsxs(Box, { component: "nav", sx: {
365
369
  display: "flex",
366
370
  minHeight: "2.5em",
367
371
  alignItems: "center",
368
372
  maxWidth: "calc(100vw - 24px - 24px)",
369
- }, children: [_jsx(Typography, { variant: "subtitle1", children: "Tool Replacements" }), _jsx(Box, { flexGrow: 1 }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: type, style: { marginLeft: "1em" }, onChange: (e) => setType(e.target.value), children: [_jsx(MenuItem, { value: "summary", children: "Summary" }), _jsx(MenuItem, { value: "details", children: "Details" })] }) }), _jsx(ChooseMachine, { station: selectedMachine, setSelectedStation: setSelectedMachine, displayType: type })] }), _jsx("main", { children: type === "summary" ? (_jsx(SummaryTable, { station: selectedMachine })) : (_jsx(AllReplacementTable, { station: selectedMachine })) })] }));
373
+ }, children: [_jsx(Typography, { variant: "subtitle1", children: "Tool Replacements" }), _jsx(Box, { sx: {
374
+ flexGrow: 1,
375
+ } }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: type, style: { marginLeft: "1em" }, onChange: (e) => setType(e.target.value), children: [_jsx(MenuItem, { value: "summary", children: "Summary" }), _jsx(MenuItem, { value: "details", children: "Details" })] }) }), _jsx(ChooseMachine, { station: selectedMachine, setSelectedStation: setSelectedMachine, displayType: type })] }), _jsx("main", { children: type === "summary" ? (_jsx(SummaryTable, { station: selectedMachine })) : (_jsx(AllReplacementTable, { station: selectedMachine })) })] }));
370
376
  });
@@ -0,0 +1,2 @@
1
+ import * as api from "../network/api.js";
2
+ export declare function filterRemoveAddQueue(entries: Iterable<Readonly<api.ILogEntry>>): Iterable<Readonly<api.ILogEntry>>;
@@ -0,0 +1,21 @@
1
+ import * as api from "../network/api.js";
2
+ export function* filterRemoveAddQueue(entries) {
3
+ let prev = null;
4
+ for (const e of entries) {
5
+ if (prev != null &&
6
+ prev.type === api.LogType.RemoveFromQueue &&
7
+ e.type === api.LogType.AddToQueue &&
8
+ prev.loc === e.loc) {
9
+ prev = null;
10
+ }
11
+ else {
12
+ if (prev !== null) {
13
+ yield prev;
14
+ }
15
+ prev = e;
16
+ }
17
+ }
18
+ if (prev !== null) {
19
+ yield prev;
20
+ }
21
+ }
@@ -45,6 +45,8 @@ import { closestCenter, DndContext, DragOverlay, getFirstCollision, MeasuringStr
45
45
  import { QuarantineMatButton } from "../station-monitor/QuarantineButton.js";
46
46
  import { useSetTitle } from "../routes.js";
47
47
  import { useAtom, useAtomValue, useSetAtom } from "jotai";
48
+ import { fmsInformation } from "../../network/server-settings.js";
49
+ import { basketDisplayName, loadStationDisplayName } from "../../cell-status/station-cycles.js";
48
50
  const ColumnWithTitle = forwardRef(function MaterialBin(props, ref) {
49
51
  return (_jsxs(Box, { sx: {
50
52
  margin: props.isDragOverlay ? undefined : "0.75em",
@@ -89,9 +91,6 @@ const QuarantineQueue = memo(function QuarantineQueue(props) {
89
91
  return (_jsx(SortableColumnWithTitle, { binId: props.binId, label: props.queue, bin: props.bin, children: _jsx(SortableContext, { items: props.material.map((m) => m.materialID), strategy: verticalListSortingStrategy, children: props.material.map((mat) => (_jsx(SortableInProcMaterial, { mat: mat, hideAvatar: true }, mat.materialID))) }) }));
90
92
  }
91
93
  });
92
- function renderLul(lul) {
93
- return "L/U " + lul.toString();
94
- }
95
94
  function compareLul(l1, l2) {
96
95
  return l1 - l2;
97
96
  }
@@ -114,22 +113,34 @@ function renderQueue(queue) {
114
113
  function compareQueue(q1, q2) {
115
114
  return q1.localeCompare(q2);
116
115
  }
116
+ function compareBasket(b1, b2) {
117
+ return b1 - b2;
118
+ }
117
119
  class SystemMaterial extends PureComponent {
118
120
  render() {
119
121
  const Col = this.props.isDragOverlay ? ColumnWithTitle : SortableColumnWithTitle;
120
122
  return (_jsx(Col, { label: this.props.name, binId: this.props.binId, bin: this.props.bin, isDragOverlay: this.props.isDragOverlay, children: LazySeq.of(this.props.material)
121
123
  .sortWith(([l1, _m1], [l2, _m2]) => this.props.compareLabel(l1, l2))
122
- .map(([label, material], idx) => (_jsxs("div", { children: [_jsx(Typography, { variant: "caption", children: this.props.renderLabel(label) }), material.map((mat, idx) => (_jsx(InProcMaterial, { mat: mat, hideAvatar: true }, idx)))] }, idx))) }));
124
+ .map(([label, material], matGroupIdx) => (_jsxs("div", { children: [_jsx(Typography, { variant: "caption", children: this.props.renderLabel(label) }), material.map((mat, idx) => (_jsx(InProcMaterial, { mat: mat, hideAvatar: true }, idx)))] }, matGroupIdx))) }));
123
125
  }
124
126
  }
125
127
  function MaterialBinColumn({ matBin, isDragOverlay, }) {
128
+ const fmsInfo = useAtomValue(fmsInformation);
129
+ const basketName = basketDisplayName(fmsInfo.basketName);
126
130
  switch (matBin.type) {
127
131
  case MaterialBinType.LoadStations:
128
- return (_jsx(SystemMaterial, { name: "Load Stations", binId: matBin.binId, renderLabel: renderLul, compareLabel: compareLul, material: matBin.byLul, bin: matBin, isDragOverlay: isDragOverlay }));
132
+ return (_jsx(SystemMaterial, { name: "Load Stations", binId: matBin.binId, renderLabel: (lul) => loadStationDisplayName(lul, fmsInfo.loadStationNames), compareLabel: compareLul, material: matBin.byLul, bin: matBin, isDragOverlay: isDragOverlay }));
129
133
  case MaterialBinType.Pallets:
130
134
  return (_jsx(SystemMaterial, { name: "Pallets", binId: matBin.binId, renderLabel: renderPal, compareLabel: comparePal, material: matBin.byPallet, bin: matBin, isDragOverlay: isDragOverlay }));
131
135
  case MaterialBinType.ActiveQueues:
132
136
  return (_jsx(SystemMaterial, { name: "Queues", binId: matBin.binId, renderLabel: renderQueue, compareLabel: compareQueue, material: matBin.byQueue, bin: matBin, isDragOverlay: isDragOverlay }));
137
+ case MaterialBinType.Baskets:
138
+ return (_jsx(SystemMaterial, { name: basketName + "s", binId: matBin.binId, renderLabel: (id) => basketName +
139
+ " " +
140
+ id.toString() +
141
+ (typeof id === "number" && matBin.basketLocations.get(id)
142
+ ? ` (${matBin.basketLocations.get(id)})`
143
+ : ""), compareLabel: compareBasket, material: matBin.byBasket, bin: matBin, isDragOverlay: isDragOverlay }));
133
144
  case MaterialBinType.QuarantineQueues:
134
145
  return (_jsx(QuarantineQueue, { binId: matBin.binId, queue: matBin.queueName, material: matBin.material, bin: matBin, isDragOverlay: isDragOverlay }));
135
146
  }
@@ -181,12 +192,12 @@ export function AllMaterial(props) {
181
192
  const reorderQueuedMat = useSetAtom(currentSt.reorderQueuedMatInCurrentStatus);
182
193
  const [activeDrag, setActiveDrag] = useState(null);
183
194
  const allBins = useMemo(() => {
184
- const allBins = selectAllMaterialIntoBins(st, matBinOrder);
195
+ const bins = selectAllMaterialIntoBins(st, matBinOrder);
185
196
  if (activeDrag && activeDrag.type === "material" && activeDrag.curOverBinId !== null) {
186
- return moveMaterialInBin(allBins, activeDrag.mat, activeDrag.curOverBinId, activeDrag.initialIdx);
197
+ return moveMaterialInBin(bins, activeDrag.mat, activeDrag.curOverBinId, activeDrag.initialIdx);
187
198
  }
188
199
  else {
189
- return allBins;
200
+ return bins;
190
201
  }
191
202
  }, [st, matBinOrder, activeDrag]);
192
203
  const curBins = props.displaySystemBins
@@ -196,10 +207,15 @@ export function AllMaterial(props) {
196
207
  return (_jsxs(DndContext, { collisionDetection: collisionDetectionStrategy, measuring: {
197
208
  droppable: { strategy: MeasuringStrategy.Always },
198
209
  }, onDragStart: ({ active }) => {
199
- if (typeof active.id === "string") {
210
+ if (typeof active.id === "string" &&
211
+ typeof active.data.current === "object" &&
212
+ active.data.current !== null &&
213
+ "bin" in active.data.current) {
200
214
  setActiveDrag({ type: "column", bin: active.data.current.bin });
201
215
  }
202
- else {
216
+ else if (typeof active.data.current === "object" &&
217
+ active.data.current !== null &&
218
+ "mat" in active.data.current) {
203
219
  setActiveDrag({
204
220
  type: "material",
205
221
  mat: active.data.current.mat,
@@ -35,6 +35,37 @@ import { memo, useState } from "react";
35
35
  import { last30ChartEndTimes, last30ChartStartTimes, last30WeekdayStartIdx, last30WeekdayStartMinuteOffset, } from "../../data/chart-times";
36
36
  import { useAtom, useAtomValue } from "jotai";
37
37
  import { Box, Button, Dialog, DialogActions, DialogContent, Divider, IconButton, MenuItem, Radio, RadioGroup, Stack, TextField, Tooltip, Typography, } from "@mui/material";
38
+ function isStartType(value) {
39
+ return (value === "CustomDate" ||
40
+ value === "StartOfToday" ||
41
+ value === "StartOfYesterday" ||
42
+ value === "StartOfWeek" ||
43
+ value === "StartOfLastWeek" ||
44
+ value === "Last30");
45
+ }
46
+ function isEndType(value) {
47
+ return value === "CustomDate" || value === "Now" || value === "EndOfYesterday" || value === "EndOfLastWeek";
48
+ }
49
+ function parseWeekdayStart(value) {
50
+ switch (value) {
51
+ case "0":
52
+ return 0;
53
+ case "1":
54
+ return 1;
55
+ case "2":
56
+ return 2;
57
+ case "3":
58
+ return 3;
59
+ case "4":
60
+ return 4;
61
+ case "5":
62
+ return 5;
63
+ case "6":
64
+ return 6;
65
+ default:
66
+ return null;
67
+ }
68
+ }
38
69
  import { Edit } from "@mui/icons-material";
39
70
  import { addMinutes, startOfToday } from "date-fns";
40
71
  function RadioLabel({ label, date }) {
@@ -70,7 +101,29 @@ function RangeStart({ chartAtom }) {
70
101
  const startOfWeek = useAtomValue(last30ChartStartTimes("StartOfWeek"));
71
102
  const startOfLastWeek = useAtomValue(last30ChartStartTimes("StartOfLastWeek"));
72
103
  const last30 = useAtomValue(last30ChartStartTimes("Last30"));
73
- return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: "Range Start" }), _jsx(RadioGroup, { value: chartRange.startType instanceof Date ? "CustomDate" : chartRange.startType, onChange: (event) => setTy(event.target.value), children: _jsxs(Stack, { direction: "column", spacing: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "StartOfToday" }), _jsx(RadioLabel, { label: "Start of Today", date: stOfToday })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "StartOfYesterday" }), _jsx(RadioLabel, { label: "Start of Yesterday", date: startOfYesterday })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "StartOfWeek" }), _jsx(RadioLabel, { label: "Start of This Week", date: startOfWeek })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "StartOfLastWeek" }), _jsx(RadioLabel, { label: "Start of Last Week", date: startOfLastWeek })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "Last30" }), _jsx(RadioLabel, { label: "Last 30 Days", date: last30 })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "CustomDate" }), _jsx(CustomDateLabel, { enabled: chartRange.startType instanceof Date, date: customDate, setDate: setDate })] })] }) })] }));
104
+ return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: "Range Start" }), _jsx(RadioGroup, { value: chartRange.startType instanceof Date ? "CustomDate" : chartRange.startType, onChange: (event) => {
105
+ if (isStartType(event.target.value)) {
106
+ setTy(event.target.value);
107
+ }
108
+ }, children: _jsxs(Stack, { direction: "column", spacing: 2, children: [_jsxs(Stack, { direction: "row", sx: {
109
+ alignItems: "center",
110
+ minHeight: "3em",
111
+ }, children: [_jsx(Radio, { value: "StartOfToday" }), _jsx(RadioLabel, { label: "Start of Today", date: stOfToday })] }), _jsxs(Stack, { direction: "row", sx: {
112
+ alignItems: "center",
113
+ minHeight: "3em",
114
+ }, children: [_jsx(Radio, { value: "StartOfYesterday" }), _jsx(RadioLabel, { label: "Start of Yesterday", date: startOfYesterday })] }), _jsxs(Stack, { direction: "row", sx: {
115
+ alignItems: "center",
116
+ minHeight: "3em",
117
+ }, children: [_jsx(Radio, { value: "StartOfWeek" }), _jsx(RadioLabel, { label: "Start of This Week", date: startOfWeek })] }), _jsxs(Stack, { direction: "row", sx: {
118
+ alignItems: "center",
119
+ minHeight: "3em",
120
+ }, children: [_jsx(Radio, { value: "StartOfLastWeek" }), _jsx(RadioLabel, { label: "Start of Last Week", date: startOfLastWeek })] }), _jsxs(Stack, { direction: "row", sx: {
121
+ alignItems: "center",
122
+ minHeight: "3em",
123
+ }, children: [_jsx(Radio, { value: "Last30" }), _jsx(RadioLabel, { label: "Last 30 Days", date: last30 })] }), _jsxs(Stack, { direction: "row", sx: {
124
+ alignItems: "center",
125
+ minHeight: "3em",
126
+ }, children: [_jsx(Radio, { value: "CustomDate" }), _jsx(CustomDateLabel, { enabled: chartRange.startType instanceof Date, date: customDate, setDate: setDate })] })] }) })] }));
74
127
  }
75
128
  function RangeEnd({ chartAtom }) {
76
129
  const [chartRange, setChartRange] = useAtom(chartAtom);
@@ -90,7 +143,23 @@ function RangeEnd({ chartAtom }) {
90
143
  }
91
144
  const endOfYesterday = useAtomValue(last30ChartEndTimes("EndOfYesterday"));
92
145
  const endOfLastWeek = useAtomValue(last30ChartEndTimes("EndOfLastWeek"));
93
- return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: "Range End" }), _jsx(RadioGroup, { value: chartRange.endType instanceof Date ? "CustomDate" : chartRange.endType, onChange: (event) => setTy(event.target.value), children: _jsxs(Stack, { direction: "column", spacing: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "Now" }), _jsx(Typography, { children: "Now" })] }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "EndOfYesterday" }), _jsx(RadioLabel, { label: "End of Yesterday", date: endOfYesterday })] }), _jsx(Box, { sx: { height: "3em" } }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "EndOfLastWeek" }), _jsx(RadioLabel, { label: "End of Last Week", date: endOfLastWeek })] }), _jsx(Box, { sx: { height: "3em" } }), _jsxs(Stack, { direction: "row", alignItems: "center", sx: { minHeight: "3em" }, children: [_jsx(Radio, { value: "CustomDate" }), _jsx(CustomDateLabel, { enabled: chartRange.endType instanceof Date, date: customDate, setDate: setDate })] })] }) })] }));
146
+ return (_jsxs(Box, { children: [_jsx(Typography, { variant: "h6", children: "Range End" }), _jsx(RadioGroup, { value: chartRange.endType instanceof Date ? "CustomDate" : chartRange.endType, onChange: (event) => {
147
+ if (isEndType(event.target.value)) {
148
+ setTy(event.target.value);
149
+ }
150
+ }, children: _jsxs(Stack, { direction: "column", spacing: 2, children: [_jsxs(Stack, { direction: "row", sx: {
151
+ alignItems: "center",
152
+ minHeight: "3em",
153
+ }, children: [_jsx(Radio, { value: "Now" }), _jsx(Typography, { children: "Now" })] }), _jsxs(Stack, { direction: "row", sx: {
154
+ alignItems: "center",
155
+ minHeight: "3em",
156
+ }, children: [_jsx(Radio, { value: "EndOfYesterday" }), _jsx(RadioLabel, { label: "End of Yesterday", date: endOfYesterday })] }), _jsx(Box, { sx: { height: "3em" } }), _jsxs(Stack, { direction: "row", sx: {
157
+ alignItems: "center",
158
+ minHeight: "3em",
159
+ }, children: [_jsx(Radio, { value: "EndOfLastWeek" }), _jsx(RadioLabel, { label: "End of Last Week", date: endOfLastWeek })] }), _jsx(Box, { sx: { height: "3em" } }), _jsxs(Stack, { direction: "row", sx: {
160
+ alignItems: "center",
161
+ minHeight: "3em",
162
+ }, children: [_jsx(Radio, { value: "CustomDate" }), _jsx(CustomDateLabel, { enabled: chartRange.endType instanceof Date, date: customDate, setDate: setDate })] })] }) })] }));
94
163
  }
95
164
  function minutesToTimespan(m) {
96
165
  const h = Math.floor(m / 60);
@@ -100,7 +169,14 @@ function minutesToTimespan(m) {
100
169
  function RangeDialog({ chartAtom, open, setOpen, }) {
101
170
  const [weekdayStart, setWeekdayStart] = useAtom(last30WeekdayStartIdx);
102
171
  const [weekdayStartMinuteOffset, setWeekdayStartMinuteOffset] = useAtom(last30WeekdayStartMinuteOffset);
103
- return (_jsxs(Dialog, { open: open, onClose: () => setOpen(false), maxWidth: "md", children: [_jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 2, divider: _jsx(Divider, { orientation: "horizontal", flexItem: true }), children: [_jsxs(Stack, { direction: "row", spacing: 2, divider: _jsx(Divider, { orientation: "vertical", flexItem: true }), children: [_jsx(RangeStart, { chartAtom: chartAtom }), _jsx(RangeEnd, { chartAtom: chartAtom })] }), _jsxs(Stack, { direction: "row", justifyContent: "space-around", children: [_jsxs(TextField, { select: true, label: "First Day Of Week", sx: { minWidth: "10em" }, value: weekdayStart, onChange: (e) => setWeekdayStart(parseInt(e.target.value)), children: [_jsx(MenuItem, { value: 0, children: "Sunday" }), _jsx(MenuItem, { value: 1, children: "Monday" }), _jsx(MenuItem, { value: 2, children: "Tuesday" }), _jsx(MenuItem, { value: 3, children: "Wednesday" }), _jsx(MenuItem, { value: 4, children: "Thursday" }), _jsx(MenuItem, { value: 5, children: "Friday" }), _jsx(MenuItem, { value: 6, children: "Saturday" })] }), _jsx(TextField, { type: "time", label: "Day Start Time", sx: { minWidth: "10em" }, value: minutesToTimespan(weekdayStartMinuteOffset), onChange: (e) => {
172
+ return (_jsxs(Dialog, { open: open, onClose: () => setOpen(false), maxWidth: "md", children: [_jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 2, divider: _jsx(Divider, { orientation: "horizontal", flexItem: true }), children: [_jsxs(Stack, { direction: "row", spacing: 2, divider: _jsx(Divider, { orientation: "vertical", flexItem: true }), children: [_jsx(RangeStart, { chartAtom: chartAtom }), _jsx(RangeEnd, { chartAtom: chartAtom })] }), _jsxs(Stack, { direction: "row", sx: {
173
+ justifyContent: "space-around",
174
+ }, children: [_jsxs(TextField, { select: true, label: "First Day Of Week", sx: { minWidth: "10em" }, value: weekdayStart, onChange: (e) => {
175
+ const parsed = parseWeekdayStart(e.target.value);
176
+ if (parsed !== null) {
177
+ setWeekdayStart(parsed);
178
+ }
179
+ }, children: [_jsx(MenuItem, { value: 0, children: "Sunday" }), _jsx(MenuItem, { value: 1, children: "Monday" }), _jsx(MenuItem, { value: 2, children: "Tuesday" }), _jsx(MenuItem, { value: 3, children: "Wednesday" }), _jsx(MenuItem, { value: 4, children: "Thursday" }), _jsx(MenuItem, { value: 5, children: "Friday" }), _jsx(MenuItem, { value: 6, children: "Saturday" })] }), _jsx(TextField, { type: "time", label: "Day Start Time", sx: { minWidth: "10em" }, value: minutesToTimespan(weekdayStartMinuteOffset), onChange: (e) => {
104
180
  const val = e.target.value;
105
181
  if (val === "") {
106
182
  setWeekdayStartMinuteOffset(0);
@@ -144,5 +220,7 @@ function formatEnd(ty, d) {
144
220
  export const Last30ChartRangeToolbar = memo(function Last30ChartRangeToolbar({ chartAtom, }) {
145
221
  const chartRange = useAtomValue(chartAtom);
146
222
  const [dialogOpen, setDialogOpen] = useState(false);
147
- return (_jsxs(_Fragment, { children: [_jsxs(Stack, { direction: "row", spacing: 2, alignItems: "center", children: [_jsxs(Typography, { variant: "body2", color: "textSecondary", children: ["Range: ", formatStart(chartRange.startType, chartRange.startDate), " -", " ", formatEnd(chartRange.endType, chartRange.endDate)] }), _jsx(Tooltip, { title: "Edit Range", children: _jsx(IconButton, { onClick: () => setDialogOpen(true), children: _jsx(Edit, {}) }) })] }), _jsx(RangeDialog, { open: dialogOpen, setOpen: setDialogOpen, chartAtom: chartAtom })] }));
223
+ return (_jsxs(_Fragment, { children: [_jsxs(Stack, { direction: "row", spacing: 2, sx: {
224
+ alignItems: "center",
225
+ }, children: [_jsxs(Typography, { variant: "body2", color: "textSecondary", children: ["Range: ", formatStart(chartRange.startType, chartRange.startDate), " -", " ", formatEnd(chartRange.endType, chartRange.endDate)] }), _jsx(Tooltip, { title: "Edit Range", children: _jsx(IconButton, { onClick: () => setDialogOpen(true), children: _jsx(Edit, {}) }) })] }), _jsx(RangeDialog, { open: dialogOpen, setOpen: setDialogOpen, chartAtom: chartAtom })] }));
148
226
  });