@seedtactics/insight-client 16.8.4-beta.8 → 17.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/assets/index-BkKYqUM0.js +388 -0
- package/dist/cell-status/material-details.d.ts +19 -5
- package/dist/cell-status/material-details.js +71 -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/station-monitor/BasketLoadStationWork.js +12 -8
- 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 +60 -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 +104 -38
- package/dist/components/station-monitor/LoadStation.js +25 -15
- package/dist/components/station-monitor/Material.js +14 -1
- package/dist/components/station-monitor/QuarantineButton.js +160 -90
- package/dist/components/station-monitor/Queues.js +2 -1
- package/dist/components/station-monitor/QueuesAddMaterial.js +65 -57
- package/dist/components/station-monitor/SystemOverview.js +2 -1
- package/dist/components/station-monitor/Whiteboard.js +2 -2
- package/dist/data/material-operation-policy.d.ts +21 -0
- package/dist/data/material-operation-policy.js +89 -0
- 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 +20 -4
- package/dist/network/api.js +163 -2
- package/dist/network/backend-mock.js +6 -0
- package/dist/network/backend.d.ts +2 -0
- package/dist/network/backend.js +2 -1
- package/package.json +12 -11
- package/dist/assets/index-DHusyIyb.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
|
@@ -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,16 @@ 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>,
|
|
106
|
+
boolean
|
|
107
|
+
];
|
|
108
|
+
export declare function useQuarantineQueuedMaterial(): [
|
|
109
|
+
(matId: number, operator: string | null, reason: string) => Promise<void>,
|
|
102
110
|
boolean
|
|
103
111
|
];
|
|
104
112
|
export interface AddExistingMaterialToQueueData {
|
|
@@ -108,7 +116,7 @@ export interface AddExistingMaterialToQueueData {
|
|
|
108
116
|
readonly operator: string | null;
|
|
109
117
|
}
|
|
110
118
|
export declare function useAddExistingMaterialToQueue(): [
|
|
111
|
-
(d: AddExistingMaterialToQueueData) => void
|
|
119
|
+
(d: AddExistingMaterialToQueueData) => Promise<void>,
|
|
112
120
|
boolean
|
|
113
121
|
];
|
|
114
122
|
export interface AddNewMaterialToQueueData {
|
|
@@ -122,7 +130,10 @@ export interface AddNewMaterialToQueueData {
|
|
|
122
130
|
readonly onNewMaterial?: (mat: Readonly<IInProcessMaterial>) => void;
|
|
123
131
|
readonly onError?: (reason: unknown) => void;
|
|
124
132
|
}
|
|
125
|
-
export declare function useAddNewMaterialToQueue(): [
|
|
133
|
+
export declare function useAddNewMaterialToQueue(): [
|
|
134
|
+
(d: AddNewMaterialToQueueData) => Promise<Readonly<IInProcessMaterial>>,
|
|
135
|
+
boolean
|
|
136
|
+
];
|
|
126
137
|
export interface AddNewCastingToQueueData {
|
|
127
138
|
readonly casting: string;
|
|
128
139
|
readonly quantity: number;
|
|
@@ -133,4 +144,7 @@ export interface AddNewCastingToQueueData {
|
|
|
133
144
|
readonly onNewMaterial?: (mats: ReadonlyArray<Readonly<IInProcessMaterial>>) => void;
|
|
134
145
|
readonly onError?: (reason: unknown) => void;
|
|
135
146
|
}
|
|
136
|
-
export declare function useAddNewCastingToQueue(): [
|
|
147
|
+
export declare function useAddNewCastingToQueue(): [
|
|
148
|
+
(d: AddNewCastingToQueueData) => Promise<ReadonlyArray<Readonly<IInProcessMaterial>>>,
|
|
149
|
+
boolean
|
|
150
|
+
];
|
|
@@ -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,96 @@ 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
|
+
}
|
|
401
|
+
}, []);
|
|
402
|
+
return [callback, updating];
|
|
403
|
+
}
|
|
404
|
+
export function useQuarantineQueuedMaterial() {
|
|
405
|
+
const [updating, setUpdating] = useState(false);
|
|
406
|
+
const callback = useCallback(async (matId, operator, reason) => {
|
|
407
|
+
setUpdating(true);
|
|
408
|
+
try {
|
|
409
|
+
await JobsBackend.quarantineQueuedMaterial(matId, operator, reason === "" ? undefined : reason);
|
|
410
|
+
}
|
|
411
|
+
finally {
|
|
412
|
+
setUpdating(false);
|
|
413
|
+
}
|
|
391
414
|
}, []);
|
|
392
415
|
return [callback, updating];
|
|
393
416
|
}
|
|
394
417
|
export function useAddExistingMaterialToQueue() {
|
|
395
418
|
const [updating, setUpdating] = useState(false);
|
|
396
|
-
const callback = useCallback((d) => {
|
|
419
|
+
const callback = useCallback(async (d) => {
|
|
397
420
|
setUpdating(true);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
421
|
+
try {
|
|
422
|
+
await JobsBackend.setMaterialInQueue(d.materialId, d.operator, new QueuePosition({
|
|
423
|
+
queue: d.queue,
|
|
424
|
+
position: d.queuePosition,
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
finally {
|
|
428
|
+
setUpdating(false);
|
|
429
|
+
}
|
|
404
430
|
}, []);
|
|
405
431
|
return [callback, updating];
|
|
406
432
|
}
|
|
407
433
|
export function useAddNewMaterialToQueue() {
|
|
408
434
|
const [updating, setUpdating] = useState(false);
|
|
409
|
-
const callback = useCallback((d) => {
|
|
435
|
+
const callback = useCallback(async (d) => {
|
|
410
436
|
setUpdating(true);
|
|
411
|
-
|
|
412
|
-
.
|
|
413
|
-
if (
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
437
|
+
try {
|
|
438
|
+
const material = await JobsBackend.addUnprocessedMaterialToQueue(d.jobUnique, d.lastCompletedProcess, d.queue, d.queuePosition, d.operator, d.workorder, d.serial || "");
|
|
439
|
+
if (material === undefined)
|
|
440
|
+
throw new Error("No material returned");
|
|
441
|
+
d.onNewMaterial?.(material);
|
|
442
|
+
return material;
|
|
443
|
+
}
|
|
444
|
+
catch (e) {
|
|
445
|
+
d.onError?.(e);
|
|
446
|
+
throw e;
|
|
447
|
+
}
|
|
448
|
+
finally {
|
|
449
|
+
setUpdating(false);
|
|
450
|
+
}
|
|
422
451
|
}, []);
|
|
423
452
|
return [callback, updating];
|
|
424
453
|
}
|
|
425
454
|
export function useAddNewCastingToQueue() {
|
|
426
455
|
const [updating, setUpdating] = useState(false);
|
|
427
|
-
const callback = useCallback((d) => {
|
|
456
|
+
const callback = useCallback(async (d) => {
|
|
428
457
|
setUpdating(true);
|
|
429
|
-
|
|
430
|
-
.
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
.
|
|
458
|
+
try {
|
|
459
|
+
const material = await JobsBackend.addUnallocatedCastingToQueue(d.casting, d.queue, d.quantity, d.operator, d.workorder, [...(d.serials || [])]);
|
|
460
|
+
d.onNewMaterial?.(material);
|
|
461
|
+
return material;
|
|
462
|
+
}
|
|
463
|
+
catch (e) {
|
|
464
|
+
d.onError?.(e);
|
|
465
|
+
throw e;
|
|
466
|
+
}
|
|
467
|
+
finally {
|
|
468
|
+
setUpdating(false);
|
|
469
|
+
}
|
|
436
470
|
}, []);
|
|
437
471
|
return [callback, updating];
|
|
438
472
|
}
|
|
@@ -48,7 +48,7 @@ import { useAtomValue } from "jotai";
|
|
|
48
48
|
import { fmsInformation } from "../network/server-settings.js";
|
|
49
49
|
import { basketDisplayName, loadStationDisplayName } from "../cell-status/station-cycles.js";
|
|
50
50
|
import { filterRemoveAddQueue } from "./log-entry-queue-filter.js";
|
|
51
|
-
import { basketContainerName } from "./log-entry-container-name.js";
|
|
51
|
+
import { basketContainerName, basketCycleDescription } from "./log-entry-container-name.js";
|
|
52
52
|
const ColoredSpan = styled("span", { shouldForwardProp: (prop) => prop.toString()[0] !== "$" })(({ $type }) => {
|
|
53
53
|
switch ($type) {
|
|
54
54
|
case "machine":
|
|
@@ -191,14 +191,7 @@ function display(props, fmsInfo) {
|
|
|
191
191
|
}
|
|
192
192
|
case api.LogType.BasketCycle: {
|
|
193
193
|
const basketName = basketDisplayName(fmsInfo.basketName);
|
|
194
|
-
|
|
195
|
-
return (_jsxs("span", { children: [basketName, " ", entry.pal, " started cycle"] }));
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
return (_jsxs("span", { children: [basketName, " ", entry.pal, " completed cycle", entry.containerIds && entry.containerIds.length > 0
|
|
199
|
-
? ` from ${entry.containerIds.length} UUID fragment${entry.containerIds.length === 1 ? "" : "s"}`
|
|
200
|
-
: ""] }));
|
|
201
|
-
}
|
|
194
|
+
return _jsx("span", { children: basketCycleDescription(entry, basketName) });
|
|
202
195
|
}
|
|
203
196
|
case api.LogType.BasketInLocation: {
|
|
204
197
|
const basketName = basketDisplayName(fmsInfo.basketName);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as api from "../network/api.js";
|
|
2
2
|
type ContainerNameEntry = Readonly<Pick<api.ILogEntry, "pal" | "containerId">>;
|
|
3
|
+
type BasketCycleEntry = ContainerNameEntry & Readonly<Pick<api.ILogEntry, "startofcycle" | "containerIds">>;
|
|
3
4
|
export declare function basketContainerName(entry: ContainerNameEntry, basketName: string): string;
|
|
5
|
+
export declare function basketCycleDescription(entry: BasketCycleEntry, basketName: string): string;
|
|
4
6
|
export {};
|
|
@@ -5,3 +5,13 @@ export function basketContainerName(entry, basketName) {
|
|
|
5
5
|
return `${basketName} ${entry.pal}`;
|
|
6
6
|
return basketName;
|
|
7
7
|
}
|
|
8
|
+
export function basketCycleDescription(entry, basketName) {
|
|
9
|
+
const container = basketContainerName(entry, basketName);
|
|
10
|
+
if (entry.startofcycle)
|
|
11
|
+
return `${container} started cycle`;
|
|
12
|
+
const fragmentCount = entry.containerIds?.length ?? 0;
|
|
13
|
+
const fragments = fragmentCount > 0
|
|
14
|
+
? ` from ${fragmentCount} UUID fragment${fragmentCount === 1 ? "" : "s"}`
|
|
15
|
+
: "";
|
|
16
|
+
return `${container} completed cycle${fragments}`;
|
|
17
|
+
}
|
|
@@ -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,
|
|
@@ -28,7 +28,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
28
28
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
29
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
30
30
|
*/
|
|
31
|
-
import {
|
|
31
|
+
import { useMemo, useState } from "react";
|
|
32
32
|
import { Alert, Box, Button, Card, CardContent, Stack, Typography } from "@mui/material";
|
|
33
33
|
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
34
34
|
import * as api from "../../network/api.js";
|
|
@@ -104,10 +104,10 @@ function SlotMaterial({ material, fsize, }) {
|
|
|
104
104
|
return material.map((mat) => (_jsx(MoveMaterialArrowNode, { kind: { type: MoveMaterialNodeKindType.Material, material: mat }, children: _jsx(InProcMaterial, { mat: mat, fsize: fsize }) }, mat.materialID)));
|
|
105
105
|
}
|
|
106
106
|
export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsize, submitCommand, }) {
|
|
107
|
-
const [submission, setSubmission] = useState(
|
|
107
|
+
const [submission, setSubmission] = useState();
|
|
108
108
|
const workState = useMemo(() => confirmableWork(material, basket.basketId), [basket.basketId, material]);
|
|
109
109
|
const work = workState.type === "confirmable" ? workState.work : undefined;
|
|
110
|
-
|
|
110
|
+
const submissionState = submission !== undefined && submission.workId === work?.workId ? submission.state : "idle";
|
|
111
111
|
const materialBySlot = useMemo(() => LazySeq.of(material)
|
|
112
112
|
.filter((mat) => mat.location.type === api.LocType.InBasket &&
|
|
113
113
|
mat.location.basketId === basket.basketId &&
|
|
@@ -129,15 +129,19 @@ export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsi
|
|
|
129
129
|
async function submit() {
|
|
130
130
|
if (work === undefined || submitCommand === undefined)
|
|
131
131
|
return;
|
|
132
|
-
|
|
132
|
+
const submittedWorkId = work.workId;
|
|
133
|
+
setSubmission({ workId: submittedWorkId, state: "submitting" });
|
|
133
134
|
try {
|
|
134
|
-
|
|
135
|
+
const state = await submitCommand(stationNumber, { workId: submittedWorkId });
|
|
136
|
+
setSubmission((current) => current?.workId === submittedWorkId ? { workId: submittedWorkId, state } : current);
|
|
135
137
|
}
|
|
136
138
|
catch {
|
|
137
|
-
setSubmission("error");
|
|
139
|
+
setSubmission((current) => current?.workId === submittedWorkId ? { workId: submittedWorkId, state: "error" } : current);
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
|
-
const submissionDisabled =
|
|
142
|
+
const submissionDisabled = submissionState === "submitting" ||
|
|
143
|
+
submissionState === "accepted" ||
|
|
144
|
+
submissionState === "conflict";
|
|
141
145
|
return (_jsxs(Stack, { spacing: 2, sx: { mt: 2 }, children: [_jsx(Typography, { variant: "h6", children: "Basket slots" }), _jsx(Box, { sx: {
|
|
142
146
|
display: "grid",
|
|
143
147
|
gridTemplateColumns: "repeat(auto-fit, minmax(15em, 1fr))",
|
|
@@ -147,5 +151,5 @@ export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsi
|
|
|
147
151
|
const loads = loadsBySlot.get(slot) ?? [];
|
|
148
152
|
const isUnknown = basket.unknownSlots?.includes(slot) === true;
|
|
149
153
|
return (_jsx(Card, { "data-testid": `basket-load-station-slot-${slot}`, variant: "outlined", children: _jsxs(CardContent, { children: [_jsxs(Typography, { variant: "h6", children: ["Slot ", slot] }), slotMaterial.length > 0 ? (_jsx(SlotMaterial, { material: slotMaterial, fsize: fsize })) : (_jsx(Typography, { color: isUnknown ? "warning.main" : "text.secondary", children: isUnknown ? "Unknown" : "Empty" })), loads.map((mat, index) => (_jsxs(Box, { sx: { mt: 1 }, children: [_jsx(Typography, { children: loadingInstruction(mat) }), _jsxs(Typography, { variant: "body2", color: "text.secondary", children: [mat.partName, " \u00B7 Process ", mat.action.processAfterLoad ?? mat.process] })] }, `${mat.jobUnique}-${mat.process}-${index}`)))] }) }, slot));
|
|
150
|
-
}) }), work && submitCommand ? (_jsx(Box, { sx: { display: "flex", justifyContent: "flex-end" }, children: _jsx(Button, { variant: "contained", disabled: submissionDisabled, onClick: () => void submit(), children: "Confirm" }) })) : work ? (_jsx(Alert, { severity: "warning", children: "Basket work confirmation is not configured." })) : workState.type === "inconsistent" ? (_jsx(Alert, { severity: "warning", children: "Basket work is inconsistent. Wait for refreshed material actions before confirming." })) : null,
|
|
154
|
+
}) }), work && submitCommand ? (_jsx(Box, { sx: { display: "flex", justifyContent: "flex-end" }, children: _jsx(Button, { variant: "contained", disabled: submissionDisabled, onClick: () => void submit(), children: "Confirm" }) })) : work ? (_jsx(Alert, { severity: "warning", children: "Basket work confirmation is not configured." })) : workState.type === "inconsistent" ? (_jsx(Alert, { severity: "warning", children: "Basket work is inconsistent. Wait for refreshed material actions before confirming." })) : null, submissionState === "accepted" ? (_jsx(Alert, { severity: "success", children: "Confirmation accepted. Waiting for refreshed work." })) : submissionState === "conflict" ? (_jsx(Alert, { severity: "warning", children: "Basket work changed before confirmation. Review the refreshed slots and try again." })) : submissionState === "error" ? (_jsx(Alert, { severity: "error", children: "Unable to confirm basket work. No work was assumed complete." })) : null] }));
|
|
151
155
|
}
|
|
@@ -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,60 @@
|
|
|
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
|
+
import { canCancelLoad } from "../../data/material-operation-policy.js";
|
|
12
|
+
export function CancelLoadButton({ onClose, ignoreOperator = false, }) {
|
|
13
|
+
const material = useAtomValue(inProcessMaterialInDialog);
|
|
14
|
+
const status = useAtomValue(currentStatus);
|
|
15
|
+
const operator = useAtomValue(currentOperator);
|
|
16
|
+
const setMaterialDialogOpen = useSetAtom(materialDialogOpen);
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
const [reason, setReason] = useState("");
|
|
19
|
+
const [updating, setUpdating] = useState(false);
|
|
20
|
+
const [error, setError] = useState(null);
|
|
21
|
+
const [snapshot, setSnapshot] = useState(null);
|
|
22
|
+
const cancellationId = material?.action.loadCancellationId ?? null;
|
|
23
|
+
const currentSnapshot = material === null || cancellationId === null || !canCancelLoad(material)
|
|
24
|
+
? null
|
|
25
|
+
: {
|
|
26
|
+
material,
|
|
27
|
+
cancellationId,
|
|
28
|
+
group: LazySeq.of(status.material)
|
|
29
|
+
.filter((candidate) => candidate.action.loadCancellationId === cancellationId)
|
|
30
|
+
.toRArray(),
|
|
31
|
+
};
|
|
32
|
+
if (currentSnapshot === null && snapshot === null)
|
|
33
|
+
return null;
|
|
34
|
+
async function cancelLoad() {
|
|
35
|
+
if (snapshot === null)
|
|
36
|
+
return;
|
|
37
|
+
setUpdating(true);
|
|
38
|
+
setError(null);
|
|
39
|
+
try {
|
|
40
|
+
await JobsBackend.cancelLoad(snapshot.material.materialID, ignoreOperator ? null : operator, new CancelLoadRequest({
|
|
41
|
+
expectedLoadCancellationId: snapshot.cancellationId,
|
|
42
|
+
reason: reason || undefined,
|
|
43
|
+
}));
|
|
44
|
+
setMaterialDialogOpen(null);
|
|
45
|
+
onClose?.();
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
setError(ApiException.isApiException(e) ? e.response : e instanceof Error ? e.message : String(e));
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
setUpdating(false);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return (_jsxs(_Fragment, { children: [currentSnapshot ? (_jsx(Tooltip, { title: "Cancel the displayed load instruction", children: _jsx(Button, { color: "primary", disabled: updating, onClick: () => {
|
|
55
|
+
setSnapshot(currentSnapshot);
|
|
56
|
+
setReason("");
|
|
57
|
+
setError(null);
|
|
58
|
+
setOpen(true);
|
|
59
|
+
}, 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" })] })] })] }));
|
|
60
|
+
}
|
|
@@ -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;
|