@seedtactics/insight-client 16.8.4-beta.1 → 16.8.4-beta.11
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 +21 -0
- package/dist/assets/index-CQhVwNX7.js +388 -0
- package/dist/cell-status/material-details.d.ts +15 -5
- package/dist/cell-status/material-details.js +58 -37
- package/dist/components/LogEntry.js +2 -9
- package/dist/components/log-entry-container-name.d.ts +2 -0
- package/dist/components/log-entry-container-name.js +10 -0
- package/dist/components/operations/AllMaterial.js +4 -3
- package/dist/components/operations/Programs.js +1 -1
- package/dist/components/station-monitor/BasketLoadStationWork.js +44 -36
- package/dist/components/station-monitor/BulkRawMaterial.js +4 -4
- package/dist/components/station-monitor/CancelLoadButton.d.ts +4 -0
- package/dist/components/station-monitor/CancelLoadButton.js +59 -0
- package/dist/components/station-monitor/Closeout.js +2 -1
- package/dist/components/station-monitor/Inspection.js +2 -1
- package/dist/components/station-monitor/InvalidateCycle.d.ts +4 -1
- package/dist/components/station-monitor/InvalidateCycle.js +61 -10
- package/dist/components/station-monitor/LoadStation.js +23 -11
- package/dist/components/station-monitor/Material.js +2 -4
- package/dist/components/station-monitor/QuarantineButton.js +80 -60
- package/dist/components/station-monitor/Queues.js +2 -1
- package/dist/components/station-monitor/QueuesAddMaterial.js +59 -48
- package/dist/components/station-monitor/SystemOverview.js +3 -2
- package/dist/components/station-monitor/Whiteboard.js +2 -2
- package/dist/extension.d.ts +11 -0
- package/dist/extension.js +21 -0
- package/dist/index.html +1 -2
- package/dist/index.js +1 -1
- package/dist/network/api.d.ts +18 -4
- package/dist/network/api.js +69 -2
- package/dist/network/backend-mock.js +3 -0
- package/dist/network/backend.d.ts +1 -0
- package/dist/network/backend.js +2 -1
- package/package.json +12 -11
- package/dist/assets/index-Y5yNHUvc.js +0 -388
- package/dist/assets/manifest-BzJli0lx.webmanifest +0 -15
- package/dist/bootstrap.d.ts +0 -5
- package/dist/bootstrap.js +0 -56
- package/dist/components/station-monitor/Material.test.d.ts +0 -1
- package/dist/components/station-monitor/Material.test.js +0 -199
|
@@ -34,17 +34,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
34
34
|
import { Box, Button, ListItemIcon, ListItemText, ListSubheader, Stack } from "@mui/material";
|
|
35
35
|
import { MenuItem } from "@mui/material";
|
|
36
36
|
import { TextField } from "@mui/material";
|
|
37
|
-
import { ActionType, LocType } from "../../network/api.js";
|
|
37
|
+
import { ActionType, LocType, LogType, } from "../../network/api.js";
|
|
38
38
|
import { JobsBackend } from "../../network/backend.js";
|
|
39
|
-
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
39
|
+
import { HashMap, LazySeq } from "@seedtactics/immutable-collections";
|
|
40
40
|
import { currentStatus } from "../../cell-status/current-status.js";
|
|
41
|
-
import { barcodePotentialNewMaterial, inProcessMaterialInDialog, materialDialogOpen, materialInDialogInfo, materialInDialogLargestUsedProcess, } from "../../cell-status/material-details.js";
|
|
41
|
+
import { barcodePotentialNewMaterial, inProcessMaterialInDialog, materialDialogOpen, materialInDialogInfo, materialInDialogLargestUsedProcess, materialInDialogLocalEvents, } from "../../cell-status/material-details.js";
|
|
42
42
|
import { currentOperator } from "../../data/operators.js";
|
|
43
43
|
import { fmsInformation } from "../../network/server-settings.js";
|
|
44
44
|
import { useAtomValue, useSetAtom } from "jotai";
|
|
45
45
|
import { useEffect, useRef } from "react";
|
|
46
46
|
import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
|
|
47
47
|
import { PartIdenticon } from "./Material.js";
|
|
48
|
+
import { isLogEntryInvalidated } from "../LogEntry.js";
|
|
49
|
+
import { ApiException } from "../../network/api.js";
|
|
50
|
+
const invalidatableEventTypes = LazySeq.of([
|
|
51
|
+
LogType.AddToQueue,
|
|
52
|
+
LogType.RemoveFromQueue,
|
|
53
|
+
LogType.LoadUnloadCycle,
|
|
54
|
+
LogType.MachineCycle,
|
|
55
|
+
LogType.BasketLoadUnload,
|
|
56
|
+
LogType.BasketCycle,
|
|
57
|
+
]).toRSet((eventType) => eventType);
|
|
58
|
+
export function affectedMaterialForInvalidation(events, materialId, process) {
|
|
59
|
+
let affected = HashMap.empty();
|
|
60
|
+
for (const event of events) {
|
|
61
|
+
if (!invalidatableEventTypes.has(event.type) ||
|
|
62
|
+
isLogEntryInvalidated(event) ||
|
|
63
|
+
!event.material.some((material) => material.id === materialId && (process === null || material.proc >= process))) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (const material of event.material) {
|
|
67
|
+
affected = affected.set(material.id, material.serial ?? null);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return affected;
|
|
71
|
+
}
|
|
48
72
|
function InvalidateSelect(props) {
|
|
49
73
|
const lastMat = useAtomValue(materialInDialogLargestUsedProcess);
|
|
50
74
|
const possible = useAtomValue(barcodePotentialNewMaterial);
|
|
@@ -63,12 +87,13 @@ function InvalidateSelect(props) {
|
|
|
63
87
|
function change(e) {
|
|
64
88
|
props.setState({
|
|
65
89
|
updating: false,
|
|
90
|
+
error: null,
|
|
66
91
|
process: e.startsWith("proc") ? parseInt(e.substring(4)) : null,
|
|
67
92
|
changeRawMat: e.startsWith("rawMat") ? e.substring(6) : null,
|
|
68
93
|
changeJobUnique: e.startsWith("job") ? e.substring(3) : null,
|
|
69
94
|
});
|
|
70
95
|
}
|
|
71
|
-
return (_jsx(TextField, { value: props.st?.process
|
|
96
|
+
return (_jsx(TextField, { value: props.st?.process && hasProc
|
|
72
97
|
? "proc" + props.st.process.toString()
|
|
73
98
|
: props.st?.changeRawMat
|
|
74
99
|
? "rawMat" + props.st.changeRawMat
|
|
@@ -104,6 +129,8 @@ function InvalidateSelect(props) {
|
|
|
104
129
|
}
|
|
105
130
|
export function InvalidateCycleDialogContent(props) {
|
|
106
131
|
const curMat = useAtomValue(materialInDialogInfo);
|
|
132
|
+
const events = useAtomValue(materialInDialogLocalEvents);
|
|
133
|
+
const status = useAtomValue(currentStatus);
|
|
107
134
|
const show = props.st !== null && curMat !== null;
|
|
108
135
|
const boxRef = useRef(null);
|
|
109
136
|
useEffect(() => {
|
|
@@ -114,7 +141,17 @@ export function InvalidateCycleDialogContent(props) {
|
|
|
114
141
|
}, [boxRef, show]);
|
|
115
142
|
if (!show)
|
|
116
143
|
return _jsx("div", {});
|
|
117
|
-
|
|
144
|
+
const process = props.st.process ?? (props.st.changeRawMat || props.st.changeJobUnique ? null : undefined);
|
|
145
|
+
const affected = process === undefined
|
|
146
|
+
? HashMap.empty()
|
|
147
|
+
: affectedMaterialForInvalidation(events, curMat.materialID, process);
|
|
148
|
+
const affectedLabels = [...affected].map(([materialId, serial]) => ({
|
|
149
|
+
materialId,
|
|
150
|
+
serial,
|
|
151
|
+
queued: status.material.find((material) => material.materialID === materialId)?.location.type ===
|
|
152
|
+
LocType.InQueue,
|
|
153
|
+
}));
|
|
154
|
+
return (_jsx(Box, { ref: boxRef, sx: { display: "flex", flexDirection: "column", alignItems: "center", marginTop: "1em" }, children: _jsxs(Stack, { spacing: 2, children: [_jsx("p", { style: { maxWidth: "35em" }, children: "Invalidating removes whole recorded cycle events from active material reconstruction while retaining them in the event log." }), _jsx(InvalidateSelect, { st: props.st, setState: props.setState }), affectedLabels.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("p", { children: "All material recorded on these events will be affected:" }), _jsx("ul", { children: affectedLabels.map((material) => (_jsxs("li", { children: [material.serial || `Material ID ${material.materialId}`, material.queued ? " (currently in a queue)" : ""] }, material.materialId))) })] })) : null, props.st.error ? _jsx("p", { role: "alert", children: props.st.error }) : null] }) }));
|
|
118
155
|
}
|
|
119
156
|
export function InvalidateCycleDialogButton(props) {
|
|
120
157
|
const fmsInfo = useAtomValue(fmsInformation);
|
|
@@ -132,6 +169,8 @@ export function InvalidateCycleDialogButton(props) {
|
|
|
132
169
|
return null;
|
|
133
170
|
if (inProcMat && inProcMat.location.type === LocType.OnPallet)
|
|
134
171
|
return null;
|
|
172
|
+
if (inProcMat && inProcMat.location.type === LocType.InQueue)
|
|
173
|
+
return null;
|
|
135
174
|
const allowChange = possibleNew !== null &&
|
|
136
175
|
(!LazySeq.ofObject(possibleNew.possibleCastingsByQueue ?? {}).isEmpty() ||
|
|
137
176
|
!LazySeq.ofObject(possibleNew.possibleJobsByQueue ?? {}).isEmpty());
|
|
@@ -140,7 +179,13 @@ export function InvalidateCycleDialogButton(props) {
|
|
|
140
179
|
if (props.ignoreOperator)
|
|
141
180
|
operator = null;
|
|
142
181
|
function showInvalidate() {
|
|
143
|
-
props.setState({
|
|
182
|
+
props.setState({
|
|
183
|
+
process: null,
|
|
184
|
+
updating: false,
|
|
185
|
+
error: null,
|
|
186
|
+
changeRawMat: null,
|
|
187
|
+
changeJobUnique: null,
|
|
188
|
+
});
|
|
144
189
|
}
|
|
145
190
|
function invalidateCycle() {
|
|
146
191
|
if (curMat && (props.st?.process || props.st?.changeRawMat || props.st?.changeJobUnique)) {
|
|
@@ -152,7 +197,7 @@ export function InvalidateCycleDialogButton(props) {
|
|
|
152
197
|
type: "MatDetails",
|
|
153
198
|
details: mat,
|
|
154
199
|
});
|
|
155
|
-
props.
|
|
200
|
+
props.setState(null);
|
|
156
201
|
}
|
|
157
202
|
else {
|
|
158
203
|
setMatToShow(null);
|
|
@@ -160,9 +205,15 @@ export function InvalidateCycleDialogButton(props) {
|
|
|
160
205
|
}
|
|
161
206
|
})
|
|
162
207
|
.catch((e) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
208
|
+
props.setState({
|
|
209
|
+
...props.st,
|
|
210
|
+
updating: false,
|
|
211
|
+
error: ApiException.isApiException(e)
|
|
212
|
+
? e.response
|
|
213
|
+
: e instanceof Error
|
|
214
|
+
? e.message
|
|
215
|
+
: String(e),
|
|
216
|
+
});
|
|
166
217
|
});
|
|
167
218
|
}
|
|
168
219
|
}
|
|
@@ -51,6 +51,7 @@ import { fmsInformation } from "../../network/server-settings.js";
|
|
|
51
51
|
import { currentStatus, secondsSinceEpochAtom } from "../../cell-status/current-status.js";
|
|
52
52
|
import { useIsDemo, useSetTitle } from "../routes.js";
|
|
53
53
|
import { QuarantineMatButton } from "./QuarantineButton.js";
|
|
54
|
+
import { CancelLoadButton } from "./CancelLoadButton.js";
|
|
54
55
|
import { durationToSeconds } from "../../util/parseISODuration.js";
|
|
55
56
|
import { formatSeconds } from "./SystemOverview.js";
|
|
56
57
|
import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterialButtons, SwapMaterialDialogContent, } from "./InvalidateCycle.js";
|
|
@@ -540,6 +541,7 @@ function AddMatButton({ queues, onClose, toQueue, showAddToQueue, setShowAddToQu
|
|
|
540
541
|
const inProcMat = useAtomValue(matDetails.inProcessMaterialInDialog);
|
|
541
542
|
const operator = useAtomValue(currentOperator);
|
|
542
543
|
const [addExistingMat, addingExistingMat] = matDetails.useAddExistingMaterialToQueue();
|
|
544
|
+
const [addError, setAddError] = useState(null);
|
|
543
545
|
if (!existingMat ||
|
|
544
546
|
inProcMat?.location.type === api.LocType.OnPallet ||
|
|
545
547
|
inProcMat?.action.type === api.ActionType.Loading ||
|
|
@@ -557,16 +559,26 @@ function AddMatButton({ queues, onClose, toQueue, showAddToQueue, setShowAddToQu
|
|
|
557
559
|
return (_jsx(Button, { color: "primary", onClick: () => setShowAddToQueue(true), children: "Add To Queue" }));
|
|
558
560
|
}
|
|
559
561
|
else {
|
|
560
|
-
return (_jsxs(Button, { color: "primary", disabled: toQueue === null || addingExistingMat, onClick: () => {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
562
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Button, { color: "primary", disabled: toQueue === null || addingExistingMat, onClick: async () => {
|
|
563
|
+
setAddError(null);
|
|
564
|
+
try {
|
|
565
|
+
await addExistingMat({
|
|
566
|
+
materialId: existingMat.materialID,
|
|
567
|
+
queue: toQueue ?? "",
|
|
568
|
+
queuePosition: -1,
|
|
569
|
+
operator: operator,
|
|
570
|
+
});
|
|
571
|
+
setMatToShow(null);
|
|
572
|
+
onClose();
|
|
573
|
+
}
|
|
574
|
+
catch (e) {
|
|
575
|
+
setAddError(api.ApiException.isApiException(e)
|
|
576
|
+
? e.response
|
|
577
|
+
: e instanceof Error
|
|
578
|
+
? e.message
|
|
579
|
+
: String(e));
|
|
580
|
+
}
|
|
581
|
+
}, children: ["Add To ", toQueue ?? "Queue", " ", lastProcMat ? ` To Run Process ${lastProcMat.process + 1}` : ""] }), addError ? _jsx(Typography, { role: "alert", children: addError }) : null] }));
|
|
570
582
|
}
|
|
571
583
|
}
|
|
572
584
|
function AssignWorkorderButton() {
|
|
@@ -593,7 +605,7 @@ const LoadMatDialog = memo(function LoadMatDialog(props) {
|
|
|
593
605
|
setShowAddMaterial(false);
|
|
594
606
|
setSelectedQueue(null);
|
|
595
607
|
}, [setSwapSt, setInvalidateSt]);
|
|
596
|
-
return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(SwapMaterialDialogContent, { st: swapSt, setState: setSwapSt }), invalidateSt !== null ? (_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt })) : null, showAddMaterial ? (_jsx(PromptForQueue, { selectedQueue: selectedQueue, setSelectedQueue: setSelectedQueue, queueNames: props.queues })) : undefined] }), buttons: _jsxs(_Fragment, { children: [_jsx(InstructionButton, { pallet: props.pallet }), _jsx(PrintLabelButton, {}), _jsx(QuarantineMatButton, {}), _jsx(SignalInspectionButton, {}), _jsx(AddMatButton, { toQueue: selectedQueue, queues: props.queues, onClose: onClose, showAddToQueue: showAddMaterial, setShowAddToQueue: setShowAddMaterial }), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, loadStation: true }), _jsx(AssignWorkorderButton, {})] }) }));
|
|
608
|
+
return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(SwapMaterialDialogContent, { st: swapSt, setState: setSwapSt }), invalidateSt !== null ? (_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt })) : null, showAddMaterial ? (_jsx(PromptForQueue, { selectedQueue: selectedQueue, setSelectedQueue: setSelectedQueue, queueNames: props.queues })) : undefined] }), buttons: _jsxs(_Fragment, { children: [_jsx(InstructionButton, { pallet: props.pallet }), _jsx(PrintLabelButton, {}), _jsx(QuarantineMatButton, {}), _jsx(CancelLoadButton, { onClose: onClose }), _jsx(SignalInspectionButton, {}), _jsx(AddMatButton, { toQueue: selectedQueue, queues: props.queues, onClose: onClose, showAddToQueue: showAddMaterial, setShowAddToQueue: setShowAddMaterial }), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, loadStation: true }), _jsx(AssignWorkorderButton, {})] }) }));
|
|
597
609
|
});
|
|
598
610
|
function useGridLayout({ numMatCols, maxNumFaces, horizontal, showMatInCompleted, }) {
|
|
599
611
|
let rows = "";
|
|
@@ -235,14 +235,12 @@ export function MaterialAction({ mat, displayActionForSinglePallet, fsize, }) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
case api.ActionType.LoadingToBasket:
|
|
238
|
-
return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Load into ", basketName, " ", mat.action.loadToBasketId ?? "", mat.action.loadToBasketSlot !== undefined
|
|
239
|
-
? ` slot ${mat.action.loadToBasketSlot + 1}`
|
|
240
|
-
: ""] }));
|
|
238
|
+
return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Load into ", basketName, " ", mat.action.loadToBasketId ?? "", mat.action.loadToBasketSlot !== undefined ? ` slot ${mat.action.loadToBasketSlot}` : ""] }));
|
|
241
239
|
case api.ActionType.UnloadToInProcess:
|
|
242
240
|
case api.ActionType.UnloadToCompletedMaterial:
|
|
243
241
|
if (mat.action.unloadToBasketId) {
|
|
244
242
|
return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Unload to ", basketName, " ", mat.action.unloadToBasketId, mat.action.unloadToBasketSlot !== undefined
|
|
245
|
-
? ` slot ${mat.action.unloadToBasketSlot
|
|
243
|
+
? ` slot ${mat.action.unloadToBasketSlot}`
|
|
246
244
|
: ""] }));
|
|
247
245
|
}
|
|
248
246
|
else if (mat.action.unloadIntoQueue) {
|
|
@@ -37,7 +37,7 @@ import { LazySeq } from "@seedtactics/immutable-collections";
|
|
|
37
37
|
import { currentStatus } from "../../cell-status/current-status.js";
|
|
38
38
|
import { inProcessMaterialInDialog, materialDialogOpen, useRemoveFromQueue, useSignalForQuarantine, } from "../../cell-status/material-details.js";
|
|
39
39
|
import { currentOperator } from "../../data/operators.js";
|
|
40
|
-
import { ActionType,
|
|
40
|
+
import { ActionType, ApiException, LocType, QueueRole, } from "../../network/api.js";
|
|
41
41
|
import { fmsInformation } from "../../network/server-settings.js";
|
|
42
42
|
import { useAtomValue, useSetAtom } from "jotai";
|
|
43
43
|
function useQuarantineMaterial(ignoreOperator) {
|
|
@@ -70,75 +70,48 @@ function useQuarantineMaterial(ignoreOperator) {
|
|
|
70
70
|
const quarantineQueues = LazySeq.ofObject(curSt.queues)
|
|
71
71
|
.filter(([qname, _]) => !activeQueues.has(qname))
|
|
72
72
|
.toRSet(([qname, _]) => qname);
|
|
73
|
-
const palLoc = LazySeq.ofObject(curSt.pallets).toOrderedMap(([_, pal]) => [
|
|
74
|
-
pal.palletNum,
|
|
75
|
-
pal.currentPalletLocation,
|
|
76
|
-
]);
|
|
77
73
|
// If in a quarantine queue, allow removal from system
|
|
78
74
|
if (inProcMat.location.type === LocType.InQueue &&
|
|
79
75
|
inProcMat.location.currentQueue &&
|
|
80
76
|
quarantineQueues.has(inProcMat.location.currentQueue)) {
|
|
81
77
|
return {
|
|
82
78
|
type: "Remove",
|
|
79
|
+
material: inProcMat,
|
|
83
80
|
quarantine: () => removeFromQueue(inProcMat.materialID, operator),
|
|
84
81
|
removing: removingFromQueue,
|
|
85
82
|
quarantineQueueDestination: null,
|
|
83
|
+
removeFromQueues: null,
|
|
84
|
+
removingFromQueues: removingFromQueue,
|
|
86
85
|
};
|
|
87
86
|
}
|
|
88
87
|
let type = null;
|
|
89
88
|
switch (inProcMat.location.type) {
|
|
90
89
|
case LocType.OnPallet:
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
const palAtLoad = inProcMat.location.palletNum &&
|
|
94
|
-
palLoc.get(inProcMat.location.palletNum)?.loc === PalletLocationEnum.LoadUnload;
|
|
95
|
-
if (inProcMat.action.type === ActionType.Loading || palAtLoad) {
|
|
96
|
-
type = "CancelLoad";
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
type = "SignalForScrap";
|
|
100
|
-
}
|
|
90
|
+
if (inProcMat.action.type === ActionType.Loading) {
|
|
91
|
+
return null;
|
|
101
92
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!job)
|
|
110
|
-
return null;
|
|
111
|
-
const path = job.procsAndPaths?.[inProcMat.process - 1]?.paths?.[inProcMat.path - 1];
|
|
112
|
-
if (inProcMat.process != job.procsAndPaths.length && (!path || !path.outputQueue)) {
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
type = "SignalForScrap";
|
|
93
|
+
// Check that the job outputs to a queue, only then can signaling for quarantine work
|
|
94
|
+
const job = curSt.jobs[inProcMat.jobUnique];
|
|
95
|
+
if (!job)
|
|
96
|
+
return null;
|
|
97
|
+
const path = job.procsAndPaths?.[inProcMat.process - 1]?.paths?.[inProcMat.path - 1];
|
|
98
|
+
if (inProcMat.process != job.procsAndPaths.length && (!path || !path.outputQueue)) {
|
|
99
|
+
return null;
|
|
116
100
|
}
|
|
101
|
+
type = "SignalForScrap";
|
|
117
102
|
break;
|
|
118
103
|
case LocType.InQueue:
|
|
119
|
-
if (
|
|
120
|
-
inProcMat.action.type === ActionType.LoadingToBasket) &&
|
|
121
|
-
!fmsInfo.allowQuarantineToCancelLoad) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
else if (inProcMat.action.type === ActionType.Loading ||
|
|
104
|
+
if (inProcMat.action.type === ActionType.Loading ||
|
|
125
105
|
inProcMat.action.type === ActionType.LoadingToBasket) {
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
type = "Scrap";
|
|
106
|
+
return null;
|
|
130
107
|
}
|
|
108
|
+
type = "Scrap";
|
|
131
109
|
break;
|
|
132
110
|
case LocType.InBasket:
|
|
133
|
-
if (inProcMat.action.type === ActionType.Loading
|
|
111
|
+
if (inProcMat.action.type === ActionType.Loading) {
|
|
134
112
|
return null;
|
|
135
113
|
}
|
|
136
|
-
|
|
137
|
-
type = "CancelLoad";
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
type = "Scrap";
|
|
141
|
-
}
|
|
114
|
+
type = "Scrap";
|
|
142
115
|
break;
|
|
143
116
|
case LocType.Free:
|
|
144
117
|
type = "Scrap";
|
|
@@ -147,18 +120,51 @@ function useQuarantineMaterial(ignoreOperator) {
|
|
|
147
120
|
if (type) {
|
|
148
121
|
return {
|
|
149
122
|
type,
|
|
150
|
-
|
|
123
|
+
material: inProcMat,
|
|
124
|
+
quarantine: async (reason) => signalQuarantine(inProcMat.materialID, operator, reason),
|
|
151
125
|
removing: signalingQuarantine,
|
|
152
126
|
quarantineQueueDestination: quarantineQueue,
|
|
127
|
+
removeFromQueues: inProcMat.location.type === LocType.InQueue &&
|
|
128
|
+
inProcMat.location.currentQueue !== undefined &&
|
|
129
|
+
activeQueues.has(inProcMat.location.currentQueue) &&
|
|
130
|
+
inProcMat.action.type === ActionType.Waiting
|
|
131
|
+
? () => removeFromQueue(inProcMat.materialID, operator)
|
|
132
|
+
: null,
|
|
133
|
+
removingFromQueues: removingFromQueue,
|
|
153
134
|
};
|
|
154
135
|
}
|
|
155
136
|
else {
|
|
156
137
|
return null;
|
|
157
138
|
}
|
|
158
139
|
}
|
|
140
|
+
function RemoveFromQueuesButton({ material, removeFromQueues, removing, }) {
|
|
141
|
+
const [open, setOpen] = useState(false);
|
|
142
|
+
const [error, setError] = useState(null);
|
|
143
|
+
const setMatToShow = useSetAtom(materialDialogOpen);
|
|
144
|
+
async function remove() {
|
|
145
|
+
setError(null);
|
|
146
|
+
try {
|
|
147
|
+
await removeFromQueues();
|
|
148
|
+
setOpen(false);
|
|
149
|
+
setMatToShow({
|
|
150
|
+
type: "MatSummary",
|
|
151
|
+
summary: {
|
|
152
|
+
materialID: material.materialID,
|
|
153
|
+
partName: material.partName,
|
|
154
|
+
serial: material.serial,
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
setError(ApiException.isApiException(e) ? e.response : e instanceof Error ? e.message : String(e));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: "Remove from all queues", children: _jsx(Button, { color: "primary", disabled: removing, onClick: () => setOpen(true), children: "Remove from Queues" }) }), _jsxs(Dialog, { open: open, onClose: () => setOpen(false), children: [_jsx(DialogTitle, { children: "Remove Material from Queues" }), _jsxs(DialogContent, { children: [_jsx("p", { children: "The material will be removed from all queues." }), error ? _jsx("p", { role: "alert", children: error }) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { color: "primary", disabled: removing, onClick: remove, children: "Remove from Queues" }), _jsx(Button, { color: "secondary", disabled: removing, onClick: () => setOpen(false), children: "Cancel" })] })] })] }));
|
|
163
|
+
}
|
|
159
164
|
export function QuarantineMatButton({ onClose, ignoreOperator, }) {
|
|
160
165
|
const [open, setOpen] = useState(false);
|
|
161
166
|
const [reason, setReason] = useState("");
|
|
167
|
+
const [error, setError] = useState(null);
|
|
162
168
|
const q = useQuarantineMaterial(!!ignoreOperator);
|
|
163
169
|
const setMatToShow = useSetAtom(materialDialogOpen);
|
|
164
170
|
if (q === null)
|
|
@@ -182,19 +188,33 @@ export function QuarantineMatButton({ onClose, ignoreOperator, }) {
|
|
|
182
188
|
: "After unload, remove the part as scrap";
|
|
183
189
|
btnTxt = q.quarantineQueueDestination ? "Quarantine" : "Scrap";
|
|
184
190
|
break;
|
|
185
|
-
case "CancelLoad":
|
|
186
|
-
title = q.quarantineQueueDestination
|
|
187
|
-
? `Cancel load and move to ${q.quarantineQueueDestination}`
|
|
188
|
-
: "Cancel load";
|
|
189
|
-
btnTxt = "Cancel Load";
|
|
190
|
-
break;
|
|
191
191
|
}
|
|
192
|
-
function quarantine() {
|
|
193
|
-
q
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
async function quarantine() {
|
|
193
|
+
if (!q)
|
|
194
|
+
return;
|
|
195
|
+
setError(null);
|
|
196
|
+
try {
|
|
197
|
+
await q.quarantine(reason);
|
|
198
|
+
setOpen(false);
|
|
199
|
+
setReason("");
|
|
200
|
+
if (q.type === "Remove") {
|
|
201
|
+
setMatToShow({
|
|
202
|
+
type: "MatSummary",
|
|
203
|
+
summary: {
|
|
204
|
+
materialID: q.material.materialID,
|
|
205
|
+
partName: q.material.partName,
|
|
206
|
+
serial: q.material.serial,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
setMatToShow(null);
|
|
212
|
+
onClose?.();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
setError(ApiException.isApiException(e) ? e.response : e instanceof Error ? e.message : String(e));
|
|
217
|
+
}
|
|
198
218
|
}
|
|
199
|
-
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: title, children: _jsx(Button, { color: "primary", disabled: q.removing, onClick: () => setOpen(true), children: btnTxt }) }), _jsxs(Dialog, { open: open, onClose: () => setOpen(false), children: [_jsx(DialogTitle, { children: "Quarantine Material" }), _jsxs(DialogContent, { children: [_jsx("p", { children: title }), _jsx(TextField, { label: "Reason", value: reason, onChange: (e) => setReason(e.target.value), fullWidth: true, autoFocus: true, multiline: true })] }), _jsxs(DialogActions, { children: [_jsx(Button, { color: "primary", onClick: quarantine, children: btnTxt }), _jsx(Button, { color: "secondary", onClick: () => setOpen(false), children: "Cancel" })] })] })] }));
|
|
219
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: title, children: _jsx(Button, { color: "primary", disabled: q.removing, onClick: () => setOpen(true), children: btnTxt }) }), q.removeFromQueues ? (_jsx(RemoveFromQueuesButton, { material: q.material, removeFromQueues: q.removeFromQueues, removing: q.removingFromQueues })) : null, _jsxs(Dialog, { open: open, onClose: () => setOpen(false), children: [_jsx(DialogTitle, { children: "Quarantine Material" }), _jsxs(DialogContent, { children: [_jsx("p", { children: title }), _jsx(TextField, { label: "Reason", value: reason, onChange: (e) => setReason(e.target.value), fullWidth: true, autoFocus: true, multiline: true }), error ? _jsx("p", { role: "alert", children: error }) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { color: "primary", disabled: q.removing, onClick: quarantine, children: btnTxt }), _jsx(Button, { color: "secondary", onClick: () => setOpen(false), children: "Cancel" })] })] })] }));
|
|
200
220
|
}
|
|
@@ -69,6 +69,7 @@ import { materialDialogOpen } from "../../cell-status/material-details.js";
|
|
|
69
69
|
import { PrintLabelButton } from "./PrintedLabel.js";
|
|
70
70
|
import { AddToQueueButton, AddToQueueMaterialDialogCt, } from "./QueuesAddMaterial.js";
|
|
71
71
|
import { QuarantineMatButton } from "./QuarantineButton.js";
|
|
72
|
+
import { CancelLoadButton } from "./CancelLoadButton.js";
|
|
72
73
|
import { AddByBarcodeDialog, scanBarcodeToAddToQueueDialog } from "../BarcodeScanning.js";
|
|
73
74
|
import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, } from "./InvalidateCycle.js";
|
|
74
75
|
const JobTableRow = styled(TableRow, { shouldForwardProp: (prop) => prop.toString()[0] !== "$" })(({ $noBorderBottom, $highlightedRow, $noncompletedRow }) => ({
|
|
@@ -287,7 +288,7 @@ const QueuedMaterialDialog = memo(function QueuedMaterialDialog({ queueNames, })
|
|
|
287
288
|
setInvalidateSt(null);
|
|
288
289
|
}, []);
|
|
289
290
|
queueNames = usePossibleQueuesForAdd(queueNames);
|
|
290
|
-
return (_jsx(MaterialDialog, { allowNote: true, onClose: onClose, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt }), _jsx(AddToQueueMaterialDialogCt, { queueNames: queueNames, st: addMatSt, setState: setAddMatSt })] }), buttons: _jsxs(_Fragment, { children: [_jsx(PrintLabelButton, {}), _jsx(QuarantineMatButton, { onClose: onClose }), _jsx(InvalidateCycleDialogButton, { onClose: onClose, st: invalidateSt, setState: setInvalidateSt }), _jsx(AddToQueueButton, { st: addMatSt, queueNames: queueNames, onClose: onClose })] }) }));
|
|
291
|
+
return (_jsx(MaterialDialog, { allowNote: true, onClose: onClose, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt }), _jsx(AddToQueueMaterialDialogCt, { queueNames: queueNames, st: addMatSt, setState: setAddMatSt })] }), buttons: _jsxs(_Fragment, { children: [_jsx(PrintLabelButton, {}), _jsx(QuarantineMatButton, { onClose: onClose }), _jsx(CancelLoadButton, { onClose: onClose }), _jsx(InvalidateCycleDialogButton, { onClose: onClose, st: invalidateSt, setState: setInvalidateSt }), _jsx(AddToQueueButton, { st: addMatSt, queueNames: queueNames, onClose: onClose })] }) }));
|
|
291
292
|
});
|
|
292
293
|
export const Queues = (props) => {
|
|
293
294
|
const operator = useAtomValue(currentOperator);
|
|
@@ -183,6 +183,7 @@ export function AddToQueueButton({ st: { enteredOperator, newMaterialTy, toQueue
|
|
|
183
183
|
const [addExistingMat, addingExistingMat] = matDetails.useAddExistingMaterialToQueue();
|
|
184
184
|
const [addNewMat, addingNewMat] = matDetails.useAddNewMaterialToQueue();
|
|
185
185
|
const [addNewCasting, addingNewCasting] = useAddNewCastingToQueue();
|
|
186
|
+
const [addError, setAddError] = useState(null);
|
|
186
187
|
const allowAdd = useAllowAddToQueue(queueNames);
|
|
187
188
|
if (!allowAdd) {
|
|
188
189
|
return null;
|
|
@@ -213,52 +214,62 @@ export function AddToQueueButton({ st: { enteredOperator, newMaterialTy, toQueue
|
|
|
213
214
|
withSerialMsg = " With Serial " + newSerial;
|
|
214
215
|
}
|
|
215
216
|
const curQueue = inProcMat?.location.currentQueue ?? null;
|
|
216
|
-
return (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
217
|
+
return (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: toQueue === null
|
|
218
|
+
? "Select a queue to add the material to"
|
|
219
|
+
: fmsInfo.requireOperatorNamePromptWhenAddingMaterial &&
|
|
220
|
+
(enteredOperator === null || enteredOperator === "")
|
|
221
|
+
? "Please enter an operator name"
|
|
222
|
+
: "", children: _jsx("span", { children: _jsx(Button, { color: "primary", disabled: toQueue === null ||
|
|
223
|
+
addingExistingMat ||
|
|
224
|
+
addingNewMat ||
|
|
225
|
+
addingNewCasting ||
|
|
226
|
+
(existingMat === null && newMaterialTy === null) ||
|
|
227
|
+
(fmsInfo.requireOperatorNamePromptWhenAddingMaterial &&
|
|
228
|
+
(enteredOperator === null || enteredOperator === "")), onClick: async () => {
|
|
229
|
+
setAddError(null);
|
|
230
|
+
try {
|
|
231
|
+
if (existingMat) {
|
|
232
|
+
await addExistingMat({
|
|
233
|
+
materialId: existingMat.materialID,
|
|
234
|
+
queue: toQueue ?? "",
|
|
235
|
+
queuePosition: -1,
|
|
236
|
+
operator: enteredOperator ?? operator,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
else if (newMaterialTy &&
|
|
240
|
+
newMaterialTy.kind === "JobAndProc" &&
|
|
241
|
+
newMaterialTy.jobUnique) {
|
|
242
|
+
await addNewMat({
|
|
243
|
+
jobUnique: newMaterialTy.jobUnique,
|
|
244
|
+
lastCompletedProcess: newMaterialTy.last_proc,
|
|
245
|
+
serial: newSerial ?? undefined,
|
|
246
|
+
workorder: newWorkorder ?? newMaterialTy?.workorder,
|
|
247
|
+
queue: toQueue ?? "",
|
|
248
|
+
queuePosition: -1,
|
|
249
|
+
operator: enteredOperator ?? operator,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
else if (newMaterialTy &&
|
|
253
|
+
newMaterialTy.kind === "RawMat" &&
|
|
254
|
+
newMaterialTy.rawMatName) {
|
|
255
|
+
await addNewCasting({
|
|
256
|
+
casting: newMaterialTy.rawMatName,
|
|
257
|
+
quantity: 1,
|
|
258
|
+
queue: toQueue ?? "",
|
|
259
|
+
serials: newSerial ? [newSerial] : undefined,
|
|
260
|
+
workorder: newWorkorder,
|
|
261
|
+
operator: enteredOperator ?? operator,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
setMatToShow(null);
|
|
265
|
+
onClose();
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
setAddError(api.ApiException.isApiException(e)
|
|
269
|
+
? e.response
|
|
270
|
+
: e instanceof Error
|
|
271
|
+
? e.message
|
|
272
|
+
: String(e));
|
|
273
|
+
}
|
|
274
|
+
}, children: toQueue === null ? ("Add to Queue") : (_jsxs("span", { children: [curQueue !== null ? `Move From ${curQueue} To` : "Add To", " ", toQueue, withSerialMsg, addProcMsg] })) }) }) }), addError ? _jsx("p", { role: "alert", children: addError }) : null] }));
|
|
264
275
|
}
|
|
@@ -43,6 +43,7 @@ import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
|
|
|
43
43
|
import { addDays } from "date-fns";
|
|
44
44
|
import { durationToSeconds } from "../../util/parseISODuration.js";
|
|
45
45
|
import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterialButtons, SwapMaterialDialogContent, } from "./InvalidateCycle.js";
|
|
46
|
+
import { CancelLoadButton } from "./CancelLoadButton.js";
|
|
46
47
|
import { QuarantineMatButton } from "./QuarantineButton.js";
|
|
47
48
|
import { SelectInspTypeDialog, SignalInspectionButton } from "./SelectInspType.js";
|
|
48
49
|
import { useSetTitle } from "../routes.js";
|
|
@@ -446,7 +447,7 @@ function PalletFaces({ maxNumFaces, mats: allMats, loadingOntoPallet, noFilter,
|
|
|
446
447
|
}
|
|
447
448
|
}
|
|
448
449
|
function BasketContents({ mats }) {
|
|
449
|
-
const byPosition = LazySeq.of(mats).orderedGroupBy((m) =>
|
|
450
|
+
const byPosition = LazySeq.of(mats).orderedGroupBy((m) => m.location.basketSlot ?? 0);
|
|
450
451
|
return (_jsx(Box, { sx: {
|
|
451
452
|
display: "flex",
|
|
452
453
|
flexWrap: "wrap",
|
|
@@ -825,7 +826,7 @@ const SystemOverviewMaterialDialog = memo(function SystemOverviewMaterialDialog(
|
|
|
825
826
|
setSwapSt(null);
|
|
826
827
|
setInvalidateSt(null);
|
|
827
828
|
}
|
|
828
|
-
return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(SwapMaterialDialogContent, { st: swapSt, setState: setSwapSt }), invalidateSt !== null ? (_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt })) : null] }), buttons: _jsxs(_Fragment, { children: [_jsx(QuarantineMatButton, { ignoreOperator: ignoreOperator }), _jsx(SignalInspectionButton, {}), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose, ignoreOperator: ignoreOperator }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: ignoreOperator })] }) }));
|
|
829
|
+
return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [_jsx(SwapMaterialDialogContent, { st: swapSt, setState: setSwapSt }), invalidateSt !== null ? (_jsx(InvalidateCycleDialogContent, { st: invalidateSt, setState: setInvalidateSt })) : null] }), buttons: _jsxs(_Fragment, { children: [_jsx(QuarantineMatButton, { ignoreOperator: ignoreOperator }), _jsx(CancelLoadButton, { onClose: onClose, ignoreOperator: ignoreOperator }), _jsx(SignalInspectionButton, {}), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose, ignoreOperator: ignoreOperator }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: ignoreOperator })] }) }));
|
|
829
830
|
});
|
|
830
831
|
export function SystemOverviewPage({ ignoreOperator, whiteBackground, }) {
|
|
831
832
|
useSetTitle("System Overview");
|
|
@@ -58,12 +58,12 @@ export const SortableRegion = memo(function SortableRegion(props) {
|
|
|
58
58
|
const overMatId = over ? numericId(over.id) : null;
|
|
59
59
|
if (over && active.id !== over.id && activeMatId !== null && overMatId !== null) {
|
|
60
60
|
const overIdx = props.matIds.indexOf(overMatId);
|
|
61
|
-
addExistingMatToQueue({
|
|
61
|
+
void addExistingMatToQueue({
|
|
62
62
|
materialId: activeMatId,
|
|
63
63
|
queue: props.queueName,
|
|
64
64
|
queuePosition: overIdx,
|
|
65
65
|
operator: operator,
|
|
66
|
-
});
|
|
66
|
+
}).catch(console.error);
|
|
67
67
|
reorderQueuedMat({
|
|
68
68
|
queue: props.queueName,
|
|
69
69
|
matId: activeMatId,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AppProps } from "./components/App.js";
|
|
2
|
+
/**
|
|
3
|
+
* Starts one complete FMS Insight application with optional statically composed custom pages.
|
|
4
|
+
*/
|
|
5
|
+
export declare function bootstrapInsight(appProps?: AppProps, rootElement?: HTMLElement): Promise<void>;
|
|
6
|
+
export { customState } from "./cell-status/custom-state.js";
|
|
7
|
+
export type { AppProps };
|
|
8
|
+
export { defaultChooseModes } from "./components/ChooseMode.js";
|
|
9
|
+
export type { ChooseModeItem } from "./components/ChooseMode.js";
|
|
10
|
+
export { RouteLocation } from "./components/routes.js";
|
|
11
|
+
export { authenticatedFetch } from "./network/backend.js";
|