@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,173 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/* Copyright (c) 2025, John Lenz
|
|
3
|
+
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above
|
|
13
|
+
copyright notice, this list of conditions and the following
|
|
14
|
+
disclaimer in the documentation and/or other materials provided
|
|
15
|
+
with the distribution.
|
|
16
|
+
|
|
17
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
18
|
+
nor the names of other contributors may be used to endorse or
|
|
19
|
+
promote products derived from this software without specific
|
|
20
|
+
prior written permission.
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
23
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
25
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
26
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
27
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
28
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
29
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
30
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
31
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
32
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
*/
|
|
34
|
+
import { memo, useMemo } from "react";
|
|
35
|
+
import { Box, Grid, IconButton, Table, Tooltip as MuiTooltip, Select, MenuItem, Typography, FormControl, } from "@mui/material";
|
|
36
|
+
import { DataTableHead, DataTableBody, useColSort } from "../analysis/DataTable.js";
|
|
37
|
+
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
38
|
+
import { buildOeeSeries, copyOeeToClipboard, } from "../../data/results.oee.js";
|
|
39
|
+
import { seriesColor } from "../../util/chart-colors.js";
|
|
40
|
+
import { addDays, startOfToday } from "date-fns";
|
|
41
|
+
import { last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
42
|
+
import { last30SimStationUse } from "../../cell-status/sim-station-use.js";
|
|
43
|
+
import { ImportExport } from "@mui/icons-material";
|
|
44
|
+
import { useSetTitle } from "../routes.js";
|
|
45
|
+
import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
46
|
+
import { scaleBand, scaleLinear } from "d3-scale";
|
|
47
|
+
import { AxisBottom, AxisLeft, GridRows } from "../AxisAndGrid.js";
|
|
48
|
+
import { ChartWithTooltip } from "../ChartTooltip.js";
|
|
49
|
+
import { localPoint } from "../../util/chart-helpers.js";
|
|
50
|
+
const actualOeeColor = seriesColor(0, 2);
|
|
51
|
+
const plannedOeeColor = seriesColor(1, 2);
|
|
52
|
+
const marginLeft = 50;
|
|
53
|
+
const marginBottom = 30;
|
|
54
|
+
const marginTop = 10;
|
|
55
|
+
const marginRight = 10;
|
|
56
|
+
function BarChart({ width, height, points, setTooltip, }) {
|
|
57
|
+
const yMax = height - marginTop - marginBottom;
|
|
58
|
+
const hourScale = useMemo(() => scaleLinear().domain([0, 24]).range([yMax, 0]), [yMax]);
|
|
59
|
+
const dateScale = useMemo(() => scaleBand()
|
|
60
|
+
.domain(LazySeq.of(points)
|
|
61
|
+
.map((p) => p.x)
|
|
62
|
+
.distinct())
|
|
63
|
+
.range([0, width - marginLeft - marginRight])
|
|
64
|
+
.padding(0.1), [points, width]);
|
|
65
|
+
const actualPlanningScale = useMemo(() => scaleBand().domain(["Actual", "Planned"]).range([0, dateScale.bandwidth()]).padding(0.05), [dateScale]);
|
|
66
|
+
return (_jsx("svg", { width: width, height: height, children: _jsxs("g", { transform: `translate(${marginLeft},${marginTop})`, children: [_jsx(AxisBottom, { scale: dateScale, top: yMax }), _jsx(AxisLeft, { scale: hourScale, left: 0, label: "Hours" }), _jsx(GridRows, { scale: hourScale, width: width - marginLeft - marginRight }), points.map((p, i) => (_jsxs("g", { transform: `translate(${dateScale(p.x)},0)`, children: [_jsx("rect", { x: actualPlanningScale("Actual"), y: hourScale(p.y), width: actualPlanningScale.bandwidth(), height: yMax - hourScale(p.y), fill: actualOeeColor, onMouseEnter: (e) => {
|
|
67
|
+
const pt = localPoint(e);
|
|
68
|
+
setTooltip({
|
|
69
|
+
left: pt?.x ?? 0,
|
|
70
|
+
top: pt?.y ?? 0,
|
|
71
|
+
datum: p,
|
|
72
|
+
});
|
|
73
|
+
}, onMouseLeave: () => setTooltip(null) }), _jsx("rect", { x: actualPlanningScale("Planned"), y: hourScale(p.plannedHours), width: actualPlanningScale.bandwidth(), height: yMax - hourScale(p.plannedHours), fill: plannedOeeColor, onMouseEnter: (e) => {
|
|
74
|
+
const pt = localPoint(e);
|
|
75
|
+
setTooltip({
|
|
76
|
+
left: pt?.x ?? 0,
|
|
77
|
+
top: pt?.y ?? 0,
|
|
78
|
+
datum: p,
|
|
79
|
+
});
|
|
80
|
+
}, onMouseLeave: () => setTooltip(null) })] }, i)))] }) }));
|
|
81
|
+
}
|
|
82
|
+
function OEELegend({ station }) {
|
|
83
|
+
return (_jsxs("div", { style: { marginTop: "1em", display: "flex", flexWrap: "wrap", justifyContent: "space-evenly" }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [_jsx("div", { style: { width: "14px", height: "14px", backgroundColor: actualOeeColor } }), _jsxs("div", { style: { marginLeft: "1em" }, children: [station, " Actual"] })] }), _jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [_jsx("div", { style: { width: "14px", height: "14px", backgroundColor: plannedOeeColor } }), _jsxs("div", { style: { marginLeft: "1em" }, children: [station, " Planned"] })] })] }));
|
|
84
|
+
}
|
|
85
|
+
function OEETooltip({ tooltip }) {
|
|
86
|
+
return (_jsxs("div", { children: [_jsx("div", { children: tooltip.datum.x }), _jsxs("div", { children: ["Actual Hours: ", tooltip.datum.y?.toFixed(1)] }), _jsxs("div", { children: ["Planned Hours: ", tooltip.datum?.plannedHours?.toFixed(1)] })] }));
|
|
87
|
+
}
|
|
88
|
+
function OEESeries({ series }) {
|
|
89
|
+
const tooltipAtom = useMemo(() => atom(null), []);
|
|
90
|
+
const setTooltip = useSetAtom(tooltipAtom);
|
|
91
|
+
return (_jsxs(Grid, { size: { xs: 12, md: 6 }, onMouseLeave: () => setTooltip(null), children: [_jsx(ChartWithTooltip, { sx: { height: "calc(100vh / 2 - 200px)" }, chart: ({ width, height }) => (_jsx(BarChart, { width: width, height: height, points: series.points, setTooltip: setTooltip })), tooltipAtom: tooltipAtom, TooltipContent: OEETooltip }), _jsx(OEELegend, { station: series.station })] }));
|
|
92
|
+
}
|
|
93
|
+
export function OEEChart({ points }) {
|
|
94
|
+
return (_jsx(Grid, { container: true, children: points.map((series, idx) => (_jsx(OEESeries, { series: series }, idx))) }));
|
|
95
|
+
}
|
|
96
|
+
var ColumnId;
|
|
97
|
+
(function (ColumnId) {
|
|
98
|
+
ColumnId[ColumnId["Date"] = 0] = "Date";
|
|
99
|
+
ColumnId[ColumnId["Station"] = 1] = "Station";
|
|
100
|
+
ColumnId[ColumnId["ActualHours"] = 2] = "ActualHours";
|
|
101
|
+
ColumnId[ColumnId["ActualOEE"] = 3] = "ActualOEE";
|
|
102
|
+
ColumnId[ColumnId["PlannedHours"] = 4] = "PlannedHours";
|
|
103
|
+
ColumnId[ColumnId["PlannedOEE"] = 5] = "PlannedOEE";
|
|
104
|
+
})(ColumnId || (ColumnId = {}));
|
|
105
|
+
const columns = [
|
|
106
|
+
{
|
|
107
|
+
id: ColumnId.Date,
|
|
108
|
+
numeric: false,
|
|
109
|
+
label: "Date",
|
|
110
|
+
getDisplay: (c) => c.x,
|
|
111
|
+
getForSort: (c) => c.day.getTime(),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: ColumnId.Station,
|
|
115
|
+
numeric: false,
|
|
116
|
+
label: "Station",
|
|
117
|
+
getDisplay: (c) => c.station,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: ColumnId.ActualHours,
|
|
121
|
+
numeric: true,
|
|
122
|
+
label: "Actual Hours",
|
|
123
|
+
getDisplay: (c) => c.y.toFixed(1),
|
|
124
|
+
getForSort: (c) => c.y,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: ColumnId.ActualOEE,
|
|
128
|
+
numeric: true,
|
|
129
|
+
label: "Actual OEE",
|
|
130
|
+
getDisplay: (c) => (c.actualOee * 100).toFixed(0) + "%",
|
|
131
|
+
getForSort: (c) => c.actualOee,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: ColumnId.PlannedHours,
|
|
135
|
+
numeric: true,
|
|
136
|
+
label: "Planned Hours",
|
|
137
|
+
getDisplay: (c) => c.plannedHours.toFixed(1),
|
|
138
|
+
getForSort: (c) => c.plannedHours,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: ColumnId.PlannedOEE,
|
|
142
|
+
numeric: true,
|
|
143
|
+
label: "Planned OEE",
|
|
144
|
+
getDisplay: (c) => (c.plannedOee * 100).toFixed(0) + "%",
|
|
145
|
+
getForSort: (c) => c.plannedOee,
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
function dataForTable(series, sortOn) {
|
|
149
|
+
return LazySeq.of(series)
|
|
150
|
+
.flatMap((e) => e.points)
|
|
151
|
+
.toSortedArray(sortOn);
|
|
152
|
+
}
|
|
153
|
+
export const OEETable = memo(function OEETableF({ points }) {
|
|
154
|
+
const sort = useColSort(ColumnId.Date, columns);
|
|
155
|
+
return (_jsxs(Table, { children: [_jsx(DataTableHead, { columns: columns, sort: sort, showDetailsCol: false }), _jsx(DataTableBody, { columns: columns, pageData: dataForTable(points, sort.sortOn) })] }));
|
|
156
|
+
});
|
|
157
|
+
const lulShowChart = atom(true);
|
|
158
|
+
const mcShowChart = atom(true);
|
|
159
|
+
export function StationOEEPage({ ty }) {
|
|
160
|
+
useSetTitle(ty === "labor" ? "L/U OEE" : "Machine OEE");
|
|
161
|
+
const [showChart, setShowChart] = useAtom(ty === "labor" ? lulShowChart : mcShowChart);
|
|
162
|
+
const start = addDays(startOfToday(), -6);
|
|
163
|
+
const end = addDays(startOfToday(), 1);
|
|
164
|
+
const cycles = useAtomValue(last30StationCycles);
|
|
165
|
+
const statUse = useAtomValue(last30SimStationUse);
|
|
166
|
+
const points = useMemo(() => buildOeeSeries(start, end, ty, cycles.valuesToLazySeq(), statUse), [start, end, ty, cycles, statUse]);
|
|
167
|
+
return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsxs(Box, { component: "nav", sx: {
|
|
168
|
+
display: "flex",
|
|
169
|
+
minHeight: "2.5em",
|
|
170
|
+
alignItems: "center",
|
|
171
|
+
maxWidth: "calc(100vw - 24px - 24px)",
|
|
172
|
+
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [ty === "labor" ? "Load/Unload" : "Machine", " OEE: comparing flexplan hours between actual and simulated production"] }), _jsx(Box, { flexGrow: 1 }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: showChart ? "chart" : "table", onChange: (e) => setShowChart(e.target.value === "chart"), children: [_jsx(MenuItem, { value: "chart", children: "Chart" }, "chart"), _jsx(MenuItem, { value: "table", children: "Table" }, "table")] }) }), _jsx(MuiTooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, onClick: () => copyOeeToClipboard(points), size: "large", children: _jsx(ImportExport, {}) }) })] }), _jsx("main", { children: showChart ? _jsx(OEEChart, { points: points }) : _jsx(OEETable, { points: points }) })] }));
|
|
173
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/* Copyright (c) 2023, John Lenz
|
|
3
|
+
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above
|
|
13
|
+
copyright notice, this list of conditions and the following
|
|
14
|
+
disclaimer in the documentation and/or other materials provided
|
|
15
|
+
with the distribution.
|
|
16
|
+
|
|
17
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
18
|
+
nor the names of other contributors may be used to endorse or
|
|
19
|
+
promote products derived from this software without specific
|
|
20
|
+
prior written permission.
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
23
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
25
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
26
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
27
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
28
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
29
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
30
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
31
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
32
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
*/
|
|
34
|
+
import { useMemo } from "react";
|
|
35
|
+
import { Box, Typography } from "@mui/material";
|
|
36
|
+
import { addDays, startOfToday } from "date-fns";
|
|
37
|
+
import { Tooltip } from "@mui/material";
|
|
38
|
+
import { IconButton } from "@mui/material";
|
|
39
|
+
import { ImportExport } from "@mui/icons-material";
|
|
40
|
+
import StationDataTable from "../analysis/StationDataTable.js";
|
|
41
|
+
import { copyCyclesToClipboard } from "../../data/results.cycles.js";
|
|
42
|
+
import { last30MaterialSummary } from "../../cell-status/material-summary.js";
|
|
43
|
+
import { last30StationCycles } from "../../cell-status/station-cycles.js";
|
|
44
|
+
import { useSetTitle } from "../routes.js";
|
|
45
|
+
import { useAtomValue } from "jotai";
|
|
46
|
+
export function OutlierCycles({ outlierTy }) {
|
|
47
|
+
useSetTitle(outlierTy === "machine" ? "Machine Outliers" : "L/U Outliers");
|
|
48
|
+
const matSummary = useAtomValue(last30MaterialSummary);
|
|
49
|
+
const today = startOfToday();
|
|
50
|
+
const allCycles = useAtomValue(last30StationCycles);
|
|
51
|
+
const points = useMemo(() => {
|
|
52
|
+
const today = startOfToday();
|
|
53
|
+
const start = addDays(today, -4);
|
|
54
|
+
const end = addDays(today, 1);
|
|
55
|
+
return {
|
|
56
|
+
seriesLabel: "Part",
|
|
57
|
+
data: allCycles
|
|
58
|
+
.valuesToLazySeq()
|
|
59
|
+
.filter((c) => c.isOutlier && c.endTime >= start && c.endTime < end && c.isLabor === (outlierTy === "labor"))
|
|
60
|
+
.toRLookup((e) => e.part + "-" + e.material[0].proc.toString()),
|
|
61
|
+
};
|
|
62
|
+
}, [outlierTy, allCycles]);
|
|
63
|
+
return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsxs(Box, { component: "nav", sx: {
|
|
64
|
+
display: "flex",
|
|
65
|
+
minHeight: "2.5em",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
maxWidth: "calc(100vw - 24px - 24px)",
|
|
68
|
+
}, children: [_jsxs(Typography, { variant: "subtitle1", children: [outlierTy === "labor" ? "Load/Unload" : "Machine", " cycles from the past 5 days statistically outside expected range"] }), _jsx(Box, { flexGrow: 1 }), _jsx(Tooltip, { title: "Copy to Clipboard", children: _jsx(IconButton, { style: { height: "25px", paddingTop: 0, paddingBottom: 0 }, onClick: () => copyCyclesToClipboard(points, matSummary.matsById, undefined), size: "large", children: _jsx(ImportExport, {}) }) })] }), _jsx("main", { children: _jsx(StationDataTable, { points: points.data, matsById: matSummary.matsById, current_date_zoom: { start: addDays(today, -4), end: addDays(today, 1) }, set_date_zoom_range: undefined, period: { type: "Last30" }, showWorkorderAndInspect: false, defaultSortDesc: true }) })] }));
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
4
|
+
import hljs from "highlight.js/lib/core";
|
|
5
|
+
import gcode from "highlight.js/lib/languages/gcode";
|
|
6
|
+
hljs.registerLanguage("gcode", gcode);
|
|
7
|
+
self.onmessage = function (event) {
|
|
8
|
+
self.postMessage(hljs.highlight(event.data, { language: "gcode" }).value);
|
|
9
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export declare function ProgramSummaryTable(): ReactNode;
|
|
3
|
+
export declare function ProgramContentDialog(): ReactNode;
|
|
4
|
+
export declare function ProgramHistoryDialog(): ReactNode;
|
|
5
|
+
export declare function ProgramReportPage(): ReactNode;
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/* Copyright (c) 2020, John Lenz
|
|
3
|
+
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above
|
|
13
|
+
copyright notice, this list of conditions and the following
|
|
14
|
+
disclaimer in the documentation and/or other materials provided
|
|
15
|
+
with the distribution.
|
|
16
|
+
|
|
17
|
+
* Neither the name of John Lenz, Black Maple Software, SeedTactics,
|
|
18
|
+
nor the names of other contributors may be used to endorse or
|
|
19
|
+
promote products derived from this software without specific
|
|
20
|
+
prior written permission.
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
23
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
25
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
26
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
27
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
28
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
29
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
30
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
31
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
32
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
*/
|
|
34
|
+
import { useState, useMemo, useEffect } from "react";
|
|
35
|
+
import { Box, Fab, FormControl, styled } from "@mui/material";
|
|
36
|
+
import { CircularProgress } from "@mui/material";
|
|
37
|
+
import { Card } from "@mui/material";
|
|
38
|
+
import { CardContent } from "@mui/material";
|
|
39
|
+
import TimeAgo from "react-timeago";
|
|
40
|
+
import { Table } from "@mui/material";
|
|
41
|
+
import { TableHead } from "@mui/material";
|
|
42
|
+
import { TableCell } from "@mui/material";
|
|
43
|
+
import { TableRow } from "@mui/material";
|
|
44
|
+
import { TableSortLabel } from "@mui/material";
|
|
45
|
+
import { Typography } from "@mui/material";
|
|
46
|
+
import { Tooltip } from "@mui/material";
|
|
47
|
+
import { KeyboardArrowDown as KeyboardArrowDownIcon, KeyboardArrowUp as KeyboardArrowUpIcon, FirstPage as FirstPageIcon, KeyboardArrowLeft, KeyboardArrowRight, History as HistoryIcon, Refresh as RefreshIcon, Code as CodeIcon, } from "@mui/icons-material";
|
|
48
|
+
import { programReportRefreshTime, currentProgramReport, programToShowContent, programContent, programToShowHistory, programFilter, } from "../../data/tools-programs.js";
|
|
49
|
+
import { TableBody } from "@mui/material";
|
|
50
|
+
import { IconButton } from "@mui/material";
|
|
51
|
+
import { Collapse } from "@mui/material";
|
|
52
|
+
import { LazySeq } from "@seedtactics/immutable-collections";
|
|
53
|
+
import { PartIdenticon } from "../station-monitor/Material.js";
|
|
54
|
+
import { Dialog } from "@mui/material";
|
|
55
|
+
import { DialogContent } from "@mui/material";
|
|
56
|
+
import { DialogTitle } from "@mui/material";
|
|
57
|
+
import { Button } from "@mui/material";
|
|
58
|
+
import { DialogActions } from "@mui/material";
|
|
59
|
+
import { useIsDemo, useSetTitle } from "../routes.js";
|
|
60
|
+
import { DisplayLoadingAndError } from "../ErrorsAndLoading.js";
|
|
61
|
+
import { MachineBackend } from "../../network/backend.js";
|
|
62
|
+
import { Select } from "@mui/material";
|
|
63
|
+
import { MenuItem } from "@mui/material";
|
|
64
|
+
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
65
|
+
const ProgramTableRow = styled(TableRow)(() => ({
|
|
66
|
+
"& > *": {
|
|
67
|
+
borderBottom: "unset",
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
function programFilename(program) {
|
|
71
|
+
if (program.length === 0)
|
|
72
|
+
return "";
|
|
73
|
+
const idx = program.lastIndexOf("\\");
|
|
74
|
+
if (idx >= 0 && idx < program.length - 2) {
|
|
75
|
+
return program.substr(idx + 1);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return program;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const numFormat = new Intl.NumberFormat("en-US", {
|
|
82
|
+
maximumFractionDigits: 2,
|
|
83
|
+
});
|
|
84
|
+
function ProgramRow(props) {
|
|
85
|
+
const [open, setOpen] = useState(false);
|
|
86
|
+
const setProgramToShowContent = useSetAtom(programToShowContent);
|
|
87
|
+
const setProgramToShowHistory = useSetAtom(programToShowHistory);
|
|
88
|
+
const numCols = 8 + (props.showCellCtrlCol ? 1 : 0) + (props.showRevCol ? 1 : 0);
|
|
89
|
+
const toolsHaveTime = props.program.toolUse !== null &&
|
|
90
|
+
props.program.toolUse.tools.length > 0 &&
|
|
91
|
+
LazySeq.of(props.program.toolUse.tools).some((t) => t.cycleUsageMinutes > 0);
|
|
92
|
+
const toolsHaveCnt = props.program.toolUse !== null &&
|
|
93
|
+
props.program.toolUse.tools.length > 0 &&
|
|
94
|
+
LazySeq.of(props.program.toolUse.tools).some((t) => t.cycleUsageCnt > 0);
|
|
95
|
+
return (_jsxs(_Fragment, { children: [_jsxs(ProgramTableRow, { children: [_jsx(TableCell, { children: props.program.toolUse === null || props.program.toolUse.tools.length === 0 ? undefined : (_jsx(IconButton, { size: "small", onClick: () => setOpen(!open), children: open ? _jsx(KeyboardArrowUpIcon, {}) : _jsx(KeyboardArrowDownIcon, {}) })) }), _jsx(TableCell, { children: programFilename(props.program.programName) }), props.showCellCtrlCol ? _jsx(TableCell, { children: props.program.cellControllerProgramName }) : undefined, _jsx(TableCell, { children: props.program.partName !== null ? (_jsxs(Box, { sx: {
|
|
96
|
+
display: "flex",
|
|
97
|
+
alignItems: "center",
|
|
98
|
+
}, children: [_jsx(PartIdenticon, { part: props.program.partName, size: 20 }), _jsx("span", { children: props.program.partName })] })) : undefined }), _jsx(TableCell, { children: props.program.comment ?? "" }), props.showRevCol ? (_jsx(TableCell, { children: props.program.revision === null ? "" : props.program.revision.toFixed() })) : undefined, _jsx(TableCell, { align: "right", children: props.program.statisticalCycleTime === null
|
|
99
|
+
? ""
|
|
100
|
+
: props.program.statisticalCycleTime.medianMinutesForSingleMat.toFixed(2) }), _jsx(TableCell, { align: "right", children: props.program.statisticalCycleTime === null
|
|
101
|
+
? ""
|
|
102
|
+
: props.program.statisticalCycleTime.MAD_aboveMinutes.toFixed(2) }), _jsx(TableCell, { align: "right", children: props.program.statisticalCycleTime === null
|
|
103
|
+
? ""
|
|
104
|
+
: props.program.statisticalCycleTime.MAD_belowMinutes.toFixed(2) }), _jsx(TableCell, { align: "right", children: props.program.plannedMins === null ? "" : numFormat.format(props.program.plannedMins) }), _jsxs(TableCell, { children: [_jsx(Tooltip, { title: "Load Program Content", children: _jsx(IconButton, { size: "small", onClick: () => setProgramToShowContent(props.program), children: _jsx(CodeIcon, {}) }) }), props.program.revision !== null ? (_jsx(Tooltip, { title: "Revision History", children: _jsx(IconButton, { size: "small", onClick: () => setProgramToShowHistory(props.program), children: _jsx(HistoryIcon, {}) }) })) : undefined] })] }), _jsx(TableRow, { children: _jsx(TableCell, { sx: { pb: "0", pt: "0" }, colSpan: numCols, children: _jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: _jsx(Box, { sx: { mr: "1em", ml: "3em" }, children: props.program.toolUse === null || props.program.toolUse.tools.length === 0 ? undefined : (_jsxs(Table, { size: "small", sx: {
|
|
105
|
+
width: "auto",
|
|
106
|
+
ml: "10em",
|
|
107
|
+
mr: "1em",
|
|
108
|
+
}, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Tool" }), toolsHaveTime ? _jsx(TableCell, { align: "right", children: "Estimated Usage (min)" }) : undefined, toolsHaveCnt ? (_jsx(TableCell, { align: "right", children: "Estimated Usage (count)" })) : undefined] }) }), _jsx(TableBody, { children: LazySeq.of(props.program.toolUse.tools).map((t, idx) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: t.toolName }), toolsHaveTime ? (_jsx(TableCell, { align: "right", children: t.cycleUsageMinutes === 0 ? "" : t.cycleUsageMinutes.toFixed(1) })) : undefined, toolsHaveCnt ? (_jsx(TableCell, { align: "right", children: t.cycleUsageCnt === 0 ? "" : t.cycleUsageCnt.toFixed(1) })) : undefined] }, idx))) })] })) }) }) }) })] }));
|
|
109
|
+
}
|
|
110
|
+
export function ProgramSummaryTable() {
|
|
111
|
+
const report = useAtomValue(currentProgramReport);
|
|
112
|
+
const [sortCol, setSortCol] = useState("ProgramName");
|
|
113
|
+
const [sortDir, setSortDir] = useState("asc");
|
|
114
|
+
if (report === null) {
|
|
115
|
+
return _jsx("div", {});
|
|
116
|
+
}
|
|
117
|
+
const rows = LazySeq.of(report.programs).sortWith((a, b) => {
|
|
118
|
+
let c = 0;
|
|
119
|
+
switch (sortCol) {
|
|
120
|
+
case "ProgramName":
|
|
121
|
+
c = programFilename(a.programName).localeCompare(programFilename(b.programName));
|
|
122
|
+
break;
|
|
123
|
+
case "CellProgName":
|
|
124
|
+
c = a.cellControllerProgramName.localeCompare(b.cellControllerProgramName);
|
|
125
|
+
break;
|
|
126
|
+
case "Comment":
|
|
127
|
+
if (a.comment === null && b.comment === null) {
|
|
128
|
+
c = 0;
|
|
129
|
+
}
|
|
130
|
+
else if (a.comment === null) {
|
|
131
|
+
c = 1;
|
|
132
|
+
}
|
|
133
|
+
else if (b.comment === null) {
|
|
134
|
+
c = -1;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
c = a.comment.localeCompare(b.comment);
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
case "Revision":
|
|
141
|
+
if (a.revision === null && b.revision === null) {
|
|
142
|
+
c = 0;
|
|
143
|
+
}
|
|
144
|
+
else if (a.revision === null) {
|
|
145
|
+
c = 1;
|
|
146
|
+
}
|
|
147
|
+
else if (b.revision === null) {
|
|
148
|
+
c = -1;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
c = a.revision - b.revision;
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
case "PartName":
|
|
155
|
+
if (a.partName === null && b.partName === null) {
|
|
156
|
+
c = 0;
|
|
157
|
+
}
|
|
158
|
+
else if (a.partName === null) {
|
|
159
|
+
c = 1;
|
|
160
|
+
}
|
|
161
|
+
else if (b.partName === null) {
|
|
162
|
+
c = -1;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
c = a.partName.localeCompare(b.partName);
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case "MedianTime":
|
|
169
|
+
if (a.statisticalCycleTime === null && b.statisticalCycleTime === null) {
|
|
170
|
+
c = 0;
|
|
171
|
+
}
|
|
172
|
+
else if (a.statisticalCycleTime === null) {
|
|
173
|
+
c = 1;
|
|
174
|
+
}
|
|
175
|
+
else if (b.statisticalCycleTime === null) {
|
|
176
|
+
c = -1;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
c =
|
|
180
|
+
a.statisticalCycleTime.medianMinutesForSingleMat -
|
|
181
|
+
b.statisticalCycleTime.medianMinutesForSingleMat;
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case "DeviationAbove":
|
|
185
|
+
if (a.statisticalCycleTime === null && b.statisticalCycleTime === null) {
|
|
186
|
+
c = 0;
|
|
187
|
+
}
|
|
188
|
+
else if (a.statisticalCycleTime === null) {
|
|
189
|
+
c = 1;
|
|
190
|
+
}
|
|
191
|
+
else if (b.statisticalCycleTime === null) {
|
|
192
|
+
c = -1;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
c = a.statisticalCycleTime.MAD_aboveMinutes - b.statisticalCycleTime.MAD_aboveMinutes;
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
case "DeviationBelow":
|
|
199
|
+
if (a.statisticalCycleTime === null && b.statisticalCycleTime === null) {
|
|
200
|
+
c = 0;
|
|
201
|
+
}
|
|
202
|
+
else if (a.statisticalCycleTime === null) {
|
|
203
|
+
c = 1;
|
|
204
|
+
}
|
|
205
|
+
else if (b.statisticalCycleTime === null) {
|
|
206
|
+
c = -1;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
c = a.statisticalCycleTime.MAD_belowMinutes - b.statisticalCycleTime.MAD_belowMinutes;
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
case "Planned":
|
|
213
|
+
if (a.plannedMins === null && b.plannedMins === null) {
|
|
214
|
+
c = 0;
|
|
215
|
+
}
|
|
216
|
+
else if (a.plannedMins === null) {
|
|
217
|
+
c = 1;
|
|
218
|
+
}
|
|
219
|
+
else if (b.plannedMins === null) {
|
|
220
|
+
c = -1;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
c = a.plannedMins - b.plannedMins;
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
if (c === 0) {
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
else if ((c < 0 && sortDir === "asc") || (c > 0 && sortDir === "desc")) {
|
|
231
|
+
return -1;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return 1;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
function toggleSort(s) {
|
|
238
|
+
if (s === sortCol) {
|
|
239
|
+
setSortDir(sortDir === "asc" ? "desc" : "asc");
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
setSortCol(s);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return (_jsxs(Table, { stickyHeader: true, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, {}), _jsx(TableCell, { sortDirection: sortCol === "ProgramName" ? sortDir : false, children: _jsx(TableSortLabel, { active: sortCol === "ProgramName", direction: sortDir, onClick: () => toggleSort("ProgramName"), children: "Program Name" }) }), report.cellNameDifferentFromProgName ? (_jsx(TableCell, { sortDirection: sortCol === "CellProgName" ? sortDir : false, children: _jsx(TableSortLabel, { active: sortCol === "CellProgName", direction: sortDir, onClick: () => toggleSort("CellProgName"), children: "Cell Controller Program" }) })) : undefined, _jsx(TableCell, { sortDirection: sortCol === "PartName" ? sortDir : false, children: _jsx(TableSortLabel, { active: sortCol === "PartName", direction: sortDir, onClick: () => toggleSort("PartName"), children: "Part" }) }), _jsx(TableCell, { sortDirection: sortCol === "Comment" ? sortDir : false, children: _jsx(TableSortLabel, { active: sortCol === "Comment", direction: sortDir, onClick: () => toggleSort("Comment"), children: "Comment" }) }), report.hasRevisions ? (_jsx(TableCell, { sortDirection: sortCol === "Revision" ? sortDir : false, children: _jsx(TableSortLabel, { active: sortCol === "Revision", direction: sortDir, onClick: () => toggleSort("Revision"), children: "Revision" }) })) : undefined, _jsx(TableCell, { sortDirection: sortCol === "MedianTime" ? sortDir : false, align: "right", children: _jsx(TableSortLabel, { active: sortCol === "MedianTime", direction: sortDir, onClick: () => toggleSort("MedianTime"), children: "Median Time / Material (min)" }) }), _jsx(TableCell, { sortDirection: sortCol === "DeviationAbove" ? sortDir : false, align: "right", children: _jsx(TableSortLabel, { active: sortCol === "DeviationAbove", direction: sortDir, onClick: () => toggleSort("DeviationAbove"), children: "Deviation Above Median" }) }), _jsx(TableCell, { sortDirection: sortCol === "DeviationBelow" ? sortDir : false, align: "right", children: _jsx(TableSortLabel, { active: sortCol === "DeviationBelow", direction: sortDir, onClick: () => toggleSort("DeviationBelow"), children: "Deviation Below Median" }) }), _jsx(TableCell, { sortDirection: sortCol === "Planned" ? sortDir : false, align: "right", children: _jsx(TableSortLabel, { active: sortCol === "Planned", direction: sortDir, onClick: () => toggleSort("Planned"), children: "Planned Time (min)" }) }), _jsx(TableCell, {})] }) }), _jsx(TableBody, { children: LazySeq.of(rows).map((program, idx) => (_jsx(ProgramRow, { program: program, showCellCtrlCol: report.cellNameDifferentFromProgName, showRevCol: report.hasRevisions }, idx))) })] }));
|
|
246
|
+
}
|
|
247
|
+
function ProgramContentCode() {
|
|
248
|
+
const ct = useAtomValue(programContent);
|
|
249
|
+
const [highlighted, setHighlighted] = useState(null);
|
|
250
|
+
const worker = useMemo(() => new Worker(new URL("./ProgramHighlight.ts", import.meta.url), { type: "module" }), []);
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
let set = (h) => setHighlighted(h);
|
|
253
|
+
worker.onmessage = (e) => set(e.data);
|
|
254
|
+
return () => {
|
|
255
|
+
// cleanup
|
|
256
|
+
set = () => null;
|
|
257
|
+
worker.terminate();
|
|
258
|
+
setHighlighted(null);
|
|
259
|
+
};
|
|
260
|
+
}, [worker]);
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (ct && ct !== "") {
|
|
263
|
+
worker.postMessage(ct);
|
|
264
|
+
}
|
|
265
|
+
}, [ct, worker]);
|
|
266
|
+
return (_jsx("pre", { children: highlighted === null ? (_jsx("code", { className: "gcode", children: ct })) : (_jsx("code", { className: "gcode", dangerouslySetInnerHTML: { __html: highlighted } })) }));
|
|
267
|
+
}
|
|
268
|
+
export function ProgramContentDialog() {
|
|
269
|
+
const [program, setProgramToShowContent] = useAtom(programToShowContent);
|
|
270
|
+
const history = useAtomValue(programToShowHistory);
|
|
271
|
+
// when history is open, content is shown on the history dialog
|
|
272
|
+
return (_jsxs(Dialog, { open: program !== null && history === null, onClose: () => setProgramToShowContent(null), maxWidth: "lg", children: [_jsx(DialogTitle, { children: program?.partName ? (_jsxs("div", { style: { display: "flex", flexWrap: "wrap", alignItems: "center" }, children: [_jsx(PartIdenticon, { part: program.partName }), _jsxs("div", { style: { marginLeft: "10px", marginRight: "3em" }, children: [program?.programName ?? "Program", " ", program?.revision ? " rev" + program.revision.toFixed() : "", " ", _jsxs(Typography, { variant: "subtitle1", component: "span", children: ["(", program.partName, ")"] })] })] })) : (_jsxs(_Fragment, { children: [program?.programName ?? "Program", " ", program?.revision ? " rev" + program.revision.toFixed() : ""] })) }), _jsx(DialogContent, { children: program === null || history !== null ? (_jsx("div", {})) : (_jsx(DisplayLoadingAndError, { children: _jsx(ProgramContentCode, {}) })) }), _jsx(DialogActions, { children: _jsx(Button, { onClick: () => setProgramToShowContent(null), children: "Close" }) })] }));
|
|
273
|
+
}
|
|
274
|
+
const revisionsPerPage = 10;
|
|
275
|
+
function ProgramRevisionTable(props) {
|
|
276
|
+
const program = useAtomValue(programToShowHistory);
|
|
277
|
+
const setProgramToShowContent = useSetAtom(programToShowContent);
|
|
278
|
+
return (_jsxs(Table, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: "Revision" }), _jsx(TableCell, { children: "Comment" }), _jsx(TableCell, { children: "Cell Controller Program" }), _jsx(TableCell, {})] }) }), _jsx(TableBody, { children: props.loading ? (_jsxs(_Fragment, { children: [_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, children: _jsx(CircularProgress, {}) }) }), LazySeq.ofRange(0, revisionsPerPage - 1).map((i) => (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4 }) }, i)))] })) : (LazySeq.of(props.revisions)
|
|
279
|
+
.drop(props.page * revisionsPerPage)
|
|
280
|
+
.take(revisionsPerPage)
|
|
281
|
+
.map((rev) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: rev.revision }), _jsx(TableCell, { children: rev.comment ?? "" }), _jsx(TableCell, { children: rev.cellControllerProgramName ?? "" }), _jsx(TableCell, { children: _jsx(Tooltip, { title: "Load Program Content", children: _jsx(IconButton, { size: "small", onClick: () => setProgramToShowContent({
|
|
282
|
+
...rev,
|
|
283
|
+
partName: program?.partName ?? null,
|
|
284
|
+
}), children: _jsx(CodeIcon, {}) }) }) })] }, rev.revision)))) })] }));
|
|
285
|
+
}
|
|
286
|
+
export function ProgramHistoryDialog() {
|
|
287
|
+
const [program, setProgram] = useAtom(programToShowHistory);
|
|
288
|
+
const [programForContent, setProgramForContent] = useAtom(programToShowContent);
|
|
289
|
+
// TODO: switch to persistent list
|
|
290
|
+
const [revisions, setRevisions] = useState(null);
|
|
291
|
+
const [lastLoadedPage, setLastLoadedPage] = useState({ page: 0, hasMore: false });
|
|
292
|
+
const [page, setPage] = useState(0);
|
|
293
|
+
const [loading, setLoading] = useState(false);
|
|
294
|
+
const [error, setError] = useState(null);
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (program === null) {
|
|
297
|
+
setRevisions(null);
|
|
298
|
+
setPage(0);
|
|
299
|
+
setLastLoadedPage({ page: 0, hasMore: false });
|
|
300
|
+
}
|
|
301
|
+
else if (program !== null && revisions === null) {
|
|
302
|
+
// load initial
|
|
303
|
+
setLoading(true);
|
|
304
|
+
setError(null);
|
|
305
|
+
MachineBackend.getProgramRevisionsInDescendingOrderOfRevision(program.programName, revisionsPerPage, undefined)
|
|
306
|
+
.then((revs) => {
|
|
307
|
+
setRevisions(revs);
|
|
308
|
+
setLastLoadedPage({ page: 0, hasMore: revs.length === revisionsPerPage });
|
|
309
|
+
})
|
|
310
|
+
.catch(setError)
|
|
311
|
+
.finally(() => setLoading(false));
|
|
312
|
+
}
|
|
313
|
+
}, [program, revisions]);
|
|
314
|
+
function advancePage() {
|
|
315
|
+
if (page < lastLoadedPage.page) {
|
|
316
|
+
setPage(page + 1);
|
|
317
|
+
}
|
|
318
|
+
else if (lastLoadedPage.hasMore && program !== null && revisions !== null && revisions.length > 0) {
|
|
319
|
+
setLoading(true);
|
|
320
|
+
setError(null);
|
|
321
|
+
const rev = revisions[revisions.length - 1];
|
|
322
|
+
MachineBackend.getProgramRevisionsInDescendingOrderOfRevision(program.programName, revisionsPerPage, rev ? rev.revision - 1 : undefined)
|
|
323
|
+
.then((revs) => {
|
|
324
|
+
setRevisions((oldRevs) => (oldRevs === null ? revs : oldRevs.concat(revs)));
|
|
325
|
+
setLastLoadedPage({ page: page + 1, hasMore: revs.length === revisionsPerPage });
|
|
326
|
+
setPage(page + 1);
|
|
327
|
+
})
|
|
328
|
+
.catch(setError)
|
|
329
|
+
.finally(() => setLoading(false));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return (_jsxs(Dialog, { open: program !== null, onClose: () => setProgram(null), maxWidth: "lg", children: [_jsx(DialogTitle, { children: program?.partName ? (_jsxs("div", { style: { display: "flex", flexWrap: "wrap", alignItems: "center" }, children: [_jsx(PartIdenticon, { part: program.partName }), _jsxs("div", { style: { marginLeft: "10px", marginRight: "3em" }, children: [program.programName ?? "Program", " ", _jsxs(Typography, { variant: "subtitle1", component: "span", children: ["(", program.partName, ")"] })] })] })) : (_jsx(_Fragment, { children: program?.programName ?? "Program" })) }), _jsxs(DialogContent, { children: [error !== null ? (_jsx(Card, { children: _jsx(CardContent, { children: typeof error === "string" ? error : error.message }) })) : undefined, programForContent !== null ? (_jsx(DisplayLoadingAndError, { children: _jsx(ProgramContentCode, {}) })) : revisions !== null ? (_jsx(ProgramRevisionTable, { page: page, revisions: revisions, loading: loading })) : loading ? (_jsx(CircularProgress, {})) : undefined] }), _jsx(DialogActions, { children: _jsxs("div", { style: { display: "flex", alignItems: "center", width: "100%" }, children: [programForContent === null ? (_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: "Latest Revisions", children: _jsx("span", { children: _jsx(IconButton, { onClick: () => setPage(0), disabled: loading || page === 0, size: "large", children: _jsx(FirstPageIcon, {}) }) }) }), _jsx(Tooltip, { title: "Previous Page", children: _jsx("span", { children: _jsx(IconButton, { onClick: () => setPage(page - 1), disabled: loading || page === 0, size: "large", children: _jsx(KeyboardArrowLeft, {}) }) }) }), _jsx(Tooltip, { title: "Next Page", children: _jsx("span", { children: _jsx(IconButton, { onClick: () => advancePage(), disabled: loading || (page === lastLoadedPage.page && !lastLoadedPage.hasMore), size: "large", children: _jsx(KeyboardArrowRight, {}) }) }) })] })) : undefined, _jsx("div", { style: { flexGrow: 1 } }), programForContent !== null ? (_jsx(Button, { onClick: () => setProgramForContent(null), children: "Back to History" })) : undefined, _jsx(Button, { onClick: () => setProgram(null), children: "Close" })] }) })] }));
|
|
333
|
+
}
|
|
334
|
+
function ProgNavHeader() {
|
|
335
|
+
const [reloadTime, refreshPrograms] = useAtom(programReportRefreshTime);
|
|
336
|
+
const [loading, setLoading] = useState(false);
|
|
337
|
+
const demo = useIsDemo();
|
|
338
|
+
const [filter, setFilter] = useAtom(programFilter);
|
|
339
|
+
function refresh() {
|
|
340
|
+
setLoading(true);
|
|
341
|
+
refreshPrograms(new Date())
|
|
342
|
+
.catch(console.log)
|
|
343
|
+
.finally(() => setLoading(false));
|
|
344
|
+
}
|
|
345
|
+
if (demo) {
|
|
346
|
+
return _jsx("div", {});
|
|
347
|
+
}
|
|
348
|
+
else if (reloadTime === null) {
|
|
349
|
+
return (_jsx("main", { style: { margin: "2em", display: "flex", justifyContent: "center" }, children: _jsx(Fab, { color: "secondary", size: "large", variant: "extended", style: { margin: "2em" }, onClick: refresh, disabled: loading, children: _jsxs(_Fragment, { children: [loading ? (_jsx(CircularProgress, { size: 10, style: { marginRight: "1em" } })) : (_jsx(RefreshIcon, { fontSize: "inherit", style: { marginRight: "1em" } })), "Load Programs"] }) }) }));
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
return (_jsxs(Box, { component: "nav", sx: {
|
|
353
|
+
display: "flex",
|
|
354
|
+
minHeight: "2.5em",
|
|
355
|
+
alignItems: "center",
|
|
356
|
+
maxWidth: "calc(100vw - 24px - 24px)",
|
|
357
|
+
}, children: [_jsx(Tooltip, { title: "Refresh Programs", children: _jsx("div", { children: _jsx(IconButton, { onClick: refresh, disabled: loading, size: "small", children: loading ? _jsx(CircularProgress, { size: 10 }) : _jsx(RefreshIcon, { fontSize: "inherit" }) }) }) }), _jsxs("span", { style: { marginLeft: "1em" }, children: ["Programs from ", _jsx(TimeAgo, { date: reloadTime })] }), _jsx("div", { style: { flexGrow: 1 } }), _jsx(FormControl, { size: "small", children: _jsxs(Select, { autoWidth: true, value: filter, onChange: (e) => setFilter(e.target.value), children: [_jsx(MenuItem, { value: "AllPrograms", children: "All Programs" }, "AllPrograms"), _jsx(MenuItem, { value: "ActivePrograms", children: "Active Programs" }, "ActivePrograms")] }) })] }));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
export function ProgramReportPage() {
|
|
361
|
+
useSetTitle("Programs");
|
|
362
|
+
return (_jsxs(Box, { paddingLeft: "24px", paddingRight: "24px", paddingTop: "10px", children: [_jsx(ProgNavHeader, {}), _jsx("main", { children: _jsx(DisplayLoadingAndError, { children: _jsx(ProgramSummaryTable, {}) }) }), _jsx(ProgramContentDialog, {}), _jsx(ProgramHistoryDialog, {})] }));
|
|
363
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function RebookingsPage(): import("react/jsx-runtime").JSX.Element;
|