@seedtactics/insight-client 17.0.0-beta.0 → 17.0.0-beta.1

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.
@@ -2,6 +2,7 @@ import { Atom } from "jotai";
2
2
  import { ServerEventAndTime } from "./loading";
3
3
  import { ILogEntry, IRebooking, IRecentHistoricData } from "../network/api";
4
4
  import { OrderedMap } from "@seedtactics/immutable-collections";
5
+ export declare function mapUnscheduledRebookings(bookings: ReadonlyArray<Readonly<IRebooking>> | null | undefined): OrderedMap<string, Readonly<IRebooking>>;
5
6
  export declare const last30Rebookings: Atom<OrderedMap<string, Readonly<IRebooking>>>;
6
7
  export declare const canceledRebookings: Atom<OrderedMap<string, Date>>;
7
8
  type ScheduledBooking = {
@@ -46,8 +46,11 @@ const unschRebookings = unwrap(atom(async (_, { signal }) => {
46
46
  return OrderedMap.empty();
47
47
  }
48
48
  const bookings = await JobsBackend.unscheduledRebookings(signal);
49
- return OrderedMap.build(bookings, (booking) => booking.bookingId);
49
+ return mapUnscheduledRebookings(bookings);
50
50
  }), (prev) => prev ?? OrderedMap.empty());
51
+ export function mapUnscheduledRebookings(bookings) {
52
+ return OrderedMap.build(bookings ?? [], (booking) => booking.bookingId);
53
+ }
51
54
  export const last30Rebookings = atom((get) => {
52
55
  const evts = get(rebookingEvts);
53
56
  const unsch = get(unschRebookings);
@@ -29,7 +29,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
29
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
30
  */
31
31
  import { useMemo, useState } from "react";
32
- import { Alert, Box, Button, Card, CardContent, Stack, Typography } from "@mui/material";
32
+ import { Alert, Box, Button, Stack, Typography } from "@mui/material";
33
33
  import { LazySeq } from "@seedtactics/immutable-collections";
34
34
  import * as api from "../../network/api.js";
35
35
  import { InProcMaterial } from "./Material.js";
@@ -150,6 +150,10 @@ export function BasketLoadStationWorkflow({ stationNumber, basket, material, fsi
150
150
  const slotMaterial = materialBySlot.get(slot) ?? [];
151
151
  const loads = loadsBySlot.get(slot) ?? [];
152
152
  const isUnknown = basket.unknownSlots?.includes(slot) === true;
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));
153
+ return (_jsx(MoveMaterialArrowNode, { kind: {
154
+ type: MoveMaterialNodeKindType.BasketSlotZone,
155
+ basketId: basket.basketId,
156
+ slot,
157
+ }, 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));
154
158
  }) }), 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] }));
155
159
  }
@@ -284,6 +284,21 @@ function selectLoadStationAndQueueProps(loadNum, queues, curSt, hideNonLoading)
284
284
  queueMat.forEach((queue) => queue.mats.sort(mkCompareByProperties((mat) => mat.location.queuePosition ?? 0)));
285
285
  basketMat.forEach((basket) => basket.mats.sort(mkCompareByProperties((mat) => mat.location.basketSlot ?? 0)));
286
286
  const matCount = freeLoading.length + palFaces.valuesToAscLazySeq().sumBy((x) => x.length);
287
+ const activeBasketSlotCount = activeBasket
288
+ ? LazySeq.of(activeBasket.emptySlots ?? [])
289
+ .concat(activeBasket.unknownSlots ?? [])
290
+ .concat(LazySeq.of(curSt.material).collect((mat) => mat.location.type === api.LocType.InBasket &&
291
+ mat.location.basketId === activeBasket.basketId
292
+ ? mat.location.basketSlot
293
+ : undefined))
294
+ .concat(LazySeq.of(curSt.material).collect((mat) => mat.action.type === api.ActionType.LoadingToBasket &&
295
+ mat.action.loadToBasketId === activeBasket.basketId
296
+ ? mat.action.loadToBasketSlot
297
+ : undefined))
298
+ .distinctBy((slot) => slot)
299
+ .toRArray().length
300
+ : 0;
301
+ const layoutCount = Math.max(matCount, activeBasketSlotCount);
287
302
  return {
288
303
  pallet: pal,
289
304
  activeBasket,
@@ -293,7 +308,7 @@ function selectLoadStationAndQueueProps(loadNum, queues, curSt, hideNonLoading)
293
308
  queues: queueMat,
294
309
  baskets: basketMat,
295
310
  elapsedLoadingTime,
296
- fsize: matCount <= 2 ? "x-large" : matCount <= 6 ? "large" : "normal",
311
+ fsize: layoutCount <= 2 ? "x-large" : layoutCount <= 6 ? "large" : "normal",
297
312
  };
298
313
  }
299
314
  function MultiInstructionButton({ loadData }) {
@@ -377,6 +377,7 @@ const MatCard = forwardRef(function MatCard(props, ref) {
377
377
  }, children: [_jsx(PartIdenticon, { part: props.mat.partName }), _jsxs(Box, { sx: {
378
378
  marginLeft: "8px",
379
379
  flexGrow: 1,
380
+ minWidth: 0,
380
381
  }, children: [_jsx(MatCardHeader, { fsize: props.fsize, children: props.mat.partName }), props.displayJob ? (_jsx(MatCardDetail, { fsize: props.fsize, children: props.mat.jobUnique && props.mat.jobUnique !== ""
381
382
  ? "Assigned to " + props.mat.jobUnique
382
383
  : "Unassigned material" })) : undefined, !props.hideEmptySerial || props.mat.serial ? (_jsxs(MatCardDetail, { fsize: props.fsize, children: ["Serial: ", props.mat.serial ? props.mat.serial : "none"] })) : undefined, props.mat.workorderId === undefined ||
@@ -391,6 +392,7 @@ const MatCard = forwardRef(function MatCard(props, ref) {
391
392
  justifyContent: "space-between",
392
393
  alignItems: "flex-end",
393
394
  alignSelf: "start",
395
+ flexShrink: 0,
394
396
  }, children: [props.mat.serial && props.mat.serial.length >= 1 && !props.hideAvatar ? (_jsx("div", { children: _jsx(Avatar, { style: { width: "30px", height: "30px" }, children: props.mat.serial.slice(-1) }) })) : undefined, props.hideWarningIcon ? undefined : (_jsx("div", { children: _jsx(Warning, { mat: props.mat }) }))] })] }) })] }));
395
397
  });
396
398
  export const MatSummary = memo(MatCard);
@@ -7,7 +7,8 @@ export declare enum MoveMaterialNodeKindType {
7
7
  CompletedExpandedMaterialZone = 3,
8
8
  PalletFaceZone = 4,
9
9
  QueueZone = 5,
10
- BasketZone = 6
10
+ BasketZone = 6,
11
+ BasketSlotZone = 7
11
12
  }
12
13
  export type MoveMaterialNodeKind = {
13
14
  readonly type: MoveMaterialNodeKindType.Material;
@@ -28,6 +29,10 @@ export type MoveMaterialNodeKind = {
28
29
  } | {
29
30
  readonly type: MoveMaterialNodeKindType.BasketZone;
30
31
  readonly basketId: number;
32
+ } | {
33
+ readonly type: MoveMaterialNodeKindType.BasketSlotZone;
34
+ readonly basketId: number;
35
+ readonly slot: number;
31
36
  };
32
37
  export type MoveMaterialIdentifier = string;
33
38
  export declare function uniqueIdForNodeKind(kind: MoveMaterialNodeKind): MoveMaterialIdentifier;
@@ -41,6 +41,7 @@ export var MoveMaterialNodeKindType;
41
41
  MoveMaterialNodeKindType[MoveMaterialNodeKindType["PalletFaceZone"] = 4] = "PalletFaceZone";
42
42
  MoveMaterialNodeKindType[MoveMaterialNodeKindType["QueueZone"] = 5] = "QueueZone";
43
43
  MoveMaterialNodeKindType[MoveMaterialNodeKindType["BasketZone"] = 6] = "BasketZone";
44
+ MoveMaterialNodeKindType[MoveMaterialNodeKindType["BasketSlotZone"] = 7] = "BasketSlotZone";
44
45
  })(MoveMaterialNodeKindType || (MoveMaterialNodeKindType = {}));
45
46
  export function uniqueIdForNodeKind(kind) {
46
47
  switch (kind.type) {
@@ -58,6 +59,8 @@ export function uniqueIdForNodeKind(kind) {
58
59
  return "QueueZone-" + kind.queue;
59
60
  case MoveMaterialNodeKindType.BasketZone:
60
61
  return "BasketZone-" + kind.basketId.toString();
62
+ case MoveMaterialNodeKindType.BasketSlotZone:
63
+ return `BasketSlotZone-${kind.basketId}-${kind.slot}`;
61
64
  }
62
65
  }
63
66
  export function memoPropsForNodeKind(kind) {
@@ -74,6 +77,8 @@ export function memoPropsForNodeKind(kind) {
74
77
  return [kind.type, kind.queue];
75
78
  case MoveMaterialNodeKindType.BasketZone:
76
79
  return [kind.type, kind.basketId];
80
+ case MoveMaterialNodeKindType.BasketSlotZone:
81
+ return [kind.type, kind.basketId, kind.slot];
77
82
  }
78
83
  }
79
84
  function groupMatByKind(allNodes) {
@@ -82,6 +87,7 @@ function groupMatByKind(allNodes) {
82
87
  const faces = new Map();
83
88
  const queues = new Map();
84
89
  const baskets = new Map();
90
+ const basketSlots = new Map();
85
91
  const material = new Array();
86
92
  for (const node of allNodes.values()) {
87
93
  switch (node.type) {
@@ -101,6 +107,9 @@ function groupMatByKind(allNodes) {
101
107
  case MoveMaterialNodeKindType.BasketZone:
102
108
  baskets.set(node.basketId, node.elem);
103
109
  break;
110
+ case MoveMaterialNodeKindType.BasketSlotZone:
111
+ basketSlots.set(`${node.basketId}:${node.slot}`, node.elem);
112
+ break;
104
113
  case MoveMaterialNodeKindType.Material:
105
114
  if (node.material) {
106
115
  material.push([node.elem, node.material]);
@@ -108,7 +117,7 @@ function groupMatByKind(allNodes) {
108
117
  break;
109
118
  }
110
119
  }
111
- return { freeMaterial, completedMaterial, faces, queues, baskets, material };
120
+ return { freeMaterial, completedMaterial, faces, queues, baskets, basketSlots, material };
112
121
  }
113
122
  export function computeArrows(container, allNodes) {
114
123
  if (!container) {
@@ -261,7 +270,10 @@ export function computeArrows(container, allNodes) {
261
270
  const basketId = mat.action.loadToBasketId;
262
271
  if (basketId === undefined)
263
272
  break;
264
- const dest = byKind.baskets.get(basketId);
273
+ const dest = mat.action.loadToBasketSlot === undefined
274
+ ? byKind.baskets.get(basketId)
275
+ : (byKind.basketSlots.get(`${basketId}:${mat.action.loadToBasketSlot}`) ??
276
+ byKind.baskets.get(basketId));
265
277
  const lastSlotUsed = basketDestUsed.get(basketId) ?? 0;
266
278
  basketDestUsed.set(basketId, lastSlotUsed + 1);
267
279
  arrows.push({
package/dist/index.html CHANGED
@@ -43,7 +43,7 @@
43
43
  }
44
44
  }
45
45
  </style>
46
- <script type="module" crossorigin src="/assets/index-BkKYqUM0.js"></script>
46
+ <script type="module" crossorigin src="/assets/index-gLnatT5a.js"></script>
47
47
  <link rel="stylesheet" crossorigin href="/assets/index-DXfAwuj-.css">
48
48
  </head>
49
49
  <body>
@@ -15,7 +15,7 @@ export interface JobAPI {
15
15
  cancelLoad(materialId: number, operName: string | null, request: Readonly<api.ICancelLoadRequest>): Promise<void>;
16
16
  swapMaterialOnPallet(materialId: number, operName: string | null, mat: Readonly<api.IMatToPutOnPallet>): Promise<void>;
17
17
  invalidatePalletCycle(materialId: number, operName: string | null | undefined, changeCastingTo: string | null | undefined, changeJobUniqueTo: string | null | undefined, process: number): Promise<Readonly<api.IMaterialDetails> | null | undefined>;
18
- unscheduledRebookings(signal?: AbortSignal): Promise<ReadonlyArray<Readonly<api.IRebooking>>>;
18
+ unscheduledRebookings(signal?: AbortSignal): Promise<ReadonlyArray<Readonly<api.IRebooking>> | null>;
19
19
  }
20
20
  export interface FmsAPI {
21
21
  fMSInformation(): Promise<Readonly<api.IFMSInfo>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedtactics/insight-client",
3
- "version": "17.0.0-beta.0",
3
+ "version": "17.0.0-beta.1",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "url": "https://github.com/SeedTactics/fms-insight"