@seedtactics/insight-client 16.6.0 → 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.
- package/dist/assets/ProgramHighlight-DPTeZ8Si.js +3 -0
- package/dist/assets/index-bPAFn3jp.js +364 -0
- package/dist/cell-status/basket-cycles.d.ts +21 -0
- package/dist/cell-status/basket-cycles.js +80 -0
- package/dist/cell-status/current-status.js +11 -3
- package/dist/cell-status/estimated-cycle-times.js +8 -4
- package/dist/cell-status/inspections.js +2 -2
- package/dist/cell-status/loading.js +4 -0
- package/dist/cell-status/material-details.d.ts +12 -4
- package/dist/cell-status/material-details.js +24 -13
- package/dist/cell-status/rebookings.js +15 -17
- package/dist/cell-status/scheduled-jobs.d.ts +1 -1
- package/dist/cell-status/scheduled-jobs.js +10 -3
- package/dist/cell-status/sim-production.js +3 -3
- package/dist/cell-status/sim-station-use.d.ts +1 -0
- package/dist/cell-status/sim-station-use.js +14 -8
- package/dist/cell-status/station-cycles.d.ts +29 -2
- package/dist/cell-status/station-cycles.js +81 -11
- package/dist/cell-status/tool-replacements.js +1 -1
- package/dist/cell-status/tool-usage.js +1 -1
- package/dist/components/App.js +101 -66
- package/dist/components/BarcodeScanning.js +12 -2
- package/dist/components/ErrorsAndLoading.js +10 -1
- package/dist/components/LogEntry.d.ts +0 -1
- package/dist/components/LogEntry.js +50 -26
- package/dist/components/Navigation.js +30 -4
- package/dist/components/analysis/AnalysisSelectToolbar.js +5 -1
- package/dist/components/analysis/BasketCycleCards.d.ts +1 -0
- package/dist/components/analysis/BasketCycleCards.js +145 -0
- package/dist/components/analysis/BufferChart.js +10 -4
- package/dist/components/analysis/CostPerPiece.js +28 -8
- package/dist/components/analysis/CycleChart.js +1 -1
- package/dist/components/analysis/DataTable.js +6 -4
- package/dist/components/analysis/HeatChart.js +27 -14
- package/dist/components/analysis/InspectionSankey.js +17 -6
- package/dist/components/analysis/PalletCycleCards.js +15 -4
- package/dist/components/analysis/PartCycleCards.js +62 -18
- package/dist/components/analysis/StationDataTable.js +14 -11
- package/dist/components/analysis/ToolReplacements.js +16 -10
- package/dist/components/log-entry-queue-filter.d.ts +2 -0
- package/dist/components/log-entry-queue-filter.js +21 -0
- package/dist/components/operations/AllMaterial.js +26 -10
- package/dist/components/operations/ChartRangeEdit.js +82 -4
- package/dist/components/operations/CloseoutReport.js +13 -4
- package/dist/components/operations/CompletedParts.js +23 -11
- package/dist/components/operations/CurrentWorkorders.js +31 -9
- package/dist/components/operations/OEEChart.js +8 -2
- package/dist/components/operations/Outliers.js +18 -7
- package/dist/components/operations/ProgramHighlight.js +4 -6
- package/dist/components/operations/Programs.js +9 -3
- package/dist/components/operations/Rebookings.js +8 -4
- package/dist/components/operations/RecentCycleChart.js +5 -3
- package/dist/components/operations/RecentProduction.js +30 -13
- package/dist/components/operations/RecentSchedules.js +6 -2
- package/dist/components/operations/RecentStationCycles.js +38 -11
- package/dist/components/operations/ShiftSettings.js +3 -3
- package/dist/components/operations/SimDayUsage.js +27 -4
- package/dist/components/operations/ToolReport.js +5 -1
- package/dist/components/operations/WorkorderGantt.js +22 -2
- package/dist/components/quality/QualityMaterial.js +11 -8
- package/dist/components/quality/RecentFailedInspections.js +3 -1
- package/dist/components/routes.d.ts +3 -0
- package/dist/components/routes.js +2 -0
- package/dist/components/station-monitor/BulkRawMaterial.js +11 -7
- package/dist/components/station-monitor/Closeout.js +14 -2
- package/dist/components/station-monitor/CustomStationMonitorDialog.js +1 -1
- package/dist/components/station-monitor/Inspection.js +23 -11
- package/dist/components/station-monitor/InvalidateCycle.js +3 -3
- package/dist/components/station-monitor/JobDetails.js +15 -2
- package/dist/components/station-monitor/LoadStation.js +274 -31
- package/dist/components/station-monitor/Material.js +71 -11
- package/dist/components/station-monitor/MoveMaterialArrows.js +4 -4
- package/dist/components/station-monitor/QuarantineButton.js +11 -0
- package/dist/components/station-monitor/Queues.js +28 -9
- package/dist/components/station-monitor/QueuesAddMaterial.js +8 -6
- package/dist/components/station-monitor/SelectInspType.js +1 -1
- package/dist/components/station-monitor/SelectWorkorder.js +1 -1
- package/dist/components/station-monitor/StationToolbar.js +17 -5
- package/dist/components/station-monitor/SystemOverview.d.ts +19 -1
- package/dist/components/station-monitor/SystemOverview.js +439 -20
- package/dist/components/station-monitor/Whiteboard.js +15 -7
- package/dist/data/all-material-bins.d.ts +7 -0
- package/dist/data/all-material-bins.js +47 -1
- package/dist/data/cost-per-piece.js +11 -8
- package/dist/data/current-cycles.d.ts +1 -1
- package/dist/data/current-cycles.js +62 -17
- package/dist/data/move-arrows.d.ts +5 -1
- package/dist/data/move-arrows.js +54 -4
- package/dist/data/part-summary.js +13 -13
- package/dist/data/path-lookup.js +6 -23
- package/dist/data/queue-material.d.ts +1 -1
- package/dist/data/queue-material.js +18 -17
- package/dist/data/results.completed-parts.js +4 -3
- package/dist/data/results.cycles.d.ts +15 -6
- package/dist/data/results.cycles.js +51 -30
- package/dist/data/results.inspection.js +11 -6
- package/dist/data/results.oee.js +8 -8
- package/dist/data/results.schedules.js +2 -11
- package/dist/data/tools-programs.js +5 -6
- package/dist/index.html +1 -1
- package/dist/network/api.d.ts +22 -4
- package/dist/network/api.js +40 -5
- package/dist/network/backend-mock.js +15 -8
- package/dist/network/backend.js +3 -3
- package/dist/network/websocket.js +15 -15
- package/dist/util/chart-helpers.d.ts +1 -1
- package/dist/util/chart-helpers.js +14 -8
- package/package.json +29 -31
- package/dist/assets/ProgramHighlight-LvRM40Qr.js +0 -3
- package/dist/assets/index-gAFi3Oss.js +0 -364
|
@@ -42,7 +42,7 @@ import { last30MaterialSummary, } from "../../cell-status/material-summary.js";
|
|
|
42
42
|
import { useSetTitle } from "../routes.js";
|
|
43
43
|
import { useAtomValue, useSetAtom } from "jotai";
|
|
44
44
|
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
45
|
-
import { Check,
|
|
45
|
+
import { Check, ErrorOutlined, MoreHoriz, SkipNext, SkipPrevious } from "@mui/icons-material";
|
|
46
46
|
function CloseoutDialogButtons() {
|
|
47
47
|
const setWorkorderDialogOpen = useSetAtom(selectWorkorderDialogOpen);
|
|
48
48
|
const mat = useAtomValue(materialInDialogInfo);
|
|
@@ -74,7 +74,9 @@ const fulldayFormat = new Intl.DateTimeFormat(undefined, {
|
|
|
74
74
|
});
|
|
75
75
|
function NavigateDay({ day, setDay, }) {
|
|
76
76
|
const today = startOfToday();
|
|
77
|
-
return (_jsxs(Stack, { direction: "row", spacing: 2,
|
|
77
|
+
return (_jsxs(Stack, { direction: "row", spacing: 2, sx: {
|
|
78
|
+
alignItems: "center",
|
|
79
|
+
}, children: [_jsx(Tooltip, { title: "Previous Day", children: _jsx("div", { children: _jsx(IconButton, { disabled: day <= addDays(today, -28), onClick: () => setDay((d) => addDays(d, -1)), children: _jsx(SkipPrevious, {}) }) }) }), _jsx(Typography, { sx: { minWidth: "14em", textAlign: "center" }, children: fulldayFormat.format(day) }), _jsx(Tooltip, { title: "Next Day", children: _jsx("div", { children: _jsx(IconButton, { disabled: day >= today, onClick: () => setDay((d) => addDays(d, 1)), children: _jsx(SkipNext, {}) }) }) })] }));
|
|
78
80
|
}
|
|
79
81
|
var SortColumn;
|
|
80
82
|
(function (SortColumn) {
|
|
@@ -136,7 +138,9 @@ const noSecondsFormat = new Intl.DateTimeFormat(undefined, {
|
|
|
136
138
|
});
|
|
137
139
|
const CloseoutRow = memo(function CloseoutRow({ mat }) {
|
|
138
140
|
const setMatToShow = useSetAtom(materialDialogOpen);
|
|
139
|
-
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: mat.last_unload_time ? timeOnlyFormat.format(mat.last_unload_time) : "" }), _jsx(TableCell, { children: mat.serial }), _jsx(TableCell, { children: _jsxs(Stack, { direction: "row", spacing: "2",
|
|
141
|
+
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: mat.last_unload_time ? timeOnlyFormat.format(mat.last_unload_time) : "" }), _jsx(TableCell, { children: mat.serial }), _jsx(TableCell, { children: _jsxs(Stack, { direction: "row", spacing: "2", sx: {
|
|
142
|
+
alignItems: "center",
|
|
143
|
+
}, children: [_jsx(PartIdenticon, { part: mat.partName, size: 25 }), _jsx(Typography, { variant: "body2", children: mat.partName })] }) }), _jsx(TableCell, { children: mat.workorderId }), _jsx(TableCell, { children: mat.closeout_completed === null || mat.closeout_completed === undefined ? ("") : mat.closeout_failed ? (_jsx(ErrorOutlined, { fontSize: "inherit" })) : (_jsx(Check, { fontSize: "inherit" })) }), _jsx(TableCell, { children: mat.closeout_completed ? noSecondsFormat.format(mat.closeout_completed) : "" }), _jsx(TableCell, { padding: "checkbox", children: mat.serial !== null && mat.serial !== "" ? (_jsx(IconButton, { onClick: () => {
|
|
140
144
|
if (!mat.serial)
|
|
141
145
|
return;
|
|
142
146
|
setMatToShow({
|
|
@@ -168,5 +172,10 @@ function CloseoutTable({ day }) {
|
|
|
168
172
|
export function CloseoutReport() {
|
|
169
173
|
useSetTitle("Close Out");
|
|
170
174
|
const [day, setDay] = useState(startOfToday());
|
|
171
|
-
return (_jsxs(Box, {
|
|
175
|
+
return (_jsxs(Box, { sx: {
|
|
176
|
+
padding: "24px",
|
|
177
|
+
}, children: [_jsx(Box, { component: "nav", sx: {
|
|
178
|
+
display: "flex",
|
|
179
|
+
justifyContent: "center",
|
|
180
|
+
}, children: _jsx(NavigateDay, { day: day, setDay: setDay }) }), _jsx("main", { children: _jsx(CloseoutTable, { day: day }) }), _jsx(SelectWorkorderDialog, {}), _jsx(CloseoutMaterialDialog, {})] }));
|
|
172
181
|
}
|
|
@@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
34
34
|
import { memo, useMemo, useState } from "react";
|
|
35
35
|
import { Box, Button, Stack, TableSortLabel, IconButton, Tooltip, Typography, Table, TableRow, TableCell, TableHead, TableBody, Toolbar, Select, MenuItem, InputBase, styled, } from "@mui/material";
|
|
36
36
|
import { MaterialDialog, PartIdenticon } from "../station-monitor/Material.js";
|
|
37
|
-
import { FirstPage as FirstPageIcon, KeyboardArrowLeft, KeyboardArrowRight, LastPage as LastPageIcon, KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, ImportExport, MoreHoriz, Check,
|
|
37
|
+
import { FirstPage as FirstPageIcon, KeyboardArrowLeft, KeyboardArrowRight, LastPage as LastPageIcon, KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, ImportExport, MoreHoriz, Check, ErrorOutlined, SavedSearch, HelpOutlined, } from "@mui/icons-material";
|
|
38
38
|
import { Collapse } from "@mui/material";
|
|
39
39
|
import { LazySeq, mkCompareByProperties } from "@seedtactics/immutable-collections";
|
|
40
40
|
import { AppLink, RouteLocation, useSetTitle } from "../routes.js";
|
|
@@ -106,10 +106,10 @@ function sortMaterial(material, col, order) {
|
|
|
106
106
|
sortCol = (j) => j.currently_quarantined ?? null;
|
|
107
107
|
break;
|
|
108
108
|
case "InspectFailed":
|
|
109
|
-
sortCol = (j) => LazySeq.ofObject(j.completedInspections ?? {}).some(([, insp]) => insp.success
|
|
109
|
+
sortCol = (j) => LazySeq.ofObject(j.completedInspections ?? {}).some(([, insp]) => !insp.success) ? -1 : 0;
|
|
110
110
|
break;
|
|
111
111
|
case "CloseOut":
|
|
112
|
-
sortCol = (j) => (j.closeout_failed === undefined ? 1 : j.closeout_failed
|
|
112
|
+
sortCol = (j) => (j.closeout_failed === undefined ? 1 : j.closeout_failed ? -1 : 0);
|
|
113
113
|
break;
|
|
114
114
|
}
|
|
115
115
|
const sorted = [...material];
|
|
@@ -149,7 +149,7 @@ function MaterialTable({ material }) {
|
|
|
149
149
|
const [rowsPerPage, setRowsPerPage] = useState(10);
|
|
150
150
|
const [page, setPage] = useState(0);
|
|
151
151
|
const curPage = sortedMats.slice(page * rowsPerPage, (page + 1) * rowsPerPage);
|
|
152
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(SortColHeader, { col: "Serial", ...sort, children: "Serial" }), _jsx(SortColHeader, { col: "CompletedDate", ...sort, children: "Completed" }), _jsx(SortColHeader, { col: "Workorder", ...sort, children: "Workorder" }), _jsx(SortColHeader, { col: "Quarantined", ...sort, children: "Quarantine?" }), _jsx(SortColHeader, { col: "InspectFailed", noWhitespaceWrap: true, ...sort, children: "Inspect Failed?" }), _jsx(SortColHeader, { col: "CloseOut", noWhitespaceWrap: true, ...sort, children: "Close Out" }), _jsx(TableCell, { padding: "checkbox" })] }) }), _jsxs(TableBody, { children: [curPage.map((s) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: s.serial ?? "" }), _jsx(TableCell, { children: s.last_unload_time ? completedDateFormat.format(s.last_unload_time) : "" }), _jsx(TableCell, { children: _jsx(WorkorderLink, { workorderId: s.workorderId }) }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.currently_quarantined ? _jsx(SavedSearch, { fontSize: "inherit" }) : "" }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: LazySeq.ofObject(s.completedInspections ?? {}).some(([, insp]) => insp.success
|
|
152
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(SortColHeader, { col: "Serial", ...sort, children: "Serial" }), _jsx(SortColHeader, { col: "CompletedDate", ...sort, children: "Completed" }), _jsx(SortColHeader, { col: "Workorder", ...sort, children: "Workorder" }), _jsx(SortColHeader, { col: "Quarantined", ...sort, children: "Quarantine?" }), _jsx(SortColHeader, { col: "InspectFailed", noWhitespaceWrap: true, ...sort, children: "Inspect Failed?" }), _jsx(SortColHeader, { col: "CloseOut", noWhitespaceWrap: true, ...sort, children: "Close Out" }), _jsx(TableCell, { padding: "checkbox" })] }) }), _jsxs(TableBody, { children: [curPage.map((s) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: s.serial ?? "" }), _jsx(TableCell, { children: s.last_unload_time ? completedDateFormat.format(s.last_unload_time) : "" }), _jsx(TableCell, { children: _jsx(WorkorderLink, { workorderId: s.workorderId }) }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.currently_quarantined ? _jsx(SavedSearch, { fontSize: "inherit" }) : "" }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: LazySeq.ofObject(s.completedInspections ?? {}).some(([, insp]) => !insp.success) ? (_jsx(ErrorOutlined, { fontSize: "inherit" })) : ("") }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.closeout_completed === undefined ? ("") : s.closeout_failed === false ? (_jsx(Check, { fontSize: "inherit" })) : (_jsx(ErrorOutlined, { fontSize: "inherit" })) }), _jsx(TableCell, { padding: "checkbox", children: _jsx(IconButton, { onClick: () => setMatToShow({
|
|
153
153
|
type: "MatSummary",
|
|
154
154
|
summary: s,
|
|
155
155
|
}), size: "large", children: _jsx(MoreHoriz, { fontSize: "inherit" }) }) })] }, s.materialID))), LazySeq.ofRange(0, rowsPerPage - curPage.length).map((i) => (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, children: "\u00A0" }) }, i)))] })] }), _jsxs(Toolbar, { variant: "dense", sx: { mb: "0.5em" }, children: [_jsx(Typography, { color: "textSecondary", variant: "caption", children: "Rows per page:" }), _jsx(Select, { style: { marginLeft: 8, marginRight: "1em" }, value: rowsPerPage, SelectDisplayProps: { style: { color: "rgba(0, 0, 0, 0.54)" } }, input: _jsx(InputBase, {}), onChange: (evt) => {
|
|
@@ -162,7 +162,12 @@ function MaterialTable({ material }) {
|
|
|
162
162
|
}, children: [10, 15, 20, 50].map((rowsPerPageOption) => (_jsx(MenuItem, { value: rowsPerPageOption, children: rowsPerPageOption }, rowsPerPageOption))) }), _jsx(Typography, { color: "textSecondary", variant: "caption", children: `${material.length === 0 ? 0 : page * rowsPerPage + 1}-${Math.min(material.length, (page + 1) * rowsPerPage)} of ${material.length}` }), _jsx(IconButton, { onClick: () => setPage(0), disabled: page === 0, "aria-label": "First Page", size: "large", children: _jsx(FirstPageIcon, {}) }), _jsx(IconButton, { onClick: () => setPage(page - 1), disabled: page === 0, "aria-label": "Previous Page", size: "large", children: _jsx(KeyboardArrowLeft, {}) }), _jsx(IconButton, { onClick: () => setPage(page + 1), disabled: page >= Math.ceil(material.length / rowsPerPage) - 1, "aria-label": "Next Page", size: "large", children: _jsx(KeyboardArrowRight, {}) }), _jsx(IconButton, { onClick: () => setPage(Math.max(0, Math.ceil(material.length / rowsPerPage) - 1)), disabled: page >= Math.ceil(material.length / rowsPerPage) - 1, "aria-label": "Last Page", size: "large", children: _jsx(LastPageIcon, {}) })] })] }));
|
|
163
163
|
}
|
|
164
164
|
const PartDetails = memo(function PartDetails({ part }) {
|
|
165
|
-
return (_jsxs(Stack, { direction: "row",
|
|
165
|
+
return (_jsxs(Stack, { direction: "row", sx: {
|
|
166
|
+
flexWrap: "wrap",
|
|
167
|
+
justifyContent: "space-around",
|
|
168
|
+
ml: "1em",
|
|
169
|
+
mr: "1em",
|
|
170
|
+
}, children: [_jsx(Box, { sx: { width: "60em", overflow: "auto" }, children: _jsx(MaterialTable, { material: part.mats }) }), _jsx(Box, { sx: { width: "40em", overflow: "auto" }, children: _jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Station" }), _jsx(TableCell, { children: "Active Hours" }), _jsx(TableCell, { children: "Elapsed Hours" }), _jsx(TableCell, { children: "Total Median Hours" })] }) }), _jsx(TableBody, { children: part.stationMins.toAscLazySeq().map(([st, times]) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: st }), _jsx(TableCell, { children: numFormat.format(times.active / 60) }), _jsx(TableCell, { children: numFormat.format(times.elapsed / 60) }), _jsx(TableCell, { children: numFormat.format(times.medianElapsed / 60) })] }, st))) })] }) })] }));
|
|
166
171
|
});
|
|
167
172
|
const PartTableRow = styled(TableRow)({
|
|
168
173
|
"& > *": {
|
|
@@ -174,7 +179,9 @@ const PartRow = memo(function PartRow({ part }) {
|
|
|
174
179
|
return (_jsxs(_Fragment, { children: [_jsxs(PartTableRow, { children: [_jsx(TableCell, { children: _jsxs(Box, { sx: {
|
|
175
180
|
display: "flex",
|
|
176
181
|
alignItems: "center",
|
|
177
|
-
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: part.part, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span",
|
|
182
|
+
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: part.part, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span", sx: {
|
|
183
|
+
display: "block",
|
|
184
|
+
}, children: part.part }) })] }) }), _jsx(TableCell, { align: "right", children: part.completedQty }), _jsx(TableCell, { align: "right", children: part.abnormalQty }), _jsx(TableCell, { align: "right", children: numFormat.format(part.stationMins
|
|
178
185
|
.toAscLazySeq()
|
|
179
186
|
.filter(([_, stat]) => !stat.isLoadUnload)
|
|
180
187
|
.sumBy(([_, t]) => t.active) / 60) }), _jsx(TableCell, { align: "right", children: numFormat.format(part.stationMins
|
|
@@ -190,13 +197,13 @@ function CopyToClipboardBtn({ partsAtom }) {
|
|
|
190
197
|
return (_jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, size: "large", onClick: () => copyPartsToClipboard(parts), children: _jsx(ImportExport, {}) }) }));
|
|
191
198
|
}
|
|
192
199
|
function MedianHelpTooltip() {
|
|
193
|
-
return (_jsx(Tooltip, { title: "Total Median Hours are calculated by taking the median cycle time (excluding outliers) and adding up for each piece of material.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(
|
|
200
|
+
return (_jsx(Tooltip, { title: "Total Median Hours are calculated by taking the median cycle time (excluding outliers) and adding up for each piece of material.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(HelpOutlined, { fontSize: "inherit" }) }) }));
|
|
194
201
|
}
|
|
195
202
|
function TimeCuttoffHelpTooltip() {
|
|
196
|
-
return (_jsx(Tooltip, { title: "The entire cycle time is credited at the time the cycle completes, so it may be that a day has more than 24 hours of credited time for example.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(
|
|
203
|
+
return (_jsx(Tooltip, { title: "The entire cycle time is credited at the time the cycle completes, so it may be that a day has more than 24 hours of credited time for example.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(HelpOutlined, { fontSize: "inherit" }) }) }));
|
|
197
204
|
}
|
|
198
205
|
function AbnormalHelpTooltip() {
|
|
199
|
-
return (_jsx(Tooltip, { title: "An abnormal part is one which was quarantined, had a failed inspection, or was explicitly marked as failing closeout. A successful closeout overrides this and will never be an abnormal part.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(
|
|
206
|
+
return (_jsx(Tooltip, { title: "An abnormal part is one which was quarantined, had a failed inspection, or was explicitly marked as failing closeout. A successful closeout overrides this and will never be an abnormal part.", children: _jsx("span", { style: { verticalAlign: "middle", marginLeft: "0.5em", fontSize: 16 }, children: _jsx(HelpOutlined, { fontSize: "inherit" }) }) }));
|
|
200
207
|
}
|
|
201
208
|
const PartHeader = memo(function PartHeader({ partsAtom, order, setOrder, sortBy, setSortBy, }) {
|
|
202
209
|
const sort = {
|
|
@@ -239,7 +246,12 @@ const CompletedPartsMaterialDialog = memo(function CompletedPartsMaterialDialog(
|
|
|
239
246
|
});
|
|
240
247
|
export function RecentCompletedPartsPage() {
|
|
241
248
|
useSetTitle("Completed Parts");
|
|
242
|
-
return (_jsxs(Box, { component: "main",
|
|
249
|
+
return (_jsxs(Box, { component: "main", sx: {
|
|
250
|
+
padding: "24px",
|
|
251
|
+
}, children: [_jsxs(Stack, { direction: "row", spacing: 2, sx: {
|
|
252
|
+
alignItems: "center",
|
|
253
|
+
justifyContent: "space-between",
|
|
254
|
+
}, children: [_jsx("span", { children: "Completed Parts" }), _jsx(Last30ChartRangeToolbar, { chartAtom: last30PartSummaryRange })] }), _jsx(CompletedPartsTable, { partsAtom: last30PartSummary }), _jsx(CompletedPartsMaterialDialog, {}), _jsx(SelectWorkorderDialog, {})] }));
|
|
243
255
|
}
|
|
244
256
|
function copyPartsToClipboard(parts) {
|
|
245
257
|
let table = "<table>\n<thead><tr>";
|
|
@@ -282,5 +294,5 @@ function copyPartsToClipboard(parts) {
|
|
|
282
294
|
table += "</tr>\n";
|
|
283
295
|
}
|
|
284
296
|
table += "</tbody></table>\n";
|
|
285
|
-
copy(table, { format: "text/html" });
|
|
297
|
+
void copy(table, { format: "text/html" });
|
|
286
298
|
}
|
|
@@ -42,7 +42,7 @@ import { TableCell } from "@mui/material";
|
|
|
42
42
|
import { TableHead } from "@mui/material";
|
|
43
43
|
import { TableBody } from "@mui/material";
|
|
44
44
|
import { MaterialDialog, PartIdenticon } from "../station-monitor/Material.js";
|
|
45
|
-
import { KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, ImportExport, MoreHoriz, Warning as WarningIcon, Check,
|
|
45
|
+
import { KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, ImportExport, MoreHoriz, Warning as WarningIcon, Check, ErrorOutlined, SavedSearch, Search, Clear, Loop, } from "@mui/icons-material";
|
|
46
46
|
import { Collapse } from "@mui/material";
|
|
47
47
|
import { addWorkorderComment, currentStatus } from "../../cell-status/current-status.js";
|
|
48
48
|
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
@@ -101,12 +101,19 @@ const WorkorderDetails = memo(function WorkorderDetails({ workorder, }) {
|
|
|
101
101
|
setMatToShow({
|
|
102
102
|
type: "MatSummary",
|
|
103
103
|
summary: {
|
|
104
|
-
|
|
104
|
+
materialID: wmat.materialID,
|
|
105
105
|
partName: workorder.part,
|
|
106
|
+
serial: wmat.serial,
|
|
107
|
+
workorderId: workorder.workorderId,
|
|
106
108
|
},
|
|
107
109
|
});
|
|
108
110
|
}
|
|
109
|
-
return (_jsxs(Stack, { direction: "row",
|
|
111
|
+
return (_jsxs(Stack, { direction: "row", sx: {
|
|
112
|
+
flexWrap: "wrap",
|
|
113
|
+
justifyContent: "space-around",
|
|
114
|
+
ml: "1em",
|
|
115
|
+
mr: "1em",
|
|
116
|
+
}, children: [_jsx("div", { children: _jsxs(Table, { size: "small", stickyHeader: true, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Serial" }), _jsx(TableCell, { children: "Quarantine?" }), _jsx(TableCell, { sx: { whiteSpace: "nowrap" }, children: "Inspect Failed?" }), _jsx(TableCell, { sx: { whiteSpace: "nowrap" }, children: "Close Out" }), _jsx(TableCell, { padding: "checkbox" })] }) }), _jsx(TableBody, { children: (workorder.material ?? []).map((s) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: s.serial ?? "" }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.quarantined ? _jsx(SavedSearch, { fontSize: "inherit" }) : "" }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.inspectionFailed ? _jsx(ErrorOutlined, { fontSize: "inherit" }) : "" }), _jsx(TableCell, { sx: { textAlign: "center" }, padding: "checkbox", children: s.closeout === WorkorderSerialCloseout.None ? ("") : s.closeout === WorkorderSerialCloseout.ClosedOut ? (_jsx(Check, { fontSize: "inherit" })) : (_jsx(ErrorOutlined, { fontSize: "inherit" })) }), _jsx(TableCell, { padding: "checkbox", children: _jsx(IconButton, { onClick: () => show(s), size: "large", children: _jsx(MoreHoriz, { fontSize: "inherit" }) }) })] }, s.materialID))) })] }) }), _jsx("div", { children: _jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Station" }), _jsx(TableCell, { children: "Active Minutes" }), _jsx(TableCell, { children: "Elapsed Minutes" })] }) }), _jsx(TableBody, { children: stationNames.map((st) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: st }), _jsx(TableCell, { children: numFormat.format(durationToMinutes(workorder.activeStationTime?.[st] ?? 0)) }), _jsx(TableCell, { children: numFormat.format(durationToMinutes(workorder.elapsedStationTime?.[st] ?? 0)) })] }, st))) })] }) }), _jsxs("div", { children: [_jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Time" }), _jsx(TableCell, { children: "Comment" })] }) }), _jsx(TableBody, { children: (workorder.comments ?? []).map((c, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: c.timeUTC.toLocaleString(undefined, {
|
|
110
117
|
year: "numeric",
|
|
111
118
|
month: "numeric",
|
|
112
119
|
day: "numeric",
|
|
@@ -134,7 +141,9 @@ function WorkorderRow({ workorder, showSim, }) {
|
|
|
134
141
|
return (_jsxs(_Fragment, { children: [_jsxs(WorkorderTableRow, { children: [_jsx(TableCell, { children: workorder.workorderId }), _jsx(TableCell, { children: _jsxs(Box, { sx: {
|
|
135
142
|
display: "flex",
|
|
136
143
|
alignItems: "center",
|
|
137
|
-
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: workorder.part, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span",
|
|
144
|
+
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: workorder.part, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span", sx: {
|
|
145
|
+
display: "block",
|
|
146
|
+
}, children: workorder.part }) })] }) }), _jsx(TableCell, { children: workorder.dueDate === null ? "" : workorder.dueDate.toLocaleDateString() }), _jsx(TableCell, { align: "right", children: workorder.priority }), _jsx(TableCell, { align: "right", children: workorder.plannedQuantity }), _jsx(TableCell, { align: "right", children: workorder.material?.length ?? 0 }), _jsx(TableCell, { align: "right", children: workorder.material?.filter(isAbnormal).length ?? 0 }), _jsx(TableCell, { align: "right", children: workorder.completedQuantity }), showSim ? (_jsxs(_Fragment, { children: [_jsx(TableCell, { align: "right", children: utcDateOnlyToString(workorder.simulatedStart) }), _jsx(TableCell, { align: "right", children: utcDateOnlyToString(workorder.simulatedFilled) })] })) : undefined, _jsx(TableCell, { children: _jsx(Tooltip, { title: "Show Details", children: _jsx(IconButton, { size: "small", onClick: () => setOpen(!open), children: open ? _jsx(KeyboardArrowUpIcon, {}) : _jsx(KeyboardArrowDownIcon, {}) }) }) })] }), _jsx(TableRow, { children: _jsx(TableCell, { sx: { pb: "0", pt: "0" }, colSpan: colCnt, children: _jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: _jsx(WorkorderDetails, { workorder: workorder }) }) }) })] }));
|
|
138
147
|
}
|
|
139
148
|
var SortColumn;
|
|
140
149
|
(function (SortColumn) {
|
|
@@ -224,7 +233,7 @@ function copyWorkordersToClipboard(workorders, showSim) {
|
|
|
224
233
|
table += `<td>${utcDateOnlyToString(w.simulatedStart)}</td>`;
|
|
225
234
|
table += `<td>${utcDateOnlyToString(w.simulatedFilled)}</td>`;
|
|
226
235
|
}
|
|
227
|
-
table += `<td>${(w.material ?? []).map((
|
|
236
|
+
table += `<td>${(w.material ?? []).map((mat) => mat.serial ?? "").join(";")}</td>`;
|
|
228
237
|
table += `<td>${LazySeq.ofObject(w.activeStationTime ?? {})
|
|
229
238
|
.map(([st, t]) => `${st}: ${durationToMinutes(t)}`)
|
|
230
239
|
.toRArray()
|
|
@@ -236,7 +245,7 @@ function copyWorkordersToClipboard(workorders, showSim) {
|
|
|
236
245
|
table += "</tr>\n";
|
|
237
246
|
}
|
|
238
247
|
table += "</tbody></table>\n";
|
|
239
|
-
copy(table);
|
|
248
|
+
void copy(table);
|
|
240
249
|
}
|
|
241
250
|
function SortColHeader(props) {
|
|
242
251
|
return (_jsxs(TableCell, { align: props.align, sortDirection: props.sortBy === props.col ? props.order : false, children: [_jsx(Tooltip, { title: "Sort", enterDelay: 300, children: _jsx(TableSortLabel, { active: props.sortBy === props.col, direction: props.order, onClick: () => {
|
|
@@ -252,7 +261,13 @@ function SortColHeader(props) {
|
|
|
252
261
|
const tableOrGantt = atom("table");
|
|
253
262
|
const SimulatedWarning = memo(function SimulatedWarning({ showSim }) {
|
|
254
263
|
const [selected, setSelected] = useAtom(tableOrGantt);
|
|
255
|
-
return (_jsxs(Stack, { direction: "row", spacing: 2,
|
|
264
|
+
return (_jsxs(Stack, { direction: "row", spacing: 2, sx: {
|
|
265
|
+
justifyContent: "flex-end",
|
|
266
|
+
alignItems: "center",
|
|
267
|
+
}, children: [showSim ? (_jsxs(Stack, { direction: "row", spacing: 2, sx: {
|
|
268
|
+
alignItems: "center",
|
|
269
|
+
flexGrow: 1,
|
|
270
|
+
}, children: [_jsx(WarningIcon, { fontSize: "small" }), _jsx(Typography, { variant: "caption", children: "Projected dates are estimates" })] })) : undefined, _jsx(FormControl, { size: "small", children: _jsxs(Select, { variant: "outlined", value: selected, onChange: (e) => setSelected(e.target.value), children: [_jsx(MenuItem, { value: "table", children: "Table" }), _jsx(MenuItem, { value: "gantt", children: "Gantt" })] }) })] }));
|
|
256
271
|
});
|
|
257
272
|
const rotateKeyframes = keyframes `
|
|
258
273
|
0% {
|
|
@@ -328,7 +343,12 @@ function WorkorderCommentDialog() {
|
|
|
328
343
|
}
|
|
329
344
|
function SearchingWorkorder() {
|
|
330
345
|
const [workId, setWorkId] = useAtom(currentWorkorderIdToSearch);
|
|
331
|
-
return (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, children: _jsxs(Stack, { direction: "column",
|
|
346
|
+
return (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, children: _jsxs(Stack, { direction: "column", sx: {
|
|
347
|
+
mt: "3em",
|
|
348
|
+
flex: "flex",
|
|
349
|
+
alignItems: "center",
|
|
350
|
+
width: "100%",
|
|
351
|
+
}, children: [_jsxs(Stack, { direction: "row", spacing: "3", children: [_jsx(CircularProgress, {}), workId && workId !== "" ? (_jsxs(Typography, { variant: "h6", children: ["Searching for workorder ", workId] })) : (_jsx(Typography, { variant: "h6", children: "Searching" }))] }), _jsx(Button, { onClick: () => setWorkId(null), children: "Cancel" })] }) }) }));
|
|
332
352
|
}
|
|
333
353
|
function WorkorderTable({ showSim, disableSearch, }) {
|
|
334
354
|
const [sortBy, setSortBy] = useState(SortColumn.WorkorderId);
|
|
@@ -364,5 +384,7 @@ export const CurrentWorkordersPage = memo(function RecentWorkordersPage({ disabl
|
|
|
364
384
|
const currentSt = useAtomValue(currentStatus);
|
|
365
385
|
const display = useAtomValue(tableOrGantt);
|
|
366
386
|
const showSim = useMemo(() => currentSt.workorders?.some((w) => !!w.simulatedStart || !!w.simulatedFilled) ?? false, [currentSt.workorders]);
|
|
367
|
-
return (_jsxs(Box, { component: "main",
|
|
387
|
+
return (_jsxs(Box, { component: "main", sx: {
|
|
388
|
+
padding: "24px",
|
|
389
|
+
}, children: [showSim ? _jsx(SimulatedWarning, { showSim: showSim }) : undefined, display === "table" ? (_jsx(WorkorderTable, { showSim: showSim, disableSearch: disableSearch })) : (_jsx(WorkorderGantt, {})), _jsx(WorkorderCommentDialog, {}), _jsx(WorkSerialDialog, {}), _jsx(SelectWorkorderDialog, {})] }));
|
|
368
390
|
});
|
|
@@ -164,10 +164,16 @@ export function StationOEEPage({ ty }) {
|
|
|
164
164
|
const cycles = useAtomValue(last30StationCycles);
|
|
165
165
|
const statUse = useAtomValue(last30SimStationUse);
|
|
166
166
|
const points = useMemo(() => buildOeeSeries(start, end, ty, cycles.valuesToLazySeq(), statUse), [start, end, ty, cycles, statUse]);
|
|
167
|
-
return (_jsxs(Box, {
|
|
167
|
+
return (_jsxs(Box, { sx: {
|
|
168
|
+
paddingLeft: "24px",
|
|
169
|
+
paddingRight: "24px",
|
|
170
|
+
paddingTop: "10px",
|
|
171
|
+
}, children: [_jsxs(Box, { component: "nav", sx: {
|
|
168
172
|
display: "flex",
|
|
169
173
|
minHeight: "2.5em",
|
|
170
174
|
alignItems: "center",
|
|
171
175
|
maxWidth: "calc(100vw - 24px - 24px)",
|
|
172
|
-
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [ty === "labor" ? "Load/Unload" : "Machine", " OEE: comparing flexplan hours between actual and simulated production"] }), _jsx(Box, {
|
|
176
|
+
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [ty === "labor" ? "Load/Unload" : "Machine", " OEE: comparing flexplan hours between actual and simulated production"] }), _jsx(Box, { sx: {
|
|
177
|
+
flexGrow: 1,
|
|
178
|
+
} }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showChart ? "chart" : "table", onChange: (e) => setShowChart(e.target.value === "chart"), children: [_jsx(MenuItem, { value: "chart", children: "Chart" }, "chart"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(MuiTooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, onClick: () => copyOeeToClipboard(points), size: "large", children: _jsx(ImportExport, {}) }) })] }), _jsx("main", { children: showChart ? _jsx(OEEChart, { points: points }) : _jsx(OEETable, { points: points }) })] }));
|
|
173
179
|
}
|
|
@@ -40,30 +40,41 @@ import { ImportExport } from "@mui/icons-material";
|
|
|
40
40
|
import StationDataTable from "../analysis/StationDataTable.js";
|
|
41
41
|
import { copyCyclesToClipboard } from "../../data/results.cycles.js";
|
|
42
42
|
import { last30MaterialSummary } from "../../cell-status/material-summary.js";
|
|
43
|
-
import { last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
43
|
+
import { isLaborCycle, last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
44
44
|
import { useSetTitle } from "../routes.js";
|
|
45
45
|
import { useAtomValue } from "jotai";
|
|
46
|
+
import { fmsInformation } from "../../network/server-settings.js";
|
|
46
47
|
export function OutlierCycles({ outlierTy }) {
|
|
47
48
|
useSetTitle(outlierTy === "machine" ? "Machine Outliers" : "L/U Outliers");
|
|
48
49
|
const matSummary = useAtomValue(last30MaterialSummary);
|
|
50
|
+
const fmsInfo = useAtomValue(fmsInformation);
|
|
49
51
|
const today = startOfToday();
|
|
50
52
|
const allCycles = useAtomValue(last30StationCycles);
|
|
51
53
|
const points = useMemo(() => {
|
|
52
|
-
const
|
|
53
|
-
const start = addDays(
|
|
54
|
-
const end = addDays(
|
|
54
|
+
const todayStart = startOfToday();
|
|
55
|
+
const start = addDays(todayStart, -4);
|
|
56
|
+
const end = addDays(todayStart, 1);
|
|
55
57
|
return {
|
|
56
58
|
seriesLabel: "Part",
|
|
57
59
|
data: allCycles
|
|
58
60
|
.valuesToLazySeq()
|
|
59
|
-
.filter((c) => c.isOutlier &&
|
|
61
|
+
.filter((c) => c.isOutlier &&
|
|
62
|
+
c.endTime >= start &&
|
|
63
|
+
c.endTime < end &&
|
|
64
|
+
isLaborCycle(c) === (outlierTy === "labor"))
|
|
60
65
|
.toRLookup((e) => e.part + "-" + e.material[0].proc.toString()),
|
|
61
66
|
};
|
|
62
67
|
}, [outlierTy, allCycles]);
|
|
63
|
-
return (_jsxs(Box, {
|
|
68
|
+
return (_jsxs(Box, { sx: {
|
|
69
|
+
paddingLeft: "24px",
|
|
70
|
+
paddingRight: "24px",
|
|
71
|
+
paddingTop: "10px",
|
|
72
|
+
}, children: [_jsxs(Box, { component: "nav", sx: {
|
|
64
73
|
display: "flex",
|
|
65
74
|
minHeight: "2.5em",
|
|
66
75
|
alignItems: "center",
|
|
67
76
|
maxWidth: "calc(100vw - 24px - 24px)",
|
|
68
|
-
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [outlierTy === "labor" ? "Load/Unload" : "Machine", " cycles from the past 5 days statistically outside expected range"] }), _jsx(Box, {
|
|
77
|
+
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [outlierTy === "labor" ? "Load/Unload" : "Machine", " cycles from the past 5 days statistically outside expected range"] }), _jsx(Box, { sx: {
|
|
78
|
+
flexGrow: 1,
|
|
79
|
+
} }), _jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, onClick: () => copyCyclesToClipboard(points, matSummary.matsById, undefined, undefined, fmsInfo.loadStationNames, fmsInfo.basketName), size: "large", children: _jsx(ImportExport, {}) }) })] }), _jsx("main", { children: _jsx(StationDataTable, { points: points.data, matsById: matSummary.matsById, current_date_zoom: { start: addDays(today, -4), end: addDays(today, 1) }, set_date_zoom_range: undefined, period: { type: "Last30" }, showWorkorderAndInspect: false, defaultSortDesc: true }) })] }));
|
|
69
80
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
1
|
+
/// <reference lib="webworker" />
|
|
4
2
|
import hljs from "highlight.js/lib/core";
|
|
5
3
|
import gcode from "highlight.js/lib/languages/gcode";
|
|
6
4
|
hljs.registerLanguage("gcode", gcode);
|
|
7
|
-
self.
|
|
8
|
-
self.postMessage(hljs.highlight(event.data, { language: "gcode" }).value);
|
|
9
|
-
};
|
|
5
|
+
self.addEventListener("message", (event) => {
|
|
6
|
+
self.postMessage(hljs.highlight(event.data, { language: "gcode" }).value, []);
|
|
7
|
+
});
|
|
@@ -250,17 +250,19 @@ function ProgramContentCode() {
|
|
|
250
250
|
const worker = useMemo(() => new Worker(new URL("./ProgramHighlight.ts", import.meta.url), { type: "module" }), []);
|
|
251
251
|
useEffect(() => {
|
|
252
252
|
let set = (h) => setHighlighted(h);
|
|
253
|
-
|
|
253
|
+
const handleMessage = (event) => set(event.data);
|
|
254
|
+
worker.addEventListener("message", handleMessage);
|
|
254
255
|
return () => {
|
|
255
256
|
// cleanup
|
|
256
257
|
set = () => null;
|
|
258
|
+
worker.removeEventListener("message", handleMessage);
|
|
257
259
|
worker.terminate();
|
|
258
260
|
setHighlighted(null);
|
|
259
261
|
};
|
|
260
262
|
}, [worker]);
|
|
261
263
|
useEffect(() => {
|
|
262
264
|
if (ct && ct !== "") {
|
|
263
|
-
worker.postMessage(ct);
|
|
265
|
+
worker.postMessage(ct, []);
|
|
264
266
|
}
|
|
265
267
|
}, [ct, worker]);
|
|
266
268
|
return (_jsx("pre", { children: highlighted === null ? (_jsx("code", { className: "gcode", children: ct })) : (_jsx("code", { className: "gcode", dangerouslySetInnerHTML: { __html: highlighted } })) }));
|
|
@@ -359,5 +361,9 @@ function ProgNavHeader() {
|
|
|
359
361
|
}
|
|
360
362
|
export function ProgramReportPage() {
|
|
361
363
|
useSetTitle("Programs");
|
|
362
|
-
return (_jsxs(Box, {
|
|
364
|
+
return (_jsxs(Box, { sx: {
|
|
365
|
+
paddingLeft: "24px",
|
|
366
|
+
paddingRight: "24px",
|
|
367
|
+
paddingTop: "10px",
|
|
368
|
+
}, children: [_jsx(ProgNavHeader, {}), _jsx("main", { children: _jsx(DisplayLoadingAndError, { children: _jsx(ProgramSummaryTable, {}) }) }), _jsx(ProgramContentDialog, {}), _jsx(ProgramHistoryDialog, {})] }));
|
|
363
369
|
}
|
|
@@ -73,7 +73,9 @@ const columns = [
|
|
|
73
73
|
numeric: false,
|
|
74
74
|
label: "Part",
|
|
75
75
|
getDisplay: (r) => r.partName,
|
|
76
|
-
Cell: ({ row }) => (_jsxs(Stack, { direction: "row", spacing: 1,
|
|
76
|
+
Cell: ({ row }) => (_jsxs(Stack, { direction: "row", spacing: 1, sx: {
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
}, children: [_jsx(PartIdenticon, { part: row.partName, size: 25 }), row.partName] })),
|
|
77
79
|
},
|
|
78
80
|
{
|
|
79
81
|
id: ColumnId.Quantity,
|
|
@@ -191,10 +193,12 @@ const NewRebookingDialog = memo(function NewRebookingDialog() {
|
|
|
191
193
|
}
|
|
192
194
|
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
195
|
input: {
|
|
194
|
-
...params.
|
|
195
|
-
startAdornment: (_jsxs(_Fragment, { children: [rebooking.part !== "" ? (_jsx(InputAdornment, { position: "start", children: _jsx(PartIdenticon, { part: rebooking.part, size: 25 }) })) : undefined, params.
|
|
196
|
+
...params.slotProps.input,
|
|
197
|
+
startAdornment: (_jsxs(_Fragment, { children: [rebooking.part !== "" ? (_jsx(InputAdornment, { position: "start", children: _jsx(PartIdenticon, { part: rebooking.part, size: 25 }) })) : undefined, params.slotProps.input?.startAdornment] })),
|
|
196
198
|
},
|
|
197
|
-
} })), renderOption: (props, option) => (_jsx("li", { ...props, children: _jsxs(Stack, { direction: "row", spacing: "1",
|
|
199
|
+
} })), renderOption: (props, option) => (_jsx("li", { ...props, children: _jsxs(Stack, { direction: "row", spacing: "1", sx: {
|
|
200
|
+
alignItems: "center",
|
|
201
|
+
}, children: [_jsx(PartIdenticon, { part: option, size: 25 }), option] }) })), filterOptions: (options, params) => {
|
|
198
202
|
const filtered = options.filter((o) => o.toLowerCase().includes(params.inputValue.toLowerCase()));
|
|
199
203
|
return filtered.length === 0 && params.inputValue !== "" ? [params.inputValue] : filtered;
|
|
200
204
|
} }), _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, {}) }) })] }));
|
|
@@ -46,6 +46,7 @@ import { currentCycles } from "../../data/current-cycles.js";
|
|
|
46
46
|
import { currentStatus } from "../../cell-status/current-status.js";
|
|
47
47
|
import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
|
|
48
48
|
import { atom, useAtomValue, useSetAtom } from "jotai";
|
|
49
|
+
import { fmsInformation } from "../../network/server-settings.js";
|
|
49
50
|
import { AxisBottom, AxisLeft, GridCols } from "../AxisAndGrid.js";
|
|
50
51
|
import { measureSvgString } from "../../util/chart-helpers.js";
|
|
51
52
|
import { scaleBand, scaleTime } from "d3-scale";
|
|
@@ -65,7 +66,7 @@ function useSimCycles() {
|
|
|
65
66
|
// make sure all planned downtimes come last so they are drawn over the top of any cycles
|
|
66
67
|
.sortBy((s) => (s.plannedDown ? 1 : 0))
|
|
67
68
|
.map((s) => ({
|
|
68
|
-
station: s.
|
|
69
|
+
station: s.stationLabel,
|
|
69
70
|
start: s.start,
|
|
70
71
|
end: s.end,
|
|
71
72
|
plannedDown: s.plannedDown,
|
|
@@ -214,13 +215,14 @@ export function RecentCycleChart({ height, width }) {
|
|
|
214
215
|
const estimated = useAtomValue(last30EstimatedCycleTimes);
|
|
215
216
|
const sim = useSimCycles();
|
|
216
217
|
const currentSt = useAtomValue(currentStatus);
|
|
218
|
+
const fmsInfo = useAtomValue(fmsInformation);
|
|
217
219
|
const cycles = useMemo(() => {
|
|
218
220
|
const cutoff = addHours(new Date(), -12);
|
|
219
221
|
return recentCycles(last30Cycles.valuesToLazySeq().filter((e) => e.endTime >= cutoff));
|
|
220
222
|
}, [last30Cycles]);
|
|
221
223
|
const current = useMemo(() => {
|
|
222
|
-
return currentCycles(currentSt, estimated);
|
|
223
|
-
}, [currentSt, estimated]);
|
|
224
|
+
return currentCycles(currentSt, estimated, fmsInfo.loadStationNames);
|
|
225
|
+
}, [currentSt, estimated, fmsInfo.loadStationNames]);
|
|
224
226
|
// ensure a re-render at least every 5 minutes, but reset the timer if the data changes
|
|
225
227
|
const now = new Date();
|
|
226
228
|
const [, forceRerender] = useState(0);
|
|
@@ -39,7 +39,7 @@ import { ShiftStart, useShifts } from "./ShiftSettings.js";
|
|
|
39
39
|
import { SkipPrevious as SkipPrevIcon, SkipNext as SkipNextIcon, ImportExport } from "@mui/icons-material";
|
|
40
40
|
import { LazySeq, OrderedMap } from "@seedtactics/immutable-collections";
|
|
41
41
|
import { last30SimProduction } from "../../cell-status/sim-production.js";
|
|
42
|
-
import { last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
42
|
+
import { isLaborCycle, last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
43
43
|
import { PartIdenticon } from "../station-monitor/Material.js";
|
|
44
44
|
import { useSetTitle } from "../routes.js";
|
|
45
45
|
import { useAtomValue } from "jotai";
|
|
@@ -74,7 +74,7 @@ function binSimProduction(prod, shifts) {
|
|
|
74
74
|
function binCompleted(cycles, shifts) {
|
|
75
75
|
return cycles
|
|
76
76
|
.valuesToLazySeq()
|
|
77
|
-
.filter((cycle) => cycle
|
|
77
|
+
.filter((cycle) => isLaborCycle(cycle) &&
|
|
78
78
|
cycle.operation === "UNLOAD" &&
|
|
79
79
|
LazySeq.of(cycle.material).some((m) => m.proc === m.numproc))
|
|
80
80
|
.collect(decideShift((c) => c.endTime, shifts))
|
|
@@ -85,18 +85,18 @@ function useRows(day) {
|
|
|
85
85
|
const sim = useAtomValue(last30SimProduction);
|
|
86
86
|
const shifts = useShifts(day);
|
|
87
87
|
return useMemo(() => {
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
return
|
|
88
|
+
const plannedByDay = binSimProduction(sim, shifts);
|
|
89
|
+
const completedByDay = binCompleted(cycles, shifts);
|
|
90
|
+
return plannedByDay
|
|
91
91
|
.mapValues((p) => ({
|
|
92
92
|
planned: p,
|
|
93
93
|
}))
|
|
94
|
-
.adjust(
|
|
94
|
+
.adjust(completedByDay, (plan, comp) => (plan ? { ...plan, completed: comp } : { completed: comp }))
|
|
95
95
|
.toAscLazySeq()
|
|
96
|
-
.map(([partName, { planned, completed }]) => ({
|
|
96
|
+
.map(([partName, { planned: plannedCounts, completed: completedCounts }]) => ({
|
|
97
97
|
part: partName,
|
|
98
|
-
planned:
|
|
99
|
-
completed:
|
|
98
|
+
planned: plannedCounts ?? OrderedMap.empty(),
|
|
99
|
+
completed: completedCounts ?? OrderedMap.empty(),
|
|
100
100
|
}))
|
|
101
101
|
.toRArray();
|
|
102
102
|
}, [cycles, sim, shifts]);
|
|
@@ -108,7 +108,9 @@ const fulldayFormat = new Intl.DateTimeFormat(undefined, {
|
|
|
108
108
|
year: "numeric",
|
|
109
109
|
});
|
|
110
110
|
function PartCell({ row }) {
|
|
111
|
-
return (_jsxs(Stack, { direction: "row", spacing: 1,
|
|
111
|
+
return (_jsxs(Stack, { direction: "row", spacing: 1, sx: {
|
|
112
|
+
alignItems: "center",
|
|
113
|
+
}, children: [_jsx(PartIdenticon, { part: row.part, size: 25 }), _jsx("span", { children: row.part })] }));
|
|
112
114
|
}
|
|
113
115
|
function useColumns(day) {
|
|
114
116
|
const numShifts = useShifts(day).length;
|
|
@@ -187,7 +189,9 @@ const RecentProductionTable = memo(function RecentSchedules({ columns, rows, })
|
|
|
187
189
|
});
|
|
188
190
|
function NavigateDay({ day, setDay, }) {
|
|
189
191
|
const today = startOfToday();
|
|
190
|
-
return (_jsxs(Stack, { direction: "row", spacing: 2,
|
|
192
|
+
return (_jsxs(Stack, { direction: "row", spacing: 2, sx: {
|
|
193
|
+
alignItems: "center",
|
|
194
|
+
}, children: [_jsx(Tooltip, { title: "Previous Day", children: _jsx("div", { children: _jsx(IconButton, { disabled: day <= addDays(today, -28), onClick: () => setDay((d) => addDays(d, -1)), children: _jsx(SkipPrevIcon, {}) }) }) }), _jsx(Typography, { sx: { minWidth: "14em", textAlign: "center" }, children: fulldayFormat.format(day) }), _jsx(Tooltip, { title: "Next Day", children: _jsx("div", { children: _jsx(IconButton, { disabled: day >= today, onClick: () => setDay((d) => addDays(d, 1)), children: _jsx(SkipNextIcon, {}) }) }) })] }));
|
|
191
195
|
}
|
|
192
196
|
const mdGridTemplate = '"shifts day export" auto / 1fr 1fr 1fr';
|
|
193
197
|
const xsGridTemplate = `"shifts export" auto
|
|
@@ -202,12 +206,25 @@ const RecentProductionToolbar = function RecentProductionToolbar({ day, setDay,
|
|
|
202
206
|
minHeight: "2.5em",
|
|
203
207
|
alignItems: "center",
|
|
204
208
|
maxWidth: "calc(100vw - 24px - 24px)",
|
|
205
|
-
}, children: [_jsx(Box, {
|
|
209
|
+
}, children: [_jsx(Box, { sx: {
|
|
210
|
+
gridArea: "shifts",
|
|
211
|
+
justifySelf: "flex-start",
|
|
212
|
+
}, children: _jsx(ShiftStart, {}) }), _jsx(Box, { sx: {
|
|
213
|
+
gridArea: "day",
|
|
214
|
+
justifySelf: "center",
|
|
215
|
+
}, children: _jsx(NavigateDay, { day: day, setDay: setDay }) }), _jsx(Box, { sx: {
|
|
216
|
+
gridArea: "export",
|
|
217
|
+
justifySelf: "flex-end",
|
|
218
|
+
}, children: _jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { onClick: () => copyTableToClipboard(columns, rows), children: _jsx(ImportExport, {}) }) }) })] }));
|
|
206
219
|
};
|
|
207
220
|
export function RecentProductionPage() {
|
|
208
221
|
useSetTitle("Recent Completed Parts");
|
|
209
222
|
const [day, setDay] = useState(startOfToday);
|
|
210
223
|
const columns = useColumns(day);
|
|
211
224
|
const rows = useRows(day);
|
|
212
|
-
return (_jsxs(Box, {
|
|
225
|
+
return (_jsxs(Box, { sx: {
|
|
226
|
+
paddingLeft: "24px",
|
|
227
|
+
paddingRight: "24px",
|
|
228
|
+
paddingTop: "10px",
|
|
229
|
+
}, children: [_jsx(RecentProductionToolbar, { day: day, setDay: setDay, rows: rows, columns: columns }), _jsx("main", { children: _jsx(RecentProductionTable, { rows: rows, columns: columns }) })] }));
|
|
213
230
|
}
|
|
@@ -76,10 +76,14 @@ function JobsRow(props) {
|
|
|
76
76
|
return (_jsxs(_Fragment, { children: [_jsxs(JobTableRow, { "$darkRow": props.showDarkRow && job.darkRow, children: [_jsx(TableCell, { children: job.routeStartTime.toLocaleString() }), _jsx(TableCell, { children: _jsxs(Box, { sx: {
|
|
77
77
|
display: "flex",
|
|
78
78
|
alignItems: "center",
|
|
79
|
-
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: job.partName, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span",
|
|
79
|
+
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: job.partName, size: 25 }) }), _jsx("div", { children: _jsx(Typography, { variant: "body2", component: "span", sx: {
|
|
80
|
+
display: "block",
|
|
81
|
+
}, children: job.partName }) })] }) }), props.showMaterial ? (_jsx(TableCell, { children: job.casting ? (_jsxs(Box, { sx: {
|
|
80
82
|
display: "flex",
|
|
81
83
|
alignItems: "center",
|
|
82
|
-
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: job.casting, size: 25 }) }), _jsx(Typography, { variant: "body2",
|
|
84
|
+
}, children: [_jsx(Box, { sx: { mr: "0.2em" }, children: _jsx(PartIdenticon, { part: job.casting, size: 25 }) }), _jsx(Typography, { variant: "body2", sx: {
|
|
85
|
+
display: "block",
|
|
86
|
+
}, children: job.casting })] })) : undefined })) : undefined, _jsxs(TableCell, { children: [job.comment, _jsx(Tooltip, { title: "Edit", children: _jsx(IconButton, { size: "small", onClick: () => props.setCurEditNoteJob(job), children: _jsx(EditIcon, {}) }) })] }), _jsx(TableCell, { children: job.inProcJob === null ? "Archived" : "Active" }), _jsx(TableCell, { align: "right", children: job.scheduledQty }), _jsx(TableCell, { align: "right", sx: { backgroundColor: job.decrementedQty > 0 ? "#FF8A65" : undefined }, children: job.decrementedQty }), _jsx(TableCell, { align: "right", children: job.completedQty }), _jsx(TableCell, { align: "right", children: job.inProcessQty }), _jsx(TableCell, { align: "right", children: job.remainingQty }), _jsx(TableCell, { children: _jsx(Tooltip, { title: "Show Details", children: _jsx(IconButton, { size: "small", onClick: () => setOpen(!open), children: open ? _jsx(KeyboardArrowUpIcon, {}) : _jsx(KeyboardArrowDownIcon, {}) }) }) })] }), _jsx(JobDetailRow, { "$darkRow": props.showDarkRow && job.darkRow, children: _jsx(TableCell, { sx: { pb: "0", pt: "0" }, colSpan: colCnt, children: _jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: _jsx(JobDetails, { job: job.inProcJob ? job.inProcJob : job.historicJob, checkAnalysisMonth: false }) }) }) })] }));
|
|
83
87
|
}
|
|
84
88
|
var SortColumn;
|
|
85
89
|
(function (SortColumn) {
|