@seedtactics/insight-client 17.0.1-beta.7 → 17.0.1-beta.8

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.
@@ -185,26 +185,6 @@ export const updateLast30Inspections = atom(null, (_, set, { evt, now, expire })
185
185
  return parts.union(LazySeq.of(log).toLookupMap((e) => e.key, (e) => e.entry.cntr, (e) => e.entry), (e1, e2) => e1.union(e2));
186
186
  });
187
187
  }
188
- else if (evt.editMaterialInLog) {
189
- const changedByCntr = evt.editMaterialInLog.editedEvents;
190
- set(last30InspectionsRW, (parts) => parts.collectValues((entries) => {
191
- for (const changed of changedByCntr) {
192
- // inspection logs have only a single material
193
- const mat = changed?.material[0];
194
- const old = entries.get(changed.counter);
195
- if (old !== undefined && mat) {
196
- const newEntry = {
197
- ...old,
198
- materialID: mat.id,
199
- serial: mat.serial,
200
- workorder: mat.workorder,
201
- };
202
- entries = entries.set(changed.counter, newEntry);
203
- }
204
- }
205
- return entries;
206
- }));
207
- }
208
188
  });
209
189
  export const setSpecificMonthInspections = atom(null, (_, set, log) => {
210
190
  set(specificMonthInspectionsRW, LazySeq.of(log)
@@ -30,7 +30,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
30
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
31
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
32
  */
33
- import { LogType, } from "../network/api.js";
33
+ import { LogType } from "../network/api.js";
34
34
  import { addDays } from "date-fns";
35
35
  import { HashMap, LazySeq, HashSet } from "@seedtactics/immutable-collections";
36
36
  import { atom } from "jotai";
@@ -203,88 +203,6 @@ function filter_old(expire, { matIdsForJob, matsById }) {
203
203
  matsById = matsById.filter((e) => e.last_event >= expire);
204
204
  return { matIdsForJob, matsById };
205
205
  }
206
- function process_swap(swap, st) {
207
- let jobs = st.matIdsForJob;
208
- const oldMatFromState = st.matsById.get(swap.oldMaterialID) ?? null;
209
- const newMatFromState = st.matsById.get(swap.newMaterialID) ?? null;
210
- if (oldMatFromState === null)
211
- return st;
212
- let oldMat = oldMatFromState;
213
- let newMat;
214
- if (newMatFromState === null) {
215
- newMat = {
216
- materialID: swap.newMaterialID,
217
- jobUnique: oldMat.jobUnique,
218
- partName: oldMat.partName,
219
- last_event: oldMat.last_event,
220
- numProcesses: oldMat.numProcesses,
221
- startedProcess1: true,
222
- unloaded_processes: {},
223
- signaledInspections: [],
224
- quarantineAfterUnload: null,
225
- completedInspections: {},
226
- };
227
- }
228
- else {
229
- newMat = newMatFromState;
230
- }
231
- if (oldMat.jobUnique &&
232
- oldMat.jobUnique !== "" &&
233
- (!newMat.jobUnique || newMat.jobUnique === "")) {
234
- // Swap newMat from raw material
235
- const forJob = jobs.get(oldMat.jobUnique);
236
- if (forJob !== undefined) {
237
- jobs = jobs.set(oldMat.jobUnique, forJob.delete(oldMat.materialID).add(newMat.materialID));
238
- }
239
- newMat = { ...newMat, jobUnique: oldMat.jobUnique };
240
- oldMat = { ...oldMat, jobUnique: "" };
241
- }
242
- const oldMatUnloads = oldMat.unloaded_processes;
243
- oldMat = { ...oldMat, unloaded_processes: newMat.unloaded_processes };
244
- newMat = { ...newMat, unloaded_processes: oldMatUnloads };
245
- for (const evt of swap.editedEvents) {
246
- const newMatFromEvt = evt.material.find((m) => m.id === swap.newMaterialID);
247
- if (newMatFromEvt) {
248
- newMat = {
249
- ...newMat,
250
- serial: newMatFromEvt.serial ?? newMat.serial,
251
- workorderId: newMatFromEvt.workorder ?? newMat.workorderId,
252
- };
253
- }
254
- switch (evt.type) {
255
- case LogType.Inspection:
256
- case LogType.InspectionForce: {
257
- const inspType = evt.program;
258
- let inspect;
259
- if (evt.result.toLowerCase() === "true" || evt.result === "1") {
260
- inspect = true;
261
- }
262
- else {
263
- inspect = false;
264
- }
265
- if (inspect) {
266
- // remove from oldMat, add to newMat
267
- oldMat = {
268
- ...oldMat,
269
- signaledInspections: LazySeq.of(oldMat.signaledInspections)
270
- .filter((i) => i !== inspType)
271
- .toRArray(),
272
- };
273
- newMat = {
274
- ...newMat,
275
- signaledInspections: LazySeq.of([...newMat.signaledInspections, inspType])
276
- .distinct()
277
- .toSortedArray((x) => x),
278
- };
279
- }
280
- }
281
- }
282
- }
283
- return {
284
- matsById: st.matsById.set(oldMat.materialID, oldMat).set(newMat.materialID, newMat),
285
- matIdsForJob: jobs,
286
- };
287
- }
288
206
  export const setLast30MatSummary = atom(null, (_, set, log) => {
289
207
  set(last30MaterialSummaryRW, (st) => log.reduce(process_event, st));
290
208
  });
@@ -301,10 +219,6 @@ export const updateLast30MatSummary = atom(null, (_, set, { evt, now, expire })
301
219
  }
302
220
  });
303
221
  }
304
- else if (evt.editMaterialInLog) {
305
- const edit = evt.editMaterialInLog;
306
- set(last30MaterialSummaryRW, (st) => process_swap(edit, st));
307
- }
308
222
  });
309
223
  export const setSpecificMonthMatSummary = atom(null, (_, set, log) => {
310
224
  set(specificMonthMaterialSummaryRW, log.reduce(process_event, {
@@ -43,6 +43,7 @@ export declare function loadStationDisplayName(stationNumber: number, loadStatio
43
43
  export declare function displayStationName(stationGroup: string, stationNumber: number, loadStationNames: {
44
44
  [key: string]: string;
45
45
  } | undefined): string;
46
+ export declare function basketSlotLabel(slot: number): string;
46
47
  export declare function basketDisplayName(basketName: string | null | undefined): string;
47
48
  export declare function carrierLabel(cycle: Readonly<PartCycleData>, basketName?: string): string;
48
49
  export declare function carrierSortKey(cycle: Readonly<PartCycleData>): number;
@@ -72,6 +72,17 @@ export function displayStationName(stationGroup, stationNumber, loadStationNames
72
72
  ? loadStationDisplayName(stationNumber, loadStationNames)
73
73
  : stat_name_and_num(stationGroup, stationNumber);
74
74
  }
75
+ // Basket slots retain one-based numeric identities in the API and persistence. The operator UI
76
+ // displays them alphabetically: 1=A, 2=B, ..., 26=Z, 27=AA.
77
+ export function basketSlotLabel(slot) {
78
+ if (!Number.isSafeInteger(slot) || slot <= 0)
79
+ return String(slot);
80
+ let label = "";
81
+ for (let remaining = slot; remaining > 0; remaining = Math.floor((remaining - 1) / 26)) {
82
+ label = String.fromCharCode(65 + ((remaining - 1) % 26)) + label;
83
+ }
84
+ return label;
85
+ }
75
86
  export function basketDisplayName(basketName) {
76
87
  return basketName && basketName.trim().length > 0 ? basketName : "Basket";
77
88
  }
@@ -151,16 +162,6 @@ function convertOldLogsToCycles(estimateCycleTimes, log, loadStationNames) {
151
162
  .collect((c) => convertLogToCycle(estimateCycleTimes, c.cycle, c.elapsedForSingleMaterialMinutes, loadStationNames))
152
163
  .buildHashMap((c) => c.cntr);
153
164
  }
154
- function process_swap(swap, partCycles) {
155
- for (const changed of swap.editedEvents) {
156
- const c = partCycles.get(changed.counter);
157
- if (c !== undefined) {
158
- const newC = { ...c, material: changed.material };
159
- partCycles = partCycles.set(changed.counter, newC);
160
- }
161
- }
162
- return partCycles;
163
- }
164
165
  export const setLast30StationCycles = atom(null, (get, set, log) => {
165
166
  const estimatedCycleTimes = get(last30EstimatedCycleTimes);
166
167
  const loadStationNames = get(fmsInformation)?.loadStationNames;
@@ -204,10 +205,6 @@ export const updateLast30StationCycles = atom(null, (get, set, { evt, now, expir
204
205
  return cycles;
205
206
  });
206
207
  }
207
- else if (evt.editMaterialInLog) {
208
- const edit = evt.editMaterialInLog;
209
- set(last30StationCyclesRW, (oldCycles) => process_swap(edit, oldCycles));
210
- }
211
208
  });
212
209
  export const setSpecificMonthStationCycles = atom(null, (get, set, log) => {
213
210
  const estimatedCycleTimes = get(specificMonthEstimatedCycleTimes);
@@ -39,7 +39,7 @@ import { Box } from "@mui/material";
39
39
  import { Typography } from "@mui/material";
40
40
  import { LazySeq } from "@seedtactics/immutable-collections";
41
41
  import { DragOverlayInProcMaterial, InProcMaterial, MaterialDialog, SortableInProcMaterial, } from "../station-monitor/Material.js";
42
- import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterialButtons, SwapMaterialDialogContent, } from "../station-monitor/InvalidateCycle.js";
42
+ import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, } from "../station-monitor/InvalidateCycle.js";
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";
@@ -147,13 +147,11 @@ function MaterialBinColumn({ matBin, isDragOverlay, }) {
147
147
  }
148
148
  }
149
149
  const AllMatDialog = memo(function AllMatDialog() {
150
- const [swapSt, setSwapSt] = useState(null);
151
150
  const [invalidateSt, setInvalidateSt] = useState(null);
152
151
  function onClose() {
153
- setSwapSt(null);
154
152
  setInvalidateSt(null);
155
153
  }
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 })] }) }));
154
+ return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsx(_Fragment, { children: 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(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: true })] }) }));
157
155
  });
158
156
  function useCollisionDetection(allBins) {
159
157
  return useCallback((args) => {
@@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
31
  import { useMemo, useState } from "react";
32
32
  import { Alert, Box, Button, Stack, Typography } from "@mui/material";
33
33
  import { LazySeq } from "@seedtactics/immutable-collections";
34
+ import { basketSlotLabel } from "../../cell-status/station-cycles.js";
34
35
  import * as api from "../../network/api.js";
35
36
  import { InProcMaterial } from "./Material.js";
36
37
  import { MoveMaterialArrowNode } from "./MoveMaterialArrows.js";
@@ -140,6 +141,7 @@ function SlotMaterial({ material, fsize, }) {
140
141
  export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsize, submitCommand, }) {
141
142
  const [submission, setSubmission] = useState();
142
143
  const workState = useMemo(() => stationWork(material, basket), [basket, material]);
144
+ const blockedReason = basket.loadStationWork?.confirmationBlockedReason?.trim();
143
145
  const work = workState.type === "active" ? workState.work : undefined;
144
146
  const submissionState = submission !== undefined &&
145
147
  submission.workId === work?.workId &&
@@ -197,8 +199,9 @@ export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsi
197
199
  type: MoveMaterialNodeKindType.BasketSlotZone,
198
200
  basketId: basket.basketId,
199
201
  slot,
200
- }, children: _jsxs(Box, { component: "section", "data-testid": `basket-load-station-slot-${slot}`, sx: { border: "1px solid", borderColor: "text.primary", p: 2 }, 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));
201
- }) }), work?.confirmEmpty && _jsxs(Typography, { children: ["Confirm basket ", basket.basketId, " is empty."] }), work && !work.ready && (_jsx(Alert, { severity: "info", children: work.awaitingSlots.length > 0
202
- ? `Waiting for material for slots ${work.awaitingSlots.join(", ")}.`
203
- : "Basket work is not ready for confirmation." })), 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] }));
202
+ }, children: _jsxs(Box, { component: "section", "data-testid": `basket-load-station-slot-${slot}`, sx: { border: "1px solid", borderColor: "text.primary", p: 2 }, children: [_jsxs(Typography, { variant: "h6", children: ["Slot ", basketSlotLabel(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));
203
+ }) }), work?.confirmEmpty && _jsxs(Typography, { children: ["Confirm basket ", basket.basketId, " is empty."] }), work && !work.ready && (_jsx(Alert, { severity: "info", children: blockedReason ||
204
+ (work.awaitingSlots.length > 0
205
+ ? `Waiting for material for slots ${work.awaitingSlots.map(basketSlotLabel).join(", ")}.`
206
+ : "Basket work is not ready for confirmation.") })), 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] }));
204
207
  }
@@ -1,6 +1,5 @@
1
- import { IInProcessMaterial, ILogEntry } from "../../network/api.js";
1
+ import { ILogEntry } from "../../network/api.js";
2
2
  import { HashMap } from "@seedtactics/immutable-collections";
3
- import { ReactNode } from "react";
4
3
  export type InvalidateCycleState = {
5
4
  readonly process: number | null;
6
5
  readonly changeRawMat: string | null;
@@ -19,18 +18,3 @@ export declare function InvalidateCycleDialogButton(props: InvalidateCycleProps
19
18
  readonly ignoreOperator?: boolean;
20
19
  readonly loadStation?: boolean;
21
20
  }): import("react").JSX.Element | null;
22
- interface SwapMaterial {
23
- readonly selectedMatToSwap: Readonly<IInProcessMaterial> | null;
24
- readonly updating: boolean;
25
- }
26
- export type SwapMaterialState = SwapMaterial | null;
27
- export interface SwapMaterialProps {
28
- readonly st: SwapMaterialState;
29
- readonly setState: (s: SwapMaterialState) => void;
30
- }
31
- export declare function SwapMaterialDialogContent(props: SwapMaterialProps): ReactNode;
32
- export declare function SwapMaterialButtons(props: SwapMaterialProps & {
33
- readonly onClose: () => void;
34
- readonly ignoreOperator?: boolean;
35
- }): import("react").JSX.Element | null;
36
- export {};
@@ -47,14 +47,12 @@ import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
47
47
  import { PartIdenticon } from "./Material.js";
48
48
  import { isLogEntryInvalidated } from "../LogEntry.js";
49
49
  import { ApiException } from "../../network/api.js";
50
- import { canInvalidateMaterial, isActiveLoadStationOperation, } from "../../data/material-operation-policy.js";
50
+ import { canInvalidateMaterial } from "../../data/material-operation-policy.js";
51
51
  const invalidatableEventTypes = LazySeq.of([
52
52
  LogType.AddToQueue,
53
53
  LogType.RemoveFromQueue,
54
54
  LogType.LoadUnloadCycle,
55
55
  LogType.MachineCycle,
56
- LogType.BasketLoadUnload,
57
- LogType.BasketCycle,
58
56
  ]).toRSet((eventType) => eventType);
59
57
  export function affectedMaterialForInvalidation(events, materialId, process) {
60
58
  let affected = HashMap.empty();
@@ -245,91 +243,3 @@ export function InvalidateCycleDialogButton(props) {
245
243
  : "Invalidate Process " + props.st.process.toString()
246
244
  : "Invalidate Cycle" })) : undefined] }));
247
245
  }
248
- function isNullOrEmpty(s) {
249
- return s === undefined || s === null || s == "";
250
- }
251
- function matCanSwap(curMat, job) {
252
- return (newMat) => {
253
- if (isNullOrEmpty(newMat.serial))
254
- return false;
255
- if (newMat.location.type === LocType.OnPallet)
256
- return false;
257
- if (newMat.process !== curMat.process - 1)
258
- return false;
259
- if (isNullOrEmpty(newMat.jobUnique)) {
260
- // if part name is wrong, check casting
261
- if (isNullOrEmpty(newMat.partName))
262
- return false;
263
- if (newMat.partName !== curMat.partName) {
264
- if (!job)
265
- return false;
266
- if (!LazySeq.of(job.procsAndPaths)
267
- .flatMap((p) => p.paths)
268
- .some((p) => p.casting === newMat.partName)) {
269
- return false;
270
- }
271
- }
272
- }
273
- else {
274
- // check path
275
- if (newMat.jobUnique !== curMat.jobUnique)
276
- return false;
277
- if (newMat.path !== curMat.path)
278
- return false;
279
- }
280
- return true;
281
- };
282
- }
283
- export function SwapMaterialDialogContent(props) {
284
- const status = useAtomValue(currentStatus);
285
- const curMat = useAtomValue(inProcessMaterialInDialog);
286
- if (curMat === null || props.st === null)
287
- return _jsx("div", {});
288
- const curMatJob = status.jobs[curMat.jobUnique];
289
- const availMats = status.material.filter(matCanSwap(curMat, curMatJob));
290
- if (availMats.length === 0) {
291
- return (_jsx("p", { style: { margin: "2em" }, children: "No material with the same job is available for swapping. You must edit the pallet using the cell controller software to remove the material from the pallet. Insight will automatically refresh once the cell controller software is updated." }));
292
- }
293
- else {
294
- return (_jsxs("div", { style: { margin: "2em" }, children: [_jsx("p", { children: "Swap serial on pallet with material from the same job." }), _jsx("p", { children: "If material on the pallet is from a different job, you cannot use this screen. Instead, the material must first be removed from the pallet using the cell controller software. Insight will automatically refresh when this occurs." }), _jsx(TextField, { value: props.st?.selectedMatToSwap?.serial ?? "", select: true, onChange: (e) => props.st &&
295
- props.setState({
296
- ...props.st,
297
- selectedMatToSwap: availMats.find((m) => m.serial === e.target.value) ?? null,
298
- }), style: { width: "20em" }, variant: "outlined", label: "Select serial to swap with " + (curMat.serial ?? ""), children: availMats.map((m) => (_jsx(MenuItem, { value: m.serial, children: m.serial }, m.materialID))) })] }));
299
- }
300
- }
301
- export function SwapMaterialButtons(props) {
302
- const fmsInfo = useAtomValue(fmsInformation);
303
- const curMat = useAtomValue(inProcessMaterialInDialog);
304
- const closeMatDialog = useSetAtom(materialDialogOpen);
305
- let operator = useAtomValue(currentOperator);
306
- if (!fmsInfo.allowSwapSerialAtLoadStation)
307
- return null;
308
- if (props.ignoreOperator)
309
- operator = null;
310
- if (!curMat ||
311
- curMat.location.type !== LocType.OnPallet ||
312
- isActiveLoadStationOperation(curMat)) {
313
- return null;
314
- }
315
- function swapMats() {
316
- if (curMat &&
317
- props.st &&
318
- props.st.selectedMatToSwap &&
319
- curMat.location.type === LocType.OnPallet) {
320
- props.setState({ selectedMatToSwap: props.st.selectedMatToSwap, updating: true });
321
- JobsBackend.swapMaterialOnPallet(curMat.materialID, operator, {
322
- pallet: curMat.location.palletNum ?? 0,
323
- materialIDToSetOnPallet: props.st.selectedMatToSwap.materialID,
324
- })
325
- .catch(console.log)
326
- .finally(() => {
327
- closeMatDialog(null);
328
- props.onClose();
329
- });
330
- }
331
- }
332
- return (_jsxs(_Fragment, { children: [props.st === null ? (_jsx(Button, { color: "primary", onClick: () => props.setState({ selectedMatToSwap: null, updating: false }), children: "Swap Serial" })) : undefined, props.st !== null ? (_jsx(Button, { color: "primary", onClick: swapMats, disabled: props.st.selectedMatToSwap === null || props.st.updating, children: props.st.selectedMatToSwap === null
333
- ? "Swap Serial"
334
- : "Swap with " + (props.st.selectedMatToSwap.serial ?? "") })) : undefined] }));
335
- }
@@ -54,7 +54,7 @@ import { QuarantineMatButton } from "./QuarantineButton.js";
54
54
  import { CancelLoadButton } from "./CancelLoadButton.js";
55
55
  import { durationToSeconds } from "../../util/parseISODuration.js";
56
56
  import { formatSeconds } from "./SystemOverview.js";
57
- import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterialButtons, SwapMaterialDialogContent, } from "./InvalidateCycle.js";
57
+ import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, } from "./InvalidateCycle.js";
58
58
  import { last30MaterialSummary } from "../../cell-status/material-summary.js";
59
59
  import { addHours } from "date-fns";
60
60
  import { PromptForQueue } from "./QueuesAddMaterial.js";
@@ -625,18 +625,16 @@ function AssignWorkorderButton() {
625
625
  return (_jsx(Button, { color: "primary", onClick: () => setWorkorderDialogOpen(true), children: "Assign Workorder" }));
626
626
  }
627
627
  const LoadMatDialog = memo(function LoadMatDialog(props) {
628
- const [swapSt, setSwapSt] = useState(null);
629
628
  const [invalidateSt, setInvalidateSt] = useState(null);
630
629
  // add material state
631
630
  const [showAddMaterial, setShowAddMaterial] = useState(false);
632
631
  const [selectedQueue, setSelectedQueue] = useState(null);
633
632
  const onClose = useCallback(function onClose() {
634
- setSwapSt(null);
635
633
  setInvalidateSt(null);
636
634
  setShowAddMaterial(false);
637
635
  setSelectedQueue(null);
638
- }, [setSwapSt, setInvalidateSt]);
639
- 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, {})] }) }));
636
+ }, [setInvalidateSt]);
637
+ return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsxs(_Fragment, { children: [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(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, loadStation: true }), _jsx(AssignWorkorderButton, {})] }) }));
640
638
  });
641
639
  function useGridLayout({ numMatCols, maxNumFaces, horizontal, showMatInCompleted, }) {
642
640
  let rows = "";
@@ -48,7 +48,7 @@ import { currentStatus } from "../../cell-status/current-status.js";
48
48
  import { useAtom, useAtomValue, useSetAtom } from "jotai";
49
49
  import { last30Rebookings } from "../../cell-status/rebookings.js";
50
50
  import { fmsInformation } from "../../network/server-settings.js";
51
- import { basketDisplayName } from "../../cell-status/station-cycles.js";
51
+ import { basketDisplayName, basketSlotLabel } from "../../cell-status/station-cycles.js";
52
52
  import { materialOperationState } from "../../data/material-operation-policy.js";
53
53
  export class PartIdenticon extends PureComponent {
54
54
  render() {
@@ -236,12 +236,14 @@ export function MaterialAction({ mat, displayActionForSinglePallet, fsize, }) {
236
236
  }
237
237
  }
238
238
  case api.ActionType.LoadingToBasket:
239
- return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Load into ", basketName, " ", mat.action.loadToBasketId ?? "", mat.action.loadToBasketSlot !== undefined ? ` slot ${mat.action.loadToBasketSlot}` : ""] }));
239
+ return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Load into ", basketName, " ", mat.action.loadToBasketId ?? "", mat.action.loadToBasketSlot !== undefined
240
+ ? ` slot ${basketSlotLabel(mat.action.loadToBasketSlot)}`
241
+ : ""] }));
240
242
  case api.ActionType.UnloadToInProcess:
241
243
  case api.ActionType.UnloadToCompletedMaterial:
242
244
  if (mat.action.unloadToBasketId) {
243
245
  return (_jsxs(MatCardDetail, { fsize: fsize, children: ["Unload to ", basketName, " ", mat.action.unloadToBasketId, mat.action.unloadToBasketSlot !== undefined
244
- ? ` slot ${mat.action.unloadToBasketSlot}`
246
+ ? ` slot ${basketSlotLabel(mat.action.unloadToBasketSlot)}`
245
247
  : ""] }));
246
248
  }
247
249
  else if (mat.action.unloadIntoQueue) {
@@ -42,7 +42,7 @@ import { materialDialogOpen } from "../../cell-status/material-details.js";
42
42
  import { last30Jobs } from "../../cell-status/scheduled-jobs.js";
43
43
  import { addDays } from "date-fns";
44
44
  import { durationToSeconds } from "../../util/parseISODuration.js";
45
- import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, SwapMaterialButtons, SwapMaterialDialogContent, } from "./InvalidateCycle.js";
45
+ import { InvalidateCycleDialogButton, InvalidateCycleDialogContent, } from "./InvalidateCycle.js";
46
46
  import { CancelLoadButton } from "./CancelLoadButton.js";
47
47
  import { QuarantineMatButton } from "./QuarantineButton.js";
48
48
  import { SelectInspTypeDialog, SignalInspectionButton } from "./SelectInspType.js";
@@ -824,13 +824,11 @@ export const SystemOverview = memo(function SystemOverview({ overview, }) {
824
824
  }, children: [overview.stockerPals.map((pal) => (_jsx(StockerPallet, { pallet: pal, maxNumFaces: overview.maxNumFacesOnPallet }, pal.pallet.palletNum))), overview.floatingBaskets.map((basket) => (_jsx(FloatingBasket, { basket: basket }, basket.basket.basketId))), overview.storageBaskets ? (_jsx(BasketStorageSummary, { empty: overview.storageBaskets.empty, filled: overview.storageBaskets.filled })) : undefined] })) : undefined] }));
825
825
  });
826
826
  const SystemOverviewMaterialDialog = memo(function SystemOverviewMaterialDialog({ ignoreOperator, }) {
827
- const [swapSt, setSwapSt] = useState(null);
828
827
  const [invalidateSt, setInvalidateSt] = useState(null);
829
828
  function onClose() {
830
- setSwapSt(null);
831
829
  setInvalidateSt(null);
832
830
  }
833
- 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 })] }) }));
831
+ return (_jsx(MaterialDialog, { onClose: onClose, allowNote: true, highlightProcsGreaterOrEqualTo: invalidateSt?.process ?? undefined, extraDialogElements: _jsx(_Fragment, { children: 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(InvalidateCycleDialogButton, { st: invalidateSt, setState: setInvalidateSt, onClose: onClose, ignoreOperator: ignoreOperator })] }) }));
834
832
  });
835
833
  export function SystemOverviewPage({ ignoreOperator, whiteBackground, }) {
836
834
  useSetTitle("System Overview");
package/dist/index.html CHANGED
@@ -43,7 +43,7 @@
43
43
  }
44
44
  }
45
45
  </style>
46
- <script type="module" crossorigin src="/assets/index-CNJT3DX_.js"></script>
46
+ <script type="module" crossorigin src="/assets/index-MFZreX-b.js"></script>
47
47
  <link rel="stylesheet" crossorigin href="/assets/index-DXfAwuj-.css">
48
48
  </head>
49
49
  <body>
@@ -59,8 +59,6 @@ export declare class JobsClient {
59
59
  protected processCancelLoad(response: Response): Promise<void>;
60
60
  invalidatePalletCycle(materialId: number, operName: string | null | undefined, changeCastingTo: string | null | undefined, changeJobUniqueTo: string | null | undefined, process: number, signal?: AbortSignal): Promise<MaterialDetails>;
61
61
  protected processInvalidatePalletCycle(response: Response): Promise<MaterialDetails>;
62
- swapMaterialOnPallet(materialId: number, operName: string | null | undefined, mat: MatToPutOnPallet, signal?: AbortSignal): Promise<void>;
63
- protected processSwapMaterialOnPallet(response: Response): Promise<void>;
64
62
  bulkRemoveMaterialFromQueues(operName: string | null | undefined, id: number[], signal?: AbortSignal): Promise<void>;
65
63
  protected processBulkRemoveMaterialFromQueues(response: Response): Promise<void>;
66
64
  decrementQuantities(loadDecrementsStrictlyAfterDecrementId: number | null | undefined, loadDecrementsAfterTimeUTC: Date | null | undefined, signal?: AbortSignal): Promise<JobAndDecrementQuantity[]>;
@@ -148,7 +146,6 @@ export declare class FMSInfo implements IFMSInfo {
148
146
  customStationMonitorDialogUrl?: string | undefined;
149
147
  supportsRebookings?: string | undefined;
150
148
  allowChangeWorkorderAtLoadStation?: boolean | undefined;
151
- allowSwapSerialAtLoadStation?: boolean | undefined;
152
149
  allowInvalidateMaterialAtLoadStation?: boolean | undefined;
153
150
  loadStationNames?: {
154
151
  [key: string]: string;
@@ -179,7 +176,6 @@ export interface IFMSInfo {
179
176
  customStationMonitorDialogUrl?: string | undefined;
180
177
  supportsRebookings?: string | undefined;
181
178
  allowChangeWorkorderAtLoadStation?: boolean | undefined;
182
- allowSwapSerialAtLoadStation?: boolean | undefined;
183
179
  allowInvalidateMaterialAtLoadStation?: boolean | undefined;
184
180
  loadStationNames?: {
185
181
  [key: string]: string;
@@ -202,7 +198,6 @@ export declare class ServerEvent implements IServerEvent {
202
198
  logEntry?: LogEntry | undefined;
203
199
  newJobs?: NewJobs | undefined;
204
200
  newCurrentStatus?: CurrentStatus | undefined;
205
- editMaterialInLog?: EditMaterialInLogEvents | undefined;
206
201
  constructor(data?: IServerEvent);
207
202
  init(_data?: any): void;
208
203
  static fromJS(data: any): ServerEvent;
@@ -212,7 +207,6 @@ export interface IServerEvent {
212
207
  logEntry?: LogEntry | undefined;
213
208
  newJobs?: NewJobs | undefined;
214
209
  newCurrentStatus?: CurrentStatus | undefined;
215
- editMaterialInLog?: EditMaterialInLogEvents | undefined;
216
210
  }
217
211
  export declare class LogEntry implements ILogEntry {
218
212
  counter: number;
@@ -1080,6 +1074,7 @@ export declare class BasketLoadStationWork implements IBasketLoadStationWork {
1080
1074
  workId: string;
1081
1075
  type: BasketLoadStationWorkType;
1082
1076
  readyToConfirm: boolean;
1077
+ confirmationBlockedReason?: string | undefined;
1083
1078
  awaitingMaterialSlots?: number[];
1084
1079
  constructor(data?: IBasketLoadStationWork);
1085
1080
  init(_data?: any): void;
@@ -1090,6 +1085,7 @@ export interface IBasketLoadStationWork {
1090
1085
  workId: string;
1091
1086
  type: BasketLoadStationWorkType;
1092
1087
  readyToConfirm: boolean;
1088
+ confirmationBlockedReason?: string | undefined;
1093
1089
  awaitingMaterialSlots?: number[];
1094
1090
  }
1095
1091
  export declare enum BasketLoadStationWorkType {
@@ -1150,20 +1146,6 @@ export declare enum BasketMoveReason {
1150
1146
  RemoveForCorrection = "RemoveForCorrection",
1151
1147
  Other = "Other"
1152
1148
  }
1153
- export declare class EditMaterialInLogEvents implements IEditMaterialInLogEvents {
1154
- oldMaterialID: number;
1155
- newMaterialID: number;
1156
- editedEvents: LogEntry[];
1157
- constructor(data?: IEditMaterialInLogEvents);
1158
- init(_data?: any): void;
1159
- static fromJS(data: any): EditMaterialInLogEvents;
1160
- toJSON(data?: any): any;
1161
- }
1162
- export interface IEditMaterialInLogEvents {
1163
- oldMaterialID: number;
1164
- newMaterialID: number;
1165
- editedEvents: LogEntry[];
1166
- }
1167
1149
  export declare class ProblemDetails implements IProblemDetails {
1168
1150
  type?: string | undefined;
1169
1151
  title?: string | undefined;
@@ -1400,18 +1382,6 @@ export interface ICancelLoadRequest {
1400
1382
  expectedLoadCancellationId: string;
1401
1383
  reason?: string | undefined;
1402
1384
  }
1403
- export declare class MatToPutOnPallet implements IMatToPutOnPallet {
1404
- pallet: number;
1405
- materialIDToSetOnPallet: number;
1406
- constructor(data?: IMatToPutOnPallet);
1407
- init(_data?: any): void;
1408
- static fromJS(data: any): MatToPutOnPallet;
1409
- toJSON(data?: any): any;
1410
- }
1411
- export interface IMatToPutOnPallet {
1412
- pallet: number;
1413
- materialIDToSetOnPallet: number;
1414
- }
1415
1385
  export declare class JobAndDecrementQuantity implements IJobAndDecrementQuantity {
1416
1386
  decrementId: number;
1417
1387
  jobUnique: string;