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