@seedtactics/insight-client 16.8.4-beta.10 → 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/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/operations/AllMaterial.js +4 -3
- 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/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 +2 -1
- package/dist/components/station-monitor/Whiteboard.js +2 -2
- package/dist/index.html +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/package.json +1 -1
- package/dist/assets/index-BB3Eqktr.js +0 -388
|
@@ -49,6 +49,7 @@ export declare const serialInMaterialDialog: Atom<Promise<string | null>>;
|
|
|
49
49
|
export declare const serialInMaterialDialogUnwrapped: Atom<string | null>;
|
|
50
50
|
export declare const serialInMaterialDialogState: Atom<AsyncAtomState<string | null>>;
|
|
51
51
|
export declare const workorderInMaterialDialog: Atom<Promise<string | null>>;
|
|
52
|
+
export declare const materialInDialogLocalEvents: Atom<readonly Readonly<ILogEntry>[]>;
|
|
52
53
|
export declare const materialInDialogEvents: Atom<readonly Readonly<ILogEntry>[]>;
|
|
53
54
|
export type LargestUsedProces = {
|
|
54
55
|
readonly process: number;
|
|
@@ -96,9 +97,12 @@ export interface PrintLabelData {
|
|
|
96
97
|
readonly proc: number;
|
|
97
98
|
}
|
|
98
99
|
export declare function usePrintLabel(): [(data: PrintLabelData) => void, boolean, boolean];
|
|
99
|
-
export declare function useRemoveFromQueue(): [
|
|
100
|
+
export declare function useRemoveFromQueue(): [
|
|
101
|
+
(matId: number, operator: string | null) => Promise<void>,
|
|
102
|
+
boolean
|
|
103
|
+
];
|
|
100
104
|
export declare function useSignalForQuarantine(): [
|
|
101
|
-
(matId: number, operator: string | null, reason: string) => void
|
|
105
|
+
(matId: number, operator: string | null, reason: string) => Promise<void>,
|
|
102
106
|
boolean
|
|
103
107
|
];
|
|
104
108
|
export interface AddExistingMaterialToQueueData {
|
|
@@ -108,7 +112,7 @@ export interface AddExistingMaterialToQueueData {
|
|
|
108
112
|
readonly operator: string | null;
|
|
109
113
|
}
|
|
110
114
|
export declare function useAddExistingMaterialToQueue(): [
|
|
111
|
-
(d: AddExistingMaterialToQueueData) => void
|
|
115
|
+
(d: AddExistingMaterialToQueueData) => Promise<void>,
|
|
112
116
|
boolean
|
|
113
117
|
];
|
|
114
118
|
export interface AddNewMaterialToQueueData {
|
|
@@ -122,7 +126,10 @@ export interface AddNewMaterialToQueueData {
|
|
|
122
126
|
readonly onNewMaterial?: (mat: Readonly<IInProcessMaterial>) => void;
|
|
123
127
|
readonly onError?: (reason: unknown) => void;
|
|
124
128
|
}
|
|
125
|
-
export declare function useAddNewMaterialToQueue(): [
|
|
129
|
+
export declare function useAddNewMaterialToQueue(): [
|
|
130
|
+
(d: AddNewMaterialToQueueData) => Promise<Readonly<IInProcessMaterial>>,
|
|
131
|
+
boolean
|
|
132
|
+
];
|
|
126
133
|
export interface AddNewCastingToQueueData {
|
|
127
134
|
readonly casting: string;
|
|
128
135
|
readonly quantity: number;
|
|
@@ -133,4 +140,7 @@ export interface AddNewCastingToQueueData {
|
|
|
133
140
|
readonly onNewMaterial?: (mats: ReadonlyArray<Readonly<IInProcessMaterial>>) => void;
|
|
134
141
|
readonly onError?: (reason: unknown) => void;
|
|
135
142
|
}
|
|
136
|
-
export declare function useAddNewCastingToQueue(): [
|
|
143
|
+
export declare function useAddNewCastingToQueue(): [
|
|
144
|
+
(d: AddNewCastingToQueueData) => Promise<ReadonlyArray<Readonly<IInProcessMaterial>>>,
|
|
145
|
+
boolean
|
|
146
|
+
];
|
|
@@ -121,8 +121,9 @@ export const inProcessMaterialInDialog = atom(async (get) => {
|
|
|
121
121
|
const toShow = get(matToShow);
|
|
122
122
|
if (toShow === null)
|
|
123
123
|
return null;
|
|
124
|
-
if (toShow.type === "InProcMat")
|
|
125
|
-
return toShow.inproc;
|
|
124
|
+
if (toShow.type === "InProcMat") {
|
|
125
|
+
return status.material.find((m) => m.materialID === toShow.inproc.materialID) ?? null;
|
|
126
|
+
}
|
|
126
127
|
const matId = (await get(materialInDialogInfo))?.materialID ?? null;
|
|
127
128
|
return matId !== null && matId >= 0
|
|
128
129
|
? (status.material.find((m) => m.materialID === matId) ?? null)
|
|
@@ -210,6 +211,9 @@ const otherMatEvents = atom(async (get, { signal }) => {
|
|
|
210
211
|
return evts;
|
|
211
212
|
});
|
|
212
213
|
const otherMatEventsUnwrapped = unwrap(otherMatEvents, (prev) => prev ?? []);
|
|
214
|
+
export const materialInDialogLocalEvents = atom((get) => {
|
|
215
|
+
return LazySeq.of(get(localMatEventsUnwrapped)).concat(get(extraLogEventsFromUpdates)).toRArray();
|
|
216
|
+
});
|
|
213
217
|
export const materialInDialogEvents = atom((get) => {
|
|
214
218
|
const evtsFromUpdate = get(extraLogEventsFromUpdates);
|
|
215
219
|
return LazySeq.of(get(localMatEventsUnwrapped))
|
|
@@ -373,66 +377,83 @@ export function usePrintLabel() {
|
|
|
373
377
|
}
|
|
374
378
|
export function useRemoveFromQueue() {
|
|
375
379
|
const [updating, setUpdating] = useState(false);
|
|
376
|
-
const callback = useCallback((matId, operator) => {
|
|
380
|
+
const callback = useCallback(async (matId, operator) => {
|
|
377
381
|
setUpdating(true);
|
|
378
|
-
|
|
379
|
-
.
|
|
380
|
-
|
|
382
|
+
try {
|
|
383
|
+
await JobsBackend.removeMaterialFromAllQueues(matId, operator ?? undefined);
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
setUpdating(false);
|
|
387
|
+
}
|
|
381
388
|
}, []);
|
|
382
389
|
return [callback, updating];
|
|
383
390
|
}
|
|
384
391
|
export function useSignalForQuarantine() {
|
|
385
392
|
const [updating, setUpdating] = useState(false);
|
|
386
|
-
const callback = useCallback((matId, operator, reason) => {
|
|
393
|
+
const callback = useCallback(async (matId, operator, reason) => {
|
|
387
394
|
setUpdating(true);
|
|
388
|
-
|
|
389
|
-
.
|
|
390
|
-
|
|
395
|
+
try {
|
|
396
|
+
await JobsBackend.signalMaterialForQuarantine(matId, operator, reason === "" ? undefined : reason);
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
setUpdating(false);
|
|
400
|
+
}
|
|
391
401
|
}, []);
|
|
392
402
|
return [callback, updating];
|
|
393
403
|
}
|
|
394
404
|
export function useAddExistingMaterialToQueue() {
|
|
395
405
|
const [updating, setUpdating] = useState(false);
|
|
396
|
-
const callback = useCallback((d) => {
|
|
406
|
+
const callback = useCallback(async (d) => {
|
|
397
407
|
setUpdating(true);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
408
|
+
try {
|
|
409
|
+
await JobsBackend.setMaterialInQueue(d.materialId, d.operator, new QueuePosition({
|
|
410
|
+
queue: d.queue,
|
|
411
|
+
position: d.queuePosition,
|
|
412
|
+
}));
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
setUpdating(false);
|
|
416
|
+
}
|
|
404
417
|
}, []);
|
|
405
418
|
return [callback, updating];
|
|
406
419
|
}
|
|
407
420
|
export function useAddNewMaterialToQueue() {
|
|
408
421
|
const [updating, setUpdating] = useState(false);
|
|
409
|
-
const callback = useCallback((d) => {
|
|
422
|
+
const callback = useCallback(async (d) => {
|
|
410
423
|
setUpdating(true);
|
|
411
|
-
|
|
412
|
-
.
|
|
413
|
-
if (
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
424
|
+
try {
|
|
425
|
+
const material = await JobsBackend.addUnprocessedMaterialToQueue(d.jobUnique, d.lastCompletedProcess, d.queue, d.queuePosition, d.operator, d.workorder, d.serial || "");
|
|
426
|
+
if (material === undefined)
|
|
427
|
+
throw new Error("No material returned");
|
|
428
|
+
d.onNewMaterial?.(material);
|
|
429
|
+
return material;
|
|
430
|
+
}
|
|
431
|
+
catch (e) {
|
|
432
|
+
d.onError?.(e);
|
|
433
|
+
throw e;
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
setUpdating(false);
|
|
437
|
+
}
|
|
422
438
|
}, []);
|
|
423
439
|
return [callback, updating];
|
|
424
440
|
}
|
|
425
441
|
export function useAddNewCastingToQueue() {
|
|
426
442
|
const [updating, setUpdating] = useState(false);
|
|
427
|
-
const callback = useCallback((d) => {
|
|
443
|
+
const callback = useCallback(async (d) => {
|
|
428
444
|
setUpdating(true);
|
|
429
|
-
|
|
430
|
-
.
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
.
|
|
445
|
+
try {
|
|
446
|
+
const material = await JobsBackend.addUnallocatedCastingToQueue(d.casting, d.queue, d.quantity, d.operator, d.workorder, [...(d.serials || [])]);
|
|
447
|
+
d.onNewMaterial?.(material);
|
|
448
|
+
return material;
|
|
449
|
+
}
|
|
450
|
+
catch (e) {
|
|
451
|
+
d.onError?.(e);
|
|
452
|
+
throw e;
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
setUpdating(false);
|
|
456
|
+
}
|
|
436
457
|
}, []);
|
|
437
458
|
return [callback, updating];
|
|
438
459
|
}
|
|
@@ -43,6 +43,7 @@ import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterial
|
|
|
43
43
|
import { horizontalListSortingStrategy, SortableContext, useSortable, verticalListSortingStrategy, } from "@dnd-kit/sortable";
|
|
44
44
|
import { closestCenter, DndContext, DragOverlay, getFirstCollision, MeasuringStrategy, pointerWithin, rectIntersection, } from "@dnd-kit/core";
|
|
45
45
|
import { QuarantineMatButton } from "../station-monitor/QuarantineButton.js";
|
|
46
|
+
import { CancelLoadButton } from "../station-monitor/CancelLoadButton.js";
|
|
46
47
|
import { useSetTitle } from "../routes.js";
|
|
47
48
|
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
48
49
|
import { fmsInformation } from "../../network/server-settings.js";
|
|
@@ -152,7 +153,7 @@ const AllMatDialog = memo(function AllMatDialog() {
|
|
|
152
153
|
setSwapSt(null);
|
|
153
154
|
setInvalidateSt(null);
|
|
154
155
|
}
|
|
155
|
-
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, { onClose: onClose, ignoreOperator: true }), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose, ignoreOperator: true }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: true })] }) }));
|
|
156
|
+
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, { onClose: onClose, ignoreOperator: true }), _jsx(CancelLoadButton, { onClose: onClose, ignoreOperator: true }), _jsx(SwapMaterialButtons, { st: swapSt, setState: setSwapSt, onClose: onClose, ignoreOperator: true }), _jsx(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: true })] }) }));
|
|
156
157
|
});
|
|
157
158
|
function useCollisionDetection(allBins) {
|
|
158
159
|
return useCallback((args) => {
|
|
@@ -260,12 +261,12 @@ export function AllMaterial(props) {
|
|
|
260
261
|
? findQueueInQuarantineQueues(over.id, allBins)
|
|
261
262
|
: findMaterialInQuarantineQueues(over.id, allBins);
|
|
262
263
|
if (overCol) {
|
|
263
|
-
addExistingMatToQueue({
|
|
264
|
+
void addExistingMatToQueue({
|
|
264
265
|
materialId: activeDrag.mat.materialID,
|
|
265
266
|
queue: overCol.bin.queueName,
|
|
266
267
|
queuePosition: overCol.idx,
|
|
267
268
|
operator: null,
|
|
268
|
-
});
|
|
269
|
+
}).catch(console.error);
|
|
269
270
|
reorderQueuedMat({
|
|
270
271
|
queue: overCol.bin.queueName,
|
|
271
272
|
matId: activeDrag.mat.materialID,
|
|
@@ -122,20 +122,20 @@ export const BulkAddCastingWithoutSerialDialog = memo(function BulkAddCastingWit
|
|
|
122
122
|
enteredQty !== null &&
|
|
123
123
|
!isNaN(enteredQty) &&
|
|
124
124
|
enteredQty > 0) {
|
|
125
|
-
addNewCasting({
|
|
125
|
+
void addNewCasting({
|
|
126
126
|
casting: selectedCasting,
|
|
127
127
|
quantity: enteredQty,
|
|
128
128
|
queue: queue,
|
|
129
129
|
workorder: null,
|
|
130
130
|
operator: fmsInfo.requireOperatorNamePromptWhenAddingMaterial ? enteredOperator : operator,
|
|
131
|
-
});
|
|
131
|
+
}).catch(console.log);
|
|
132
132
|
}
|
|
133
133
|
close();
|
|
134
134
|
}
|
|
135
135
|
function addAndPrint() {
|
|
136
136
|
if (queue !== null && selectedCasting !== null && enteredQty !== null && !isNaN(enteredQty)) {
|
|
137
137
|
setAdding(true);
|
|
138
|
-
addNewCasting({
|
|
138
|
+
void addNewCasting({
|
|
139
139
|
casting: selectedCasting,
|
|
140
140
|
quantity: enteredQty,
|
|
141
141
|
queue: queue,
|
|
@@ -154,7 +154,7 @@ export const BulkAddCastingWithoutSerialDialog = memo(function BulkAddCastingWit
|
|
|
154
154
|
onError: () => {
|
|
155
155
|
close();
|
|
156
156
|
},
|
|
157
|
-
});
|
|
157
|
+
}).catch(() => { });
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
return (_jsxs(_Fragment, { children: [_jsxs(Dialog, { open: queue !== null, onClose: () => close(), maxWidth: "md", children: [_jsx(DialogTitle, { children: "Add Raw Material" }), _jsx(DialogContent, { children: _jsxs(Stack, { direction: "column", spacing: 2, sx: {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField, Tooltip, } from "@mui/material";
|
|
3
|
+
import { useAtomValue, useSetAtom } from "jotai";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
6
|
+
import { currentStatus } from "../../cell-status/current-status.js";
|
|
7
|
+
import { inProcessMaterialInDialog, materialDialogOpen, } from "../../cell-status/material-details.js";
|
|
8
|
+
import { currentOperator } from "../../data/operators.js";
|
|
9
|
+
import { JobsBackend } from "../../network/backend.js";
|
|
10
|
+
import { ApiException, CancelLoadRequest } from "../../network/api.js";
|
|
11
|
+
export function CancelLoadButton({ onClose, ignoreOperator = false, }) {
|
|
12
|
+
const material = useAtomValue(inProcessMaterialInDialog);
|
|
13
|
+
const status = useAtomValue(currentStatus);
|
|
14
|
+
const operator = useAtomValue(currentOperator);
|
|
15
|
+
const setMaterialDialogOpen = useSetAtom(materialDialogOpen);
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
17
|
+
const [reason, setReason] = useState("");
|
|
18
|
+
const [updating, setUpdating] = useState(false);
|
|
19
|
+
const [error, setError] = useState(null);
|
|
20
|
+
const [snapshot, setSnapshot] = useState(null);
|
|
21
|
+
const cancellationId = material?.action.loadCancellationId ?? null;
|
|
22
|
+
const currentSnapshot = material === null || cancellationId === null
|
|
23
|
+
? null
|
|
24
|
+
: {
|
|
25
|
+
material,
|
|
26
|
+
cancellationId,
|
|
27
|
+
group: LazySeq.of(status.material)
|
|
28
|
+
.filter((candidate) => candidate.action.loadCancellationId === cancellationId)
|
|
29
|
+
.toRArray(),
|
|
30
|
+
};
|
|
31
|
+
if (currentSnapshot === null && snapshot === null)
|
|
32
|
+
return null;
|
|
33
|
+
async function cancelLoad() {
|
|
34
|
+
if (snapshot === null)
|
|
35
|
+
return;
|
|
36
|
+
setUpdating(true);
|
|
37
|
+
setError(null);
|
|
38
|
+
try {
|
|
39
|
+
await JobsBackend.cancelLoad(snapshot.material.materialID, ignoreOperator ? null : operator, new CancelLoadRequest({
|
|
40
|
+
expectedLoadCancellationId: snapshot.cancellationId,
|
|
41
|
+
reason: reason || undefined,
|
|
42
|
+
}));
|
|
43
|
+
setMaterialDialogOpen(null);
|
|
44
|
+
onClose?.();
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
setError(ApiException.isApiException(e) ? e.response : e instanceof Error ? e.message : String(e));
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
setUpdating(false);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return (_jsxs(_Fragment, { children: [currentSnapshot ? (_jsx(Tooltip, { title: "Cancel the displayed load instruction", children: _jsx(Button, { color: "primary", disabled: updating, onClick: () => {
|
|
54
|
+
setSnapshot(currentSnapshot);
|
|
55
|
+
setReason("");
|
|
56
|
+
setError(null);
|
|
57
|
+
setOpen(true);
|
|
58
|
+
}, children: "Cancel Load" }) })) : null, _jsxs(Dialog, { open: open && snapshot !== null, onClose: () => setOpen(false), children: [_jsx(DialogTitle, { children: "Cancel Load" }), _jsxs(DialogContent, { children: [_jsx("p", { children: "The displayed load instruction will be cancelled and recalculated for:" }), _jsx("ul", { children: snapshot?.group.map((candidate) => (_jsx("li", { children: candidate.serial || `Material ID ${candidate.materialID}` }, candidate.materialID))) }), _jsx(TextField, { label: "Reason (optional)", value: reason, onChange: (e) => setReason(e.target.value), fullWidth: true, multiline: true }), error ? _jsx("p", { role: "alert", children: error }) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { color: "primary", disabled: updating, onClick: cancelLoad, children: "Cancel Load" }), _jsx(Button, { color: "secondary", disabled: updating, onClick: () => setOpen(false), children: "Keep Load" })] })] })] }));
|
|
59
|
+
}
|
|
@@ -44,6 +44,7 @@ import { materialDialogOpen, materialInDialogInfo, materialInDialogLargestUsedPr
|
|
|
44
44
|
import { last30MaterialSummary, } from "../../cell-status/material-summary.js";
|
|
45
45
|
import { instructionUrl } from "../../network/backend.js";
|
|
46
46
|
import { QuarantineMatButton } from "./QuarantineButton.js";
|
|
47
|
+
import { CancelLoadButton } from "./CancelLoadButton.js";
|
|
47
48
|
import { useIsDemo, useSetTitle } from "../routes.js";
|
|
48
49
|
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
49
50
|
function CompleteButton() {
|
|
@@ -108,7 +109,7 @@ function AssignWorkorderButton() {
|
|
|
108
109
|
return (_jsx(Button, { color: "primary", onClick: () => setWorkorderDialogOpen(true), children: "Assign Workorder" }));
|
|
109
110
|
}
|
|
110
111
|
const CloseoutMaterialDialog = memo(function CloseoutDialog() {
|
|
111
|
-
return (_jsx(MaterialDialog, { allowNote: true, buttons: _jsxs(_Fragment, { children: [_jsx(InstrButton, {}), _jsx(QuarantineMatButton, {}), _jsx(AssignWorkorderButton, {}), _jsx(CompleteButton, {})] }) }));
|
|
112
|
+
return (_jsx(MaterialDialog, { allowNote: true, buttons: _jsxs(_Fragment, { children: [_jsx(InstrButton, {}), _jsx(QuarantineMatButton, {}), _jsx(CancelLoadButton, {}), _jsx(AssignWorkorderButton, {}), _jsx(CompleteButton, {})] }) }));
|
|
112
113
|
});
|
|
113
114
|
const currentNearestMinutes = atom(new Date());
|
|
114
115
|
currentNearestMinutes.onMount = (set) => {
|
|
@@ -43,6 +43,7 @@ import { last30MaterialSummary } from "../../cell-status/material-summary.js";
|
|
|
43
43
|
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
44
44
|
import { instructionUrl } from "../../network/backend.js";
|
|
45
45
|
import { QuarantineMatButton } from "./QuarantineButton.js";
|
|
46
|
+
import { CancelLoadButton } from "./CancelLoadButton.js";
|
|
46
47
|
import { useIsDemo, useSetTitle } from "../routes.js";
|
|
47
48
|
import { useAtomValue, useSetAtom } from "jotai";
|
|
48
49
|
function InspButtons(props) {
|
|
@@ -67,7 +68,7 @@ function InspButtons(props) {
|
|
|
67
68
|
setMatToShow(null);
|
|
68
69
|
}
|
|
69
70
|
const url = instructionUrl(material.partName, props.inspection_type, material.materialID, null, maxProc, operator);
|
|
70
|
-
return (_jsxs(_Fragment, { children: [material.partName !== "" ? (demo ? (_jsx(Button, { color: "primary", children: "Instructions" })) : (_jsx(Button, { href: url, target: "bms-instructions", color: "primary", children: "Instructions" }))) : undefined, _jsx(QuarantineMatButton, {}), _jsxs(Button, { color: "primary", disabled: completeInspUpdating, onClick: () => markInspComplete(true), children: ["Mark ", props.inspection_type, " Success"] }), _jsxs(Button, { color: "primary", disabled: completeInspUpdating, onClick: () => markInspComplete(false), children: ["Mark ", props.inspection_type, " Failed"] })] }));
|
|
71
|
+
return (_jsxs(_Fragment, { children: [material.partName !== "" ? (demo ? (_jsx(Button, { color: "primary", children: "Instructions" })) : (_jsx(Button, { href: url, target: "bms-instructions", color: "primary", children: "Instructions" }))) : undefined, _jsx(QuarantineMatButton, {}), _jsx(CancelLoadButton, {}), _jsxs(Button, { color: "primary", disabled: completeInspUpdating, onClick: () => markInspComplete(true), children: ["Mark ", props.inspection_type, " Success"] }), _jsxs(Button, { color: "primary", disabled: completeInspUpdating, onClick: () => markInspComplete(false), children: ["Mark ", props.inspection_type, " Failed"] })] }));
|
|
71
72
|
}
|
|
72
73
|
function DialogBodyInspButtons({ focusInspectionType }) {
|
|
73
74
|
const material = useAtomValue(matDetails.materialInDialogInspections);
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { IInProcessMaterial } from "../../network/api.js";
|
|
1
|
+
import { IInProcessMaterial, ILogEntry } from "../../network/api.js";
|
|
2
|
+
import { HashMap } from "@seedtactics/immutable-collections";
|
|
2
3
|
import { ReactNode } from "react";
|
|
3
4
|
export type InvalidateCycleState = {
|
|
4
5
|
readonly process: number | null;
|
|
5
6
|
readonly changeRawMat: string | null;
|
|
6
7
|
readonly changeJobUnique: string | null;
|
|
7
8
|
readonly updating: boolean;
|
|
9
|
+
readonly error: string | null;
|
|
8
10
|
};
|
|
9
11
|
export type InvalidateCycleProps = {
|
|
10
12
|
readonly st: InvalidateCycleState | null;
|
|
11
13
|
readonly setState: (s: InvalidateCycleState | null) => void;
|
|
12
14
|
};
|
|
15
|
+
export declare function affectedMaterialForInvalidation(events: ReadonlyArray<Readonly<ILogEntry>>, materialId: number, process: number | null): HashMap<number, string | null>;
|
|
13
16
|
export declare function InvalidateCycleDialogContent(props: InvalidateCycleProps): import("react").JSX.Element;
|
|
14
17
|
export declare function InvalidateCycleDialogButton(props: InvalidateCycleProps & {
|
|
15
18
|
readonly onClose: () => void;
|
|
@@ -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 = "";
|