@seedtactics/insight-client 16.4.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 +37 -0
- package/dist/cell-status/buffers.d.ts +36 -0
- package/dist/cell-status/buffers.js +127 -0
- package/dist/cell-status/current-status.d.ts +30 -0
- package/dist/cell-status/current-status.js +200 -0
- package/dist/cell-status/estimated-cycle-times.d.ts +41 -0
- package/dist/cell-status/estimated-cycle-times.js +257 -0
- package/dist/cell-status/inspections.d.ts +55 -0
- package/dist/cell-status/inspections.js +213 -0
- package/dist/cell-status/loading.d.ts +26 -0
- package/dist/cell-status/loading.js +112 -0
- package/dist/cell-status/material-details.d.ts +116 -0
- package/dist/cell-status/material-details.js +422 -0
- package/dist/cell-status/material-summary.d.ts +52 -0
- package/dist/cell-status/material-summary.js +312 -0
- package/dist/cell-status/names.d.ts +19 -0
- package/dist/cell-status/names.js +134 -0
- package/dist/cell-status/pallet-cycles.d.ts +24 -0
- package/dist/cell-status/pallet-cycles.js +78 -0
- package/dist/cell-status/rebookings.d.ts +30 -0
- package/dist/cell-status/rebookings.js +139 -0
- package/dist/cell-status/scheduled-jobs.d.ts +18 -0
- package/dist/cell-status/scheduled-jobs.js +94 -0
- package/dist/cell-status/sim-day-usage.d.ts +14 -0
- package/dist/cell-status/sim-day-usage.js +54 -0
- package/dist/cell-status/sim-production.d.ts +22 -0
- package/dist/cell-status/sim-production.js +91 -0
- package/dist/cell-status/sim-station-use.d.ts +25 -0
- package/dist/cell-status/sim-station-use.js +71 -0
- package/dist/cell-status/station-cycles.d.ts +34 -0
- package/dist/cell-status/station-cycles.js +145 -0
- package/dist/cell-status/tool-replacements.d.ts +44 -0
- package/dist/cell-status/tool-replacements.js +155 -0
- package/dist/cell-status/tool-usage.d.ts +25 -0
- package/dist/cell-status/tool-usage.js +95 -0
- package/dist/components/App.d.ts +15 -0
- package/dist/components/App.js +549 -0
- package/dist/components/AxisAndGrid.d.ts +51 -0
- package/dist/components/AxisAndGrid.js +47 -0
- package/dist/components/BarcodeScanning.d.ts +6 -0
- package/dist/components/BarcodeScanning.js +150 -0
- package/dist/components/ChartTooltip.d.ts +28 -0
- package/dist/components/ChartTooltip.js +95 -0
- package/dist/components/ChooseMode.d.ts +18 -0
- package/dist/components/ChooseMode.js +136 -0
- package/dist/components/ChooseOperator.d.ts +1 -0
- package/dist/components/ChooseOperator.js +93 -0
- package/dist/components/ErrorsAndLoading.d.ts +9 -0
- package/dist/components/ErrorsAndLoading.js +55 -0
- package/dist/components/LoadingIcon.d.ts +1 -0
- package/dist/components/LoadingIcon.js +48 -0
- package/dist/components/LogEntry.d.ts +16 -0
- package/dist/components/LogEntry.js +365 -0
- package/dist/components/ManualSerialEntry.d.ts +5 -0
- package/dist/components/ManualSerialEntry.js +91 -0
- package/dist/components/MonthSelect.d.ts +6 -0
- package/dist/components/MonthSelect.js +67 -0
- package/dist/components/Navigation.d.ts +23 -0
- package/dist/components/Navigation.js +120 -0
- package/dist/components/VerboseLogging.d.ts +1 -0
- package/dist/components/VerboseLogging.js +47 -0
- package/dist/components/analysis/AnalysisSelectToolbar.d.ts +1 -0
- package/dist/components/analysis/AnalysisSelectToolbar.js +55 -0
- package/dist/components/analysis/BufferChart.d.ts +1 -0
- package/dist/components/analysis/BufferChart.js +139 -0
- package/dist/components/analysis/CostPerPiece.d.ts +2 -0
- package/dist/components/analysis/CostPerPiece.js +175 -0
- package/dist/components/analysis/CycleChart.d.ts +42 -0
- package/dist/components/analysis/CycleChart.js +281 -0
- package/dist/components/analysis/DataTable.d.ts +83 -0
- package/dist/components/analysis/DataTable.js +215 -0
- package/dist/components/analysis/EfficiencyPage.d.ts +2 -0
- package/dist/components/analysis/EfficiencyPage.js +138 -0
- package/dist/components/analysis/HeatChart.d.ts +22 -0
- package/dist/components/analysis/HeatChart.js +161 -0
- package/dist/components/analysis/InspectionDataTable.d.ts +10 -0
- package/dist/components/analysis/InspectionDataTable.js +148 -0
- package/dist/components/analysis/InspectionSankey.d.ts +12 -0
- package/dist/components/analysis/InspectionSankey.js +140 -0
- package/dist/components/analysis/PalletCycleCards.d.ts +1 -0
- package/dist/components/analysis/PalletCycleCards.js +137 -0
- package/dist/components/analysis/PartCycleCards.d.ts +2 -0
- package/dist/components/analysis/PartCycleCards.js +331 -0
- package/dist/components/analysis/QualityPage.d.ts +1 -0
- package/dist/components/analysis/QualityPage.js +49 -0
- package/dist/components/analysis/ScheduleHistory.d.ts +3 -0
- package/dist/components/analysis/ScheduleHistory.js +108 -0
- package/dist/components/analysis/StationDataTable.d.ts +25 -0
- package/dist/components/analysis/StationDataTable.js +246 -0
- package/dist/components/analysis/ToolReplacements.d.ts +1 -0
- package/dist/components/analysis/ToolReplacements.js +370 -0
- package/dist/components/operations/AllMaterial.d.ts +5 -0
- package/dist/components/operations/AllMaterial.js +267 -0
- package/dist/components/operations/ChartRangeEdit.d.ts +4 -0
- package/dist/components/operations/ChartRangeEdit.js +148 -0
- package/dist/components/operations/CloseoutReport.d.ts +2 -0
- package/dist/components/operations/CloseoutReport.js +172 -0
- package/dist/components/operations/CompletedParts.d.ts +2 -0
- package/dist/components/operations/CompletedParts.js +286 -0
- package/dist/components/operations/CurrentWorkorders.d.ts +3 -0
- package/dist/components/operations/CurrentWorkorders.js +368 -0
- package/dist/components/operations/Dashboard.d.ts +2 -0
- package/dist/components/operations/Dashboard.js +90 -0
- package/dist/components/operations/OEEChart.d.ts +10 -0
- package/dist/components/operations/OEEChart.js +173 -0
- package/dist/components/operations/Outliers.d.ts +4 -0
- package/dist/components/operations/Outliers.js +69 -0
- package/dist/components/operations/ProgramHighlight.d.ts +1 -0
- package/dist/components/operations/ProgramHighlight.js +9 -0
- package/dist/components/operations/Programs.d.ts +5 -0
- package/dist/components/operations/Programs.js +363 -0
- package/dist/components/operations/Rebookings.d.ts +1 -0
- package/dist/components/operations/Rebookings.js +213 -0
- package/dist/components/operations/RecentCycleChart.d.ts +4 -0
- package/dist/components/operations/RecentCycleChart.js +240 -0
- package/dist/components/operations/RecentProduction.d.ts +2 -0
- package/dist/components/operations/RecentProduction.js +213 -0
- package/dist/components/operations/RecentSchedules.d.ts +12 -0
- package/dist/components/operations/RecentSchedules.js +180 -0
- package/dist/components/operations/RecentStationCycles.d.ts +4 -0
- package/dist/components/operations/RecentStationCycles.js +159 -0
- package/dist/components/operations/ShiftSettings.d.ts +6 -0
- package/dist/components/operations/ShiftSettings.js +134 -0
- package/dist/components/operations/SimDayUsage.d.ts +1 -0
- package/dist/components/operations/SimDayUsage.js +133 -0
- package/dist/components/operations/ToolReport.d.ts +3 -0
- package/dist/components/operations/ToolReport.js +233 -0
- package/dist/components/operations/WorkorderGantt.d.ts +1 -0
- package/dist/components/operations/WorkorderGantt.js +124 -0
- package/dist/components/quality/QualityMaterial.d.ts +2 -0
- package/dist/components/quality/QualityMaterial.js +169 -0
- package/dist/components/quality/QualityPaths.d.ts +1 -0
- package/dist/components/quality/QualityPaths.js +53 -0
- package/dist/components/quality/RecentFailedInspections.d.ts +1 -0
- package/dist/components/quality/RecentFailedInspections.js +123 -0
- package/dist/components/routes.d.ts +170 -0
- package/dist/components/routes.js +301 -0
- package/dist/components/station-monitor/BulkRawMaterial.d.ts +11 -0
- package/dist/components/station-monitor/BulkRawMaterial.js +251 -0
- package/dist/components/station-monitor/Closeout.d.ts +5 -0
- package/dist/components/station-monitor/Closeout.js +162 -0
- package/dist/components/station-monitor/CustomStationMonitorDialog.d.ts +1 -0
- package/dist/components/station-monitor/CustomStationMonitorDialog.js +55 -0
- package/dist/components/station-monitor/Inspection.d.ts +8 -0
- package/dist/components/station-monitor/Inspection.js +164 -0
- package/dist/components/station-monitor/InvalidateCycle.d.ts +33 -0
- package/dist/components/station-monitor/InvalidateCycle.js +262 -0
- package/dist/components/station-monitor/JobDetails.d.ts +7 -0
- package/dist/components/station-monitor/JobDetails.js +108 -0
- package/dist/components/station-monitor/LoadStation.d.ts +10 -0
- package/dist/components/station-monitor/LoadStation.js +450 -0
- package/dist/components/station-monitor/Material.d.ts +77 -0
- package/dist/components/station-monitor/Material.js +489 -0
- package/dist/components/station-monitor/MoveMaterialArrows.d.ts +11 -0
- package/dist/components/station-monitor/MoveMaterialArrows.js +118 -0
- package/dist/components/station-monitor/PrintedLabel.d.ts +29 -0
- package/dist/components/station-monitor/PrintedLabel.js +166 -0
- package/dist/components/station-monitor/QuarantineButton.d.ts +4 -0
- package/dist/components/station-monitor/QuarantineButton.js +184 -0
- package/dist/components/station-monitor/Queues.d.ts +23 -0
- package/dist/components/station-monitor/Queues.js +312 -0
- package/dist/components/station-monitor/QueuesAddMaterial.d.ts +30 -0
- package/dist/components/station-monitor/QueuesAddMaterial.js +248 -0
- package/dist/components/station-monitor/SelectInspType.d.ts +2 -0
- package/dist/components/station-monitor/SelectInspType.js +99 -0
- package/dist/components/station-monitor/SelectWorkorder.d.ts +4 -0
- package/dist/components/station-monitor/SelectWorkorder.js +100 -0
- package/dist/components/station-monitor/StationToolbar.d.ts +3 -0
- package/dist/components/station-monitor/StationToolbar.js +168 -0
- package/dist/components/station-monitor/SystemOverview.d.ts +46 -0
- package/dist/components/station-monitor/SystemOverview.js +439 -0
- package/dist/components/station-monitor/Whiteboard.d.ts +10 -0
- package/dist/components/station-monitor/Whiteboard.js +67 -0
- package/dist/data/all-material-bins.d.ts +45 -0
- package/dist/data/all-material-bins.js +224 -0
- package/dist/data/chart-times.d.ts +20 -0
- package/dist/data/chart-times.js +99 -0
- package/dist/data/cost-per-piece.d.ts +32 -0
- package/dist/data/cost-per-piece.js +183 -0
- package/dist/data/current-cycles.d.ts +13 -0
- package/dist/data/current-cycles.js +144 -0
- package/dist/data/inspection-sankey.d.ts +15 -0
- package/dist/data/inspection-sankey.js +147 -0
- package/dist/data/move-arrows.d.ts +48 -0
- package/dist/data/move-arrows.js +217 -0
- package/dist/data/operators.d.ts +2 -0
- package/dist/data/operators.js +44 -0
- package/dist/data/part-summary.d.ts +17 -0
- package/dist/data/part-summary.js +107 -0
- package/dist/data/path-lookup.d.ts +13 -0
- package/dist/data/path-lookup.js +107 -0
- package/dist/data/queue-material.d.ts +46 -0
- package/dist/data/queue-material.js +256 -0
- package/dist/data/results.bufferchart.d.ts +10 -0
- package/dist/data/results.bufferchart.js +90 -0
- package/dist/data/results.completed-parts.d.ts +26 -0
- package/dist/data/results.completed-parts.js +181 -0
- package/dist/data/results.cycles.d.ts +86 -0
- package/dist/data/results.cycles.js +454 -0
- package/dist/data/results.inspection.d.ts +36 -0
- package/dist/data/results.inspection.js +188 -0
- package/dist/data/results.oee.d.ts +40 -0
- package/dist/data/results.oee.js +330 -0
- package/dist/data/results.schedules.d.ts +23 -0
- package/dist/data/results.schedules.js +157 -0
- package/dist/data/tools-programs.d.ts +78 -0
- package/dist/data/tools-programs.js +376 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +60 -0
- package/dist/network/api.d.ts +1390 -0
- package/dist/network/api.js +4971 -0
- package/dist/network/backend-mock.d.ts +11 -0
- package/dist/network/backend-mock.js +512 -0
- package/dist/network/backend.d.ts +57 -0
- package/dist/network/backend.js +77 -0
- package/dist/network/load-specific-month.d.ts +13 -0
- package/dist/network/load-specific-month.js +77 -0
- package/dist/network/server-settings.d.ts +12 -0
- package/dist/network/server-settings.js +92 -0
- package/dist/network/websocket.d.ts +4 -0
- package/dist/network/websocket.js +165 -0
- package/dist/renderer.d.ts +8 -0
- package/dist/renderer.js +55 -0
- package/dist/seedtactics-logo.d.ts +2 -0
- package/dist/seedtactics-logo.js +4 -0
- package/dist/util/chart-colors.d.ts +1 -0
- package/dist/util/chart-colors.js +116 -0
- package/dist/util/chart-helpers.d.ts +3 -0
- package/dist/util/chart-helpers.js +51 -0
- package/dist/util/parseISODuration.d.ts +4 -0
- package/dist/util/parseISODuration.js +40 -0
- package/docs/client-efficiency.md +355 -0
- package/docs/client-engineering.md +54 -0
- package/docs/client-launch.md +55 -0
- package/docs/client-operations.md +88 -0
- package/docs/client-quality.md +74 -0
- package/docs/client-sales.md +61 -0
- package/docs/client-scanners.md +41 -0
- package/docs/client-station-monitor.md +149 -0
- package/docs/client-tools-programs.md +74 -0
- package/docs/improve-fms.md +141 -0
- package/docs/makino.md +40 -0
- package/docs/material-quarantine.md +82 -0
- package/docs/material-tracking.md +236 -0
- package/docs/mazak.md +115 -0
- package/docs/niigata.md +228 -0
- package/docs/operator-procedures.md +106 -0
- package/docs/part-instructions.md +63 -0
- package/docs/screenshots/insight-all-material.png +0 -0
- package/docs/screenshots/insight-analysis-pallets.png +0 -0
- package/docs/screenshots/insight-analysis-part-completed.png +0 -0
- package/docs/screenshots/insight-analysis-sankey.png +0 -0
- package/docs/screenshots/insight-analysis-station-oee.png +0 -0
- package/docs/screenshots/insight-buffer-occupancy.png +0 -0
- package/docs/screenshots/insight-choose-analysis-month.png +0 -0
- package/docs/screenshots/insight-closeout.png +0 -0
- package/docs/screenshots/insight-cost-percentages.png +0 -0
- package/docs/screenshots/insight-dashboard.png +0 -0
- package/docs/screenshots/insight-event-custom-view.jpg +0 -0
- package/docs/screenshots/insight-event-viewer.jpg +0 -0
- package/docs/screenshots/insight-inspection.png +0 -0
- package/docs/screenshots/insight-load-station-details.png +0 -0
- package/docs/screenshots/insight-load-station.png +0 -0
- package/docs/screenshots/insight-loadcycle-graph.png +0 -0
- package/docs/screenshots/insight-loadstation-small.jpg +0 -0
- package/docs/screenshots/insight-machinecycle-graph.png +0 -0
- package/docs/screenshots/insight-machinecycle-table.png +0 -0
- package/docs/screenshots/insight-machinecycles.png +0 -0
- package/docs/screenshots/insight-machinehours.png +0 -0
- package/docs/screenshots/insight-machineoutliers.png +0 -0
- package/docs/screenshots/insight-monthly-schedules.png +0 -0
- package/docs/screenshots/insight-operations-material.png +0 -0
- package/docs/screenshots/insight-operations-overview.png +0 -0
- package/docs/screenshots/insight-operations-reports.png +0 -0
- package/docs/screenshots/insight-part-cost.png +0 -0
- package/docs/screenshots/insight-program-report.png +0 -0
- package/docs/screenshots/insight-quality-material-details.png +0 -0
- package/docs/screenshots/insight-quality-material.png +0 -0
- package/docs/screenshots/insight-quality-quarantine.png +0 -0
- package/docs/screenshots/insight-quality-sankey.png +0 -0
- package/docs/screenshots/insight-quality-similar-paths.png +0 -0
- package/docs/screenshots/insight-queue-details.png +0 -0
- package/docs/screenshots/insight-queues-jobs-table.png +0 -0
- package/docs/screenshots/insight-queues.png +0 -0
- package/docs/screenshots/insight-sim-day-usage.png +0 -0
- package/docs/screenshots/insight-station-system-overview-buttons.png +0 -0
- package/docs/screenshots/insight-station-system-overview.png +0 -0
- package/docs/screenshots/insight-system-overview.png +0 -0
- package/docs/screenshots/insight-tool-replacements.png +0 -0
- package/docs/screenshots/insight-tool-report.png +0 -0
- package/docs/screenshots/insight-toolbar-btns.png +0 -0
- package/docs/screenshots/insight-workorder-gantt.png +0 -0
- package/docs/screenshots/insight-workorders.png +0 -0
- package/docs/security.md +131 -0
- package/docs/server-config.md +56 -0
- package/docs/server-errors.md +44 -0
- package/package.json +90 -0
- package/src/index.ts +65 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Copyright (c) 2025, John Lenz
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above
|
|
12
|
+
copyright notice, this list of conditions and the following
|
|
13
|
+
disclaimer in the documentation and/or other materials provided
|
|
14
|
+
with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
17
|
+
nor the names of other contributors may be used to endorse or
|
|
18
|
+
promote products derived from this software without specific
|
|
19
|
+
prior written permission.
|
|
20
|
+
|
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
22
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
24
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
25
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
26
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
27
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
28
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
29
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
31
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
*/
|
|
33
|
+
import { LazySeq, OrderedMap, OrderedSet } from "@seedtactics/immutable-collections";
|
|
34
|
+
import { last30MaterialSummary } from "../cell-status/material-summary";
|
|
35
|
+
import { atom } from "jotai";
|
|
36
|
+
import { last30StationCycles } from "../cell-status/station-cycles";
|
|
37
|
+
import { chartRangeAtom } from "./chart-times";
|
|
38
|
+
function isAbnormal(m) {
|
|
39
|
+
if (m.closeout_completed === undefined) {
|
|
40
|
+
// no closeout has been done, so fall back to checking inspections and quarantined
|
|
41
|
+
if (LazySeq.ofObject(m.completedInspections ?? {}).some(([, insp]) => insp.success === false)) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
if (m.currently_quarantined) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return m.closeout_failed !== false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const last30PartSummaryRange = chartRangeAtom("part-summary");
|
|
54
|
+
export const last30PartSummary = atom((get) => {
|
|
55
|
+
const mats = get(last30MaterialSummary);
|
|
56
|
+
const cycles = get(last30StationCycles);
|
|
57
|
+
const range = get(last30PartSummaryRange);
|
|
58
|
+
const stationTimes = cycles
|
|
59
|
+
.valuesToLazySeq()
|
|
60
|
+
.filter((c) => (range.startDate === null || c.endTime >= range.startDate) &&
|
|
61
|
+
(range.endDate === null || c.endTime <= range.endDate))
|
|
62
|
+
.toLookupOrderedMap((c) => c.part, (c) => c.stationGroup, (c) => ({
|
|
63
|
+
isLoadUnload: c.isLabor,
|
|
64
|
+
elapsed: c.elapsedMinsPerMaterial * c.material.length,
|
|
65
|
+
active: c.activeMinutes,
|
|
66
|
+
medianElapsed: c.medianCycleMinutes,
|
|
67
|
+
}), (a, b) => ({
|
|
68
|
+
isLoadUnload: a.isLoadUnload || b.isLoadUnload,
|
|
69
|
+
elapsed: a.elapsed + b.elapsed,
|
|
70
|
+
active: a.active + b.active,
|
|
71
|
+
medianElapsed: a.medianElapsed + b.medianElapsed,
|
|
72
|
+
}));
|
|
73
|
+
return mats.matsById
|
|
74
|
+
.valuesToLazySeq()
|
|
75
|
+
.filter((m) => Boolean(m.numProcesses &&
|
|
76
|
+
m.unloaded_processes?.[m.numProcesses] &&
|
|
77
|
+
(range.startDate === null || m.unloaded_processes[m.numProcesses] >= range.startDate) &&
|
|
78
|
+
(range.endDate === null || m.unloaded_processes[m.numProcesses] <= range.endDate)))
|
|
79
|
+
.toOrderedLookup((m) => m.partName)
|
|
80
|
+
.mapValues((mats, partName) => ({
|
|
81
|
+
part: partName,
|
|
82
|
+
completedQty: mats.length,
|
|
83
|
+
abnormalQty: LazySeq.of(mats).sumBy((m) => (isAbnormal(m) ? 1 : 0)),
|
|
84
|
+
mats: mats,
|
|
85
|
+
stationMins: OrderedMap.empty(),
|
|
86
|
+
workorders: LazySeq.of(mats)
|
|
87
|
+
.toOrderedSet((m) => m.workorderId ?? "")
|
|
88
|
+
.delete(""),
|
|
89
|
+
}))
|
|
90
|
+
.adjust(stationTimes, (summary, stationTimes, partName) => {
|
|
91
|
+
if (summary) {
|
|
92
|
+
return { ...summary, stationMins: stationTimes };
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return {
|
|
96
|
+
part: partName,
|
|
97
|
+
completedQty: 0,
|
|
98
|
+
abnormalQty: 0,
|
|
99
|
+
mats: [],
|
|
100
|
+
stationMins: stationTimes,
|
|
101
|
+
workorders: OrderedSet.empty(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
.valuesToAscLazySeq()
|
|
106
|
+
.toRArray();
|
|
107
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PartAndInspType, InspectionLogsByCntr } from "../cell-status/inspections.js";
|
|
2
|
+
import { HashMap } from "@seedtactics/immutable-collections";
|
|
3
|
+
export type PathLookupLogEntries = HashMap<PartAndInspType, InspectionLogsByCntr>;
|
|
4
|
+
export interface PathLookupRange {
|
|
5
|
+
readonly part: string;
|
|
6
|
+
readonly curStart: Date;
|
|
7
|
+
readonly curEnd: Date;
|
|
8
|
+
}
|
|
9
|
+
export declare const pathLookupRange: import("jotai").PrimitiveAtom<PathLookupRange | null> & {
|
|
10
|
+
init: PathLookupRange | null;
|
|
11
|
+
};
|
|
12
|
+
export declare const inspectionLogEntries: import("jotai").Atom<PathLookupLogEntries>;
|
|
13
|
+
export declare function extendRange(numDays: number): (range: PathLookupRange | null) => PathLookupRange | null;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* Copyright (c) 2019, John Lenz
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above
|
|
12
|
+
copyright notice, this list of conditions and the following
|
|
13
|
+
disclaimer in the documentation and/or other materials provided
|
|
14
|
+
with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
17
|
+
nor the names of other contributors may be used to endorse or
|
|
18
|
+
promote products derived from this software without specific
|
|
19
|
+
prior written permission.
|
|
20
|
+
|
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
22
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
24
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
25
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
26
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
27
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
28
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
29
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
31
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
*/
|
|
33
|
+
import { LogBackend, OtherLogBackends } from "../network/backend.js";
|
|
34
|
+
import { addDays } from "date-fns";
|
|
35
|
+
import { convertLogToInspections, } from "../cell-status/inspections.js";
|
|
36
|
+
import { HashMap, LazySeq } from "@seedtactics/immutable-collections";
|
|
37
|
+
import { atom } from "jotai";
|
|
38
|
+
import { loadable } from "jotai/utils";
|
|
39
|
+
export const pathLookupRange = atom(null);
|
|
40
|
+
const localLogEntries = atom(async (get, { signal }) => {
|
|
41
|
+
const range = get(pathLookupRange);
|
|
42
|
+
if (range == null)
|
|
43
|
+
return HashMap.empty();
|
|
44
|
+
const events = await LogBackend.get(range.curStart, range.curEnd, signal);
|
|
45
|
+
return LazySeq.of(events)
|
|
46
|
+
.flatMap(convertLogToInspections)
|
|
47
|
+
.filter((e) => e.key.part === range.part)
|
|
48
|
+
.toLookupMap((e) => e.key, (e) => e.entry.cntr, (e) => e.entry);
|
|
49
|
+
});
|
|
50
|
+
const localLogLoadable = loadable(localLogEntries);
|
|
51
|
+
const otherLogEntries = atom(async (get) => {
|
|
52
|
+
const range = get(pathLookupRange);
|
|
53
|
+
if (range == null)
|
|
54
|
+
return HashMap.empty();
|
|
55
|
+
const allEvts = [];
|
|
56
|
+
for (const b of OtherLogBackends) {
|
|
57
|
+
allEvts.push(await b.get(range.curStart, range.curEnd));
|
|
58
|
+
}
|
|
59
|
+
return LazySeq.of(allEvts)
|
|
60
|
+
.flatMap((es) => es)
|
|
61
|
+
.flatMap(convertLogToInspections)
|
|
62
|
+
.filter((e) => e.key.part === range.part)
|
|
63
|
+
.toLookupMap((e) => e.key, (e) => e.entry.cntr, (e) => e.entry);
|
|
64
|
+
});
|
|
65
|
+
const otherLogLoadable = loadable(otherLogEntries);
|
|
66
|
+
export const inspectionLogEntries = atom((get) => {
|
|
67
|
+
const localEvts = get(localLogLoadable);
|
|
68
|
+
const otherEvts = get(otherLogLoadable);
|
|
69
|
+
const localData = localEvts.state === "hasData" ? localEvts.data : null;
|
|
70
|
+
const otherData = otherEvts.state === "hasData" ? otherEvts.data : null;
|
|
71
|
+
if (localData) {
|
|
72
|
+
if (!otherData) {
|
|
73
|
+
return localData;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return HashMap.union((inspsByCntr1, inspsByCntr2) => inspsByCntr1.union(inspsByCntr2), localData, otherData);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
if (otherData) {
|
|
81
|
+
return otherData;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return HashMap.empty();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
export function extendRange(numDays) {
|
|
89
|
+
return (range) => {
|
|
90
|
+
if (range === null)
|
|
91
|
+
return null;
|
|
92
|
+
if (numDays < 0) {
|
|
93
|
+
return {
|
|
94
|
+
curStart: addDays(range.curStart, numDays),
|
|
95
|
+
curEnd: range.curEnd,
|
|
96
|
+
part: range.part,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
return {
|
|
101
|
+
curStart: range.curStart,
|
|
102
|
+
curEnd: addDays(range.curEnd, numDays),
|
|
103
|
+
part: range.part,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as api from "../network/api.js";
|
|
2
|
+
export type SelectableJob = {
|
|
3
|
+
readonly jobUnique: string;
|
|
4
|
+
readonly job: Readonly<api.IJob> | null;
|
|
5
|
+
readonly workorder: string | null;
|
|
6
|
+
readonly machinedProcs: ReadonlyArray<{
|
|
7
|
+
readonly lastProc: number;
|
|
8
|
+
readonly details?: string;
|
|
9
|
+
}>;
|
|
10
|
+
};
|
|
11
|
+
export type SelectableCasting = {
|
|
12
|
+
readonly casting: string;
|
|
13
|
+
readonly message: string | null;
|
|
14
|
+
};
|
|
15
|
+
export type SelectableMaterialType = {
|
|
16
|
+
readonly castings: ReadonlyArray<SelectableCasting>;
|
|
17
|
+
readonly jobs: ReadonlyArray<SelectableJob>;
|
|
18
|
+
};
|
|
19
|
+
export declare function usePossibleNewMaterialTypes(toQueue: string | null): SelectableMaterialType;
|
|
20
|
+
export interface JobRawMaterialData {
|
|
21
|
+
readonly job: Readonly<api.IActiveJob>;
|
|
22
|
+
readonly startingTime: Date | undefined;
|
|
23
|
+
readonly rawMatName: string;
|
|
24
|
+
readonly remainingToStart: number;
|
|
25
|
+
readonly assignedRaw: number;
|
|
26
|
+
readonly availableUnassigned: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function extractJobRawMaterial(jobs: {
|
|
29
|
+
[key: string]: Readonly<api.IActiveJob>;
|
|
30
|
+
}, mats: Iterable<Readonly<api.IInProcessMaterial>>, queue: string): ReadonlyArray<JobRawMaterialData>;
|
|
31
|
+
export type MaterialList = ReadonlyArray<Readonly<api.IInProcessMaterial>>;
|
|
32
|
+
export interface QueueRawMaterialGroup {
|
|
33
|
+
readonly partOrCasting: string;
|
|
34
|
+
readonly assignedJobUnique: string | null;
|
|
35
|
+
readonly material: MaterialList;
|
|
36
|
+
}
|
|
37
|
+
export interface QueueData {
|
|
38
|
+
readonly label: string;
|
|
39
|
+
readonly free: boolean;
|
|
40
|
+
readonly rawMaterialQueue: boolean;
|
|
41
|
+
readonly inProcQueue: boolean;
|
|
42
|
+
readonly material: MaterialList;
|
|
43
|
+
readonly groupedRawMat?: ReadonlyArray<QueueRawMaterialGroup>;
|
|
44
|
+
}
|
|
45
|
+
export declare function selectQueueData(queuesToCheck: ReadonlyArray<string>, curSt: Readonly<api.ICurrentStatus>, rawMatQueues: ReadonlySet<string>, inProcQueues: ReadonlySet<string>): ReadonlyArray<QueueData>;
|
|
46
|
+
export declare function loadRawMaterialEvents(material: ReadonlyArray<Readonly<api.IInProcessMaterial>>): Promise<ReadonlyArray<Readonly<api.ILogEntry>>>;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/* Copyright (c) 2023, John Lenz
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above
|
|
12
|
+
copyright notice, this list of conditions and the following
|
|
13
|
+
disclaimer in the documentation and/or other materials provided
|
|
14
|
+
with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
17
|
+
nor the names of other contributors may be used to endorse or
|
|
18
|
+
promote products derived from this software without specific
|
|
19
|
+
prior written permission.
|
|
20
|
+
|
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
22
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
24
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
25
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
26
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
27
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
28
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
29
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
31
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
*/
|
|
33
|
+
import * as api from "../network/api.js";
|
|
34
|
+
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
35
|
+
import { LogBackend } from "../network/backend.js";
|
|
36
|
+
import { differenceInSeconds } from "date-fns";
|
|
37
|
+
import { useAtomValue } from "jotai";
|
|
38
|
+
import { currentStatus } from "../cell-status/current-status.js";
|
|
39
|
+
import { rawMaterialQueues } from "../cell-status/names.js";
|
|
40
|
+
import { barcodePotentialNewMaterial } from "../cell-status/material-details.js";
|
|
41
|
+
import { useMemo } from "react";
|
|
42
|
+
import { last30Jobs } from "../cell-status/scheduled-jobs.js";
|
|
43
|
+
function describePath(path) {
|
|
44
|
+
return `${path.palletNums && path.palletNums.length > 1
|
|
45
|
+
? "Pallets " + path.palletNums.map((p) => p.toString()).join(",")
|
|
46
|
+
: path.palletNums && path.palletNums.length == 1
|
|
47
|
+
? "Pallet " + path.palletNums[0].toString()
|
|
48
|
+
: "Pallet"}; ${path.stops.map((s) => s.stationGroup + "#" + (s.stationNums ?? []).join(",")).join("->")}`;
|
|
49
|
+
}
|
|
50
|
+
function workorderDetailForCasting(currentSt, workorderId, casting) {
|
|
51
|
+
const partNames = LazySeq.ofObject(currentSt.jobs)
|
|
52
|
+
.filter(([, j]) => j.procsAndPaths[0].paths.some((p) => p.casting === casting))
|
|
53
|
+
.toHashSet(([, j]) => j.partName);
|
|
54
|
+
const workorder = currentSt.workorders?.find((w) => w.workorderId === workorderId && (w.part === casting || partNames.has(w.part)));
|
|
55
|
+
if (!workorder)
|
|
56
|
+
return null;
|
|
57
|
+
return `Started: ${workorder.material?.length ?? 0}; Planned: ${workorder.plannedQuantity}`;
|
|
58
|
+
}
|
|
59
|
+
function possibleCastings(currentSt, barcode, toQueue) {
|
|
60
|
+
const workorder = barcode?.workorder;
|
|
61
|
+
return LazySeq.of(barcode?.possibleCastingsByQueue?.[toQueue] ?? [])
|
|
62
|
+
.map((c) => ({
|
|
63
|
+
casting: c,
|
|
64
|
+
message: workorder ? workorderDetailForCasting(currentSt, workorder, c) : null,
|
|
65
|
+
}))
|
|
66
|
+
.toSortedArray((c) => c.casting);
|
|
67
|
+
}
|
|
68
|
+
function possibleJobs(currentSt, historicJobs, barcode, toQueue) {
|
|
69
|
+
return LazySeq.of(barcode?.possibleJobsByQueue?.[toQueue] ?? [])
|
|
70
|
+
.groupBy((j) => j.jobUnique)
|
|
71
|
+
.collect(([uniq, procs]) => {
|
|
72
|
+
const job = currentSt.jobs[uniq] ?? historicJobs.get(uniq);
|
|
73
|
+
return {
|
|
74
|
+
jobUnique: uniq,
|
|
75
|
+
job: job ?? null,
|
|
76
|
+
workorder: LazySeq.of(procs)
|
|
77
|
+
.collect((p) => p.workorder)
|
|
78
|
+
.head() ?? null,
|
|
79
|
+
machinedProcs: procs.map((proc) => ({
|
|
80
|
+
lastProc: proc.lastCompletedProcess,
|
|
81
|
+
details: job?.procsAndPaths[proc.lastCompletedProcess].paths.map(describePath).join(" | ") ?? "",
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
})
|
|
85
|
+
.toSortedArray((j) => j.job?.partName ?? j.jobUnique);
|
|
86
|
+
}
|
|
87
|
+
export function usePossibleNewMaterialTypes(toQueue) {
|
|
88
|
+
const historicJobs = useAtomValue(last30Jobs);
|
|
89
|
+
const currentSt = useAtomValue(currentStatus);
|
|
90
|
+
const barcode = useAtomValue(barcodePotentialNewMaterial);
|
|
91
|
+
const rawMatQueues = useAtomValue(rawMaterialQueues);
|
|
92
|
+
return useMemo(() => {
|
|
93
|
+
if (barcode === null || toQueue === null) {
|
|
94
|
+
return { castings: [], jobs: [] };
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return {
|
|
98
|
+
castings: rawMatQueues.has(toQueue) ? possibleCastings(currentSt, barcode, toQueue) : [],
|
|
99
|
+
jobs: possibleJobs(currentSt, historicJobs, barcode, toQueue),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}, [currentSt, historicJobs, toQueue, barcode, rawMatQueues]);
|
|
103
|
+
}
|
|
104
|
+
function isMatAssignedRaw(unique, m) {
|
|
105
|
+
return (m.jobUnique === unique &&
|
|
106
|
+
m.location.type === api.LocType.InQueue &&
|
|
107
|
+
m.action.type !== api.ActionType.Loading &&
|
|
108
|
+
m.process === 0);
|
|
109
|
+
}
|
|
110
|
+
function isMatUnassignedRaw(rawMatName, m) {
|
|
111
|
+
return (m.partName === rawMatName &&
|
|
112
|
+
m.location.type === api.LocType.InQueue &&
|
|
113
|
+
m.action.type !== api.ActionType.Loading &&
|
|
114
|
+
m.process === 0 &&
|
|
115
|
+
!m.jobUnique);
|
|
116
|
+
}
|
|
117
|
+
export function extractJobRawMaterial(jobs, mats, queue) {
|
|
118
|
+
return LazySeq.ofObject(jobs)
|
|
119
|
+
.filter(([, j]) => j.remainingToStart === undefined || j.remainingToStart > 0)
|
|
120
|
+
.collect(([, j]) => {
|
|
121
|
+
const paths = (j.procsAndPaths?.[0]?.paths ?? []).filter((p) => p.inputQueue === queue);
|
|
122
|
+
if (paths.length === 0) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const rawMatName = LazySeq.of(paths)
|
|
126
|
+
.collect((path) => (path.casting && path.casting !== "" ? path.casting : undefined))
|
|
127
|
+
.head() ?? j.partName;
|
|
128
|
+
return {
|
|
129
|
+
job: j,
|
|
130
|
+
startingTime: LazySeq.of(paths)
|
|
131
|
+
.map((p) => p.simulatedStartingUTC)
|
|
132
|
+
.minBy((d) => d),
|
|
133
|
+
rawMatName: rawMatName,
|
|
134
|
+
remainingToStart: j.remainingToStart ?? 0,
|
|
135
|
+
assignedRaw: LazySeq.of(mats)
|
|
136
|
+
.filter((m) => isMatAssignedRaw(j.unique, m))
|
|
137
|
+
.length(),
|
|
138
|
+
availableUnassigned: LazySeq.of(mats)
|
|
139
|
+
.filter((m) => isMatUnassignedRaw(rawMatName, m))
|
|
140
|
+
.length(),
|
|
141
|
+
};
|
|
142
|
+
// })
|
|
143
|
+
})
|
|
144
|
+
.toSortedArray((x) => {
|
|
145
|
+
const prec = LazySeq.of(x.job.precedence?.[0] ?? []).minBy((p) => p);
|
|
146
|
+
if (!prec || prec < 0)
|
|
147
|
+
return Number.MAX_SAFE_INTEGER;
|
|
148
|
+
return prec;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function compareByQueuePos(m1, m2) {
|
|
152
|
+
return (m1.location.queuePosition ?? 10000000000) - (m2.location.queuePosition ?? 10000000000);
|
|
153
|
+
}
|
|
154
|
+
export function selectQueueData(queuesToCheck, curSt, rawMatQueues, inProcQueues) {
|
|
155
|
+
const queues = [];
|
|
156
|
+
const queueNames = [...queuesToCheck];
|
|
157
|
+
queueNames.sort((a, b) => a.localeCompare(b));
|
|
158
|
+
for (const queueName of queueNames) {
|
|
159
|
+
const isRawMat = rawMatQueues.has(queueName);
|
|
160
|
+
if (isRawMat) {
|
|
161
|
+
const material = [];
|
|
162
|
+
const matByPartThenUniq = new Map();
|
|
163
|
+
for (const m of curSt.material) {
|
|
164
|
+
if (m.location.type === api.LocType.InQueue && m.location.currentQueue === queueName) {
|
|
165
|
+
if ((m.serial && m.serial !== "") || m.action.type !== api.ActionType.Waiting) {
|
|
166
|
+
material.push(m);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
let matsForPart = matByPartThenUniq.get(m.partName);
|
|
170
|
+
if (!matsForPart) {
|
|
171
|
+
matsForPart = new Map();
|
|
172
|
+
matByPartThenUniq.set(m.partName, matsForPart);
|
|
173
|
+
}
|
|
174
|
+
const uniq = m.jobUnique || null;
|
|
175
|
+
const matsForJob = matsForPart.get(uniq);
|
|
176
|
+
if (matsForJob) {
|
|
177
|
+
matsForJob.push(m);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
matsForPart.set(uniq, [m]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const matGroups = [];
|
|
186
|
+
for (const [partName, matsForPart] of matByPartThenUniq) {
|
|
187
|
+
for (const [uniq, mats] of matsForPart) {
|
|
188
|
+
matGroups.push({
|
|
189
|
+
partOrCasting: partName,
|
|
190
|
+
assignedJobUnique: uniq,
|
|
191
|
+
material: mats,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
matGroups.sort((x, y) => {
|
|
196
|
+
const c1 = x.partOrCasting.localeCompare(y.partOrCasting);
|
|
197
|
+
if (c1 === 0) {
|
|
198
|
+
return (x.assignedJobUnique || "").localeCompare(y.assignedJobUnique || "");
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
return c1;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
queues.push({
|
|
205
|
+
label: queueName,
|
|
206
|
+
free: false,
|
|
207
|
+
rawMaterialQueue: true,
|
|
208
|
+
inProcQueue: false,
|
|
209
|
+
material: material.sort(compareByQueuePos),
|
|
210
|
+
groupedRawMat: matGroups,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
queues.push({
|
|
215
|
+
label: queueName,
|
|
216
|
+
free: false,
|
|
217
|
+
rawMaterialQueue: false,
|
|
218
|
+
inProcQueue: inProcQueues.has(queueName),
|
|
219
|
+
material: curSt.material
|
|
220
|
+
.filter((m) => m.location.type === api.LocType.InQueue && m.location.currentQueue === queueName)
|
|
221
|
+
.sort(compareByQueuePos),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return queues;
|
|
226
|
+
}
|
|
227
|
+
export async function loadRawMaterialEvents(material) {
|
|
228
|
+
const events = [];
|
|
229
|
+
for (const chunk of LazySeq.of(material).chunk(15)) {
|
|
230
|
+
events.push(...(await LogBackend.logForMaterials(chunk.map((m) => m.materialID))));
|
|
231
|
+
}
|
|
232
|
+
events.sort((a, b) => a.endUTC.getTime() - b.endUTC.getTime());
|
|
233
|
+
const groupedEvents = [];
|
|
234
|
+
for (let i = 0; i < events.length; i++) {
|
|
235
|
+
const evt = events[i];
|
|
236
|
+
if (evt.type === api.LogType.AddToQueue || evt.type === api.LogType.RemoveFromQueue) {
|
|
237
|
+
const material = [...evt.material];
|
|
238
|
+
while (i + 1 < events.length &&
|
|
239
|
+
events[i + 1].type === evt.type &&
|
|
240
|
+
differenceInSeconds(events[i + 1].endUTC, evt.endUTC) < 10) {
|
|
241
|
+
material.push(...events[i + 1].material);
|
|
242
|
+
i += 1;
|
|
243
|
+
}
|
|
244
|
+
if (material.length === evt.material.length) {
|
|
245
|
+
groupedEvents.push(evt);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
groupedEvents.push({ ...evt, material: material });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
groupedEvents.push(events[i]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return groupedEvents;
|
|
256
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BufferEntry } from "../cell-status/buffers.js";
|
|
2
|
+
export interface BufferChartPoint {
|
|
3
|
+
readonly x: Date;
|
|
4
|
+
readonly y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface BufferChartSeries {
|
|
7
|
+
readonly label: string;
|
|
8
|
+
readonly points: ReadonlyArray<BufferChartPoint>;
|
|
9
|
+
}
|
|
10
|
+
export declare function buildBufferChart(start: Date, end: Date, movingAverageDistanceInHours: number, rawMatQueues: ReadonlySet<string>, entries: Iterable<BufferEntry>): ReadonlyArray<BufferChartSeries>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* Copyright (c) 2020, John Lenz
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
* Redistributions of source code must retain the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
* Redistributions in binary form must reproduce the above
|
|
12
|
+
copyright notice, this list of conditions and the following
|
|
13
|
+
disclaimer in the documentation and/or other materials provided
|
|
14
|
+
with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
17
|
+
nor the names of other contributors may be used to endorse or
|
|
18
|
+
promote products derived from this software without specific
|
|
19
|
+
prior written permission.
|
|
20
|
+
|
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
22
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
24
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
25
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
26
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
27
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
28
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
29
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
31
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
32
|
+
*/
|
|
33
|
+
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
34
|
+
function bufferSeriesLabel(ty) {
|
|
35
|
+
switch (ty.type) {
|
|
36
|
+
case "Queue":
|
|
37
|
+
return ty.queue;
|
|
38
|
+
case "Rotary":
|
|
39
|
+
return "Rotary " + ty.machineGroup + " #" + ty.machineNum.toString();
|
|
40
|
+
case "StockerWaitForMC":
|
|
41
|
+
return "Stocker[Waiting For Machining]";
|
|
42
|
+
case "StockerWaitForUnload":
|
|
43
|
+
return "Stocker[Waiting For Unload]";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const numPoints = 30 * 5;
|
|
47
|
+
function addEntryToPoint(movingAverageDistanceInMilliseconds, point, entry) {
|
|
48
|
+
const startT = Math.max(point.x.getTime() - movingAverageDistanceInMilliseconds, entry.endTime.getTime() - entry.elapsedSeconds * 1000);
|
|
49
|
+
const endT = Math.min(point.x.getTime() + movingAverageDistanceInMilliseconds, entry.endTime.getTime());
|
|
50
|
+
point.y += ((endT - startT) / (2 * movingAverageDistanceInMilliseconds)) * entry.numMaterial;
|
|
51
|
+
}
|
|
52
|
+
function calcPoints(absoluteStart, absoluteEnd, movingAverageDistanceInMilliseconds, entries) {
|
|
53
|
+
// the actual start and end is inward from the start and end by the moving average distance
|
|
54
|
+
const start = new Date(absoluteStart.getTime() + movingAverageDistanceInMilliseconds);
|
|
55
|
+
const end = new Date(absoluteEnd.getTime() - movingAverageDistanceInMilliseconds);
|
|
56
|
+
const gap = (end.getTime() - start.getTime()) / (numPoints - 1);
|
|
57
|
+
const points = [];
|
|
58
|
+
// initialize all points to 0
|
|
59
|
+
for (let i = 0; i < numPoints - 1; i++) {
|
|
60
|
+
points.push({
|
|
61
|
+
x: new Date(start.getTime() + i * gap),
|
|
62
|
+
y: 0,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
points.push({ x: end, y: 0 });
|
|
66
|
+
// add times
|
|
67
|
+
for (const e of entries) {
|
|
68
|
+
const startIdx = Math.max(0, Math.ceil((e.endTime.getTime() -
|
|
69
|
+
e.elapsedSeconds * 1000 -
|
|
70
|
+
movingAverageDistanceInMilliseconds -
|
|
71
|
+
start.getTime()) /
|
|
72
|
+
gap));
|
|
73
|
+
const endIdx = Math.min(numPoints - 1, Math.floor((e.endTime.getTime() + movingAverageDistanceInMilliseconds - start.getTime()) / gap));
|
|
74
|
+
for (let i = startIdx; i <= endIdx; i++) {
|
|
75
|
+
addEntryToPoint(movingAverageDistanceInMilliseconds, points[i], e);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return points;
|
|
79
|
+
}
|
|
80
|
+
export function buildBufferChart(start, end, movingAverageDistanceInHours, rawMatQueues, entries) {
|
|
81
|
+
const movingAverageDistanceInMilliseconds = movingAverageDistanceInHours * 60 * 60 * 1000;
|
|
82
|
+
return LazySeq.of(entries)
|
|
83
|
+
.filter((e) => e.buffer.type !== "Queue" || !rawMatQueues.has(e.buffer.queue))
|
|
84
|
+
.groupBy((v) => bufferSeriesLabel(v.buffer))
|
|
85
|
+
.map(([k, points]) => ({
|
|
86
|
+
label: k,
|
|
87
|
+
points: calcPoints(start, end, movingAverageDistanceInMilliseconds, points),
|
|
88
|
+
}))
|
|
89
|
+
.toSortedArray((a) => a.label);
|
|
90
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MaterialSummaryAndCompletedData } from "../cell-status/material-summary.js";
|
|
2
|
+
import { SimPartCompleted } from "../cell-status/sim-production.js";
|
|
3
|
+
import { PartCycleData } from "../cell-status/station-cycles.js";
|
|
4
|
+
import { HashMap } from "@seedtactics/immutable-collections";
|
|
5
|
+
declare class DayAndPart {
|
|
6
|
+
day: Date;
|
|
7
|
+
part: string;
|
|
8
|
+
constructor(day: Date, part: string);
|
|
9
|
+
compare(other: DayAndPart): number;
|
|
10
|
+
hash(): number;
|
|
11
|
+
toString(): string;
|
|
12
|
+
adjustDay(f: (d: Date) => Date): DayAndPart;
|
|
13
|
+
}
|
|
14
|
+
export interface PartsCompletedSummary {
|
|
15
|
+
readonly count: number;
|
|
16
|
+
readonly activeMachineMins: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function binCyclesByDayAndPart(cycles: Iterable<PartCycleData>, matsById: HashMap<number, MaterialSummaryAndCompletedData>, start: Date, end: Date): HashMap<DayAndPart, PartsCompletedSummary>;
|
|
19
|
+
export declare function binSimProductionByDayAndPart(prod: Iterable<SimPartCompleted>): HashMap<DayAndPart, PartsCompletedSummary>;
|
|
20
|
+
interface HeatmapClipboardPoint {
|
|
21
|
+
readonly x: Date;
|
|
22
|
+
readonly y: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildCompletedPartsHeatmapTable(points: ReadonlyArray<HeatmapClipboardPoint & PartsCompletedSummary>): string;
|
|
25
|
+
export declare function copyCompletedPartsHeatmapToClipboard(points: ReadonlyArray<HeatmapClipboardPoint & PartsCompletedSummary>): void;
|
|
26
|
+
export {};
|