@dexteel/mesf-core 7.20.1 → 7.22.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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/index.esm.js +219 -94
- package/dist/index.esm.js.map +1 -1
- package/dist/pages/trendings-v2/TrendingsPageV2.d.ts +2 -1
- package/dist/pages/trendings-v2/components/chart/models/TrendingModelsV2.d.ts +1 -0
- package/dist/pages/trendings-v2/components/chart/sections/HeaderSectionV2.d.ts +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.22.0](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.21.0...@dexteel/mesf-core-v7.22.0) (2026-05-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **trendings-v2:** simplify chart layout ([114ea8f](https://github.com/dexteel/mesf-core-frontend/commit/114ea8fd2f5495f8ccc2d52bcff0bdb6d5202999))
|
|
9
|
+
|
|
10
|
+
## [7.21.0](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.20.1...@dexteel/mesf-core-v7.21.0) (2026-04-24)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **trendings-v2:** add stepped mode and URL state sync ([d87f8b6](https://github.com/dexteel/mesf-core-frontend/commit/d87f8b6f1e22b46d2a32b7e59017a4f62a9b0323))
|
|
16
|
+
|
|
3
17
|
## [7.20.1](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.20.0...@dexteel/mesf-core-v7.20.1) (2026-04-20)
|
|
4
18
|
|
|
5
19
|
|
package/dist/index.esm.js
CHANGED
|
@@ -25,7 +25,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
|
|
25
25
|
import EditIcon from '@mui/icons-material/Edit';
|
|
26
26
|
import FindInPageIcon from '@mui/icons-material/FindInPage';
|
|
27
27
|
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
|
|
28
|
-
import { ArrowRight, ArrowBackRounded, ArrowForwardRounded, SkipNext, ChevronLeft, ChevronRight, Cloud, ExpandLess, ExpandMore, Square as Square$1, Timeline, Send, Menu as Menu$1, People, Storage, Group as Group$1, Assignment, Chat, ViewList, Build, Settings as Settings$2, Code as Code$1,
|
|
28
|
+
import { ArrowRight, ArrowBackRounded, ArrowForwardRounded, SkipNext, ChevronLeft, ChevronRight, Cloud, ExpandLess, ExpandMore, Square as Square$1, Timeline, Send, Menu as Menu$1, People, Storage, Group as Group$1, Assignment, Chat, ViewList, Build, Settings as Settings$2, Code as Code$1, KeyboardDoubleArrowLeft, KeyboardArrowLeft, KeyboardArrowRight, KeyboardDoubleArrowRight, Update, ZoomIn, Restore, Lock, Create, Delete, Folder, InsertChart, Search, PlaylistAdd, DragIndicator, Save, AttachFile, CloudUpload, GetApp } from '@mui/icons-material';
|
|
29
29
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
30
30
|
import FormatListBulletedSharpIcon from '@mui/icons-material/FormatListBulletedSharp';
|
|
31
31
|
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
|
@@ -11851,19 +11851,21 @@ const dateNavigator = (startDate, endDate, scope, operator, current = false) =>
|
|
|
11851
11851
|
return { newStartDate, newEndDate };
|
|
11852
11852
|
};
|
|
11853
11853
|
|
|
11854
|
-
const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setChartOptions, chartInstance }) => {
|
|
11854
|
+
const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setChartOptions, setAggregationMode, chartInstance, }) => {
|
|
11855
11855
|
const queryClient = useQueryClient();
|
|
11856
11856
|
const { state: { timeScopeStart, timeScopeEnd, scope, viewSelected, views }, actions: { setTotalScope, setViewSelected }, } = useTrendingContextV2();
|
|
11857
11857
|
const [customOptions, setCustomOptions] = useState({
|
|
11858
11858
|
showGridLines: true,
|
|
11859
11859
|
showSymbols: false,
|
|
11860
|
-
smoothLines:
|
|
11860
|
+
smoothLines: false,
|
|
11861
|
+
steppedLines: true,
|
|
11861
11862
|
showLegend: false,
|
|
11862
11863
|
showTooltip: true,
|
|
11863
|
-
combinedView:
|
|
11864
|
+
combinedView: true,
|
|
11864
11865
|
showToolbox: true,
|
|
11865
|
-
showYAxisNames:
|
|
11866
|
+
showYAxisNames: false,
|
|
11866
11867
|
});
|
|
11868
|
+
const [aggregationMode, setAggregationModeState] = useState("avg");
|
|
11867
11869
|
// View management state
|
|
11868
11870
|
const [viewModalMode, setViewModalMode] = useState(null);
|
|
11869
11871
|
const [viewForModal, setViewForModal] = useState(null);
|
|
@@ -11980,6 +11982,11 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
11980
11982
|
setChartOptions(customOptions);
|
|
11981
11983
|
}
|
|
11982
11984
|
}, [customOptions, setChartOptions]);
|
|
11985
|
+
useEffect(() => {
|
|
11986
|
+
if (setAggregationMode) {
|
|
11987
|
+
setAggregationMode(aggregationMode);
|
|
11988
|
+
}
|
|
11989
|
+
}, [aggregationMode, setAggregationMode]);
|
|
11983
11990
|
return (React__default.createElement(React__default.Fragment, null,
|
|
11984
11991
|
React__default.createElement(Grid2, { size: 12, container: true, spacing: 1, justifyContent: "space-between", alignItems: "center", style: { height: "auto" } },
|
|
11985
11992
|
React__default.createElement(Grid2, { size: { md: 5, sm: 12, xs: 12 }, container: true, justifyContent: "flex-start", alignItems: "center", wrap: "wrap" },
|
|
@@ -11992,12 +11999,13 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
11992
11999
|
width: "100%",
|
|
11993
12000
|
} },
|
|
11994
12001
|
React__default.createElement(Grid2, null,
|
|
11995
|
-
React__default.createElement(
|
|
11996
|
-
React__default.createElement(
|
|
12002
|
+
React__default.createElement(Tooltip, { title: "Previous period", arrow: true },
|
|
12003
|
+
React__default.createElement(IconButton$1, { onClick: () => handleDateNavigator("subtract"), size: "small" },
|
|
12004
|
+
React__default.createElement(KeyboardDoubleArrowLeft, { fontSize: "medium", sx: { color: "black" } })))),
|
|
11997
12005
|
React__default.createElement(Grid2, null,
|
|
11998
|
-
React__default.createElement(Tooltip, { title: "
|
|
12006
|
+
React__default.createElement(Tooltip, { title: "Pan backward 20%", arrow: true },
|
|
11999
12007
|
React__default.createElement(IconButton$1, { onClick: () => handlePartialDateNavigator("subtract"), size: "small" },
|
|
12000
|
-
React__default.createElement(
|
|
12008
|
+
React__default.createElement(KeyboardArrowLeft, { fontSize: "medium", sx: { color: "black" } })))),
|
|
12001
12009
|
React__default.createElement(Grid2, { size: { md: 3.5 } },
|
|
12002
12010
|
React__default.createElement(LocalizationProvider$1, { dateAdapter: AdapterMoment },
|
|
12003
12011
|
React__default.createElement(DateTimePicker, { label: "Start", format: "MM/DD/YYYY HH:mm:ss", value: moment$g(timeScopeStart), onChange: (newValue) => {
|
|
@@ -12035,15 +12043,17 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12035
12043
|
},
|
|
12036
12044
|
}, disabled: autoRefresh }))),
|
|
12037
12045
|
React__default.createElement(Grid2, null,
|
|
12038
|
-
React__default.createElement(Tooltip, { title: "
|
|
12046
|
+
React__default.createElement(Tooltip, { title: "Pan forward 20%", arrow: true },
|
|
12039
12047
|
React__default.createElement(IconButton$1, { onClick: () => handlePartialDateNavigator("add"), size: "small" },
|
|
12040
|
-
React__default.createElement(
|
|
12048
|
+
React__default.createElement(KeyboardArrowRight, { fontSize: "medium", sx: { color: "black" } })))),
|
|
12041
12049
|
React__default.createElement(Grid2, null,
|
|
12042
|
-
React__default.createElement(
|
|
12043
|
-
React__default.createElement(
|
|
12050
|
+
React__default.createElement(Tooltip, { title: "Next period", arrow: true },
|
|
12051
|
+
React__default.createElement(IconButton$1, { onClick: () => handleDateNavigator("add"), size: "small" },
|
|
12052
|
+
React__default.createElement(KeyboardDoubleArrowRight, { fontSize: "medium", sx: { color: "black" } })))),
|
|
12044
12053
|
React__default.createElement(Grid2, null,
|
|
12045
|
-
React__default.createElement(
|
|
12046
|
-
React__default.createElement(
|
|
12054
|
+
React__default.createElement(Tooltip, { title: "Jump to current time", arrow: true },
|
|
12055
|
+
React__default.createElement(IconButton$1, { onClick: () => handleDateNavigator("subtract", true), size: "small" },
|
|
12056
|
+
React__default.createElement(Update, { fontSize: "medium", sx: { color: "black" } })))))),
|
|
12047
12057
|
React__default.createElement(Grid2, { size: { md: 5, sm: 6, xs: 12 } },
|
|
12048
12058
|
React__default.createElement(Paper, { elevation: 0, sx: {
|
|
12049
12059
|
p: 1,
|
|
@@ -12055,31 +12065,24 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12055
12065
|
alignItems: "stretch",
|
|
12056
12066
|
justifyContent: "space-between",
|
|
12057
12067
|
} },
|
|
12058
|
-
React__default.createElement(Box, { sx: { width:
|
|
12068
|
+
React__default.createElement(Box, { sx: { width: 155 } },
|
|
12059
12069
|
React__default.createElement(FormControl, { fullWidth: true, size: "small" },
|
|
12060
12070
|
React__default.createElement(Select, { multiple: true, value: [
|
|
12061
12071
|
...(customOptions.showGridLines ? ["grid"] : []),
|
|
12062
12072
|
...(customOptions.showSymbols ? ["symbols"] : []),
|
|
12063
12073
|
...(customOptions.smoothLines ? ["smooth"] : []),
|
|
12074
|
+
...(customOptions.steppedLines ? ["stepped"] : []),
|
|
12064
12075
|
...(customOptions.showTooltip ? ["tooltip"] : []),
|
|
12065
12076
|
...(customOptions.showToolbox ? ["toolbox"] : []),
|
|
12066
12077
|
...(customOptions.showYAxisNames ? ["yAxisNames"] : []),
|
|
12067
12078
|
], onChange: (e) => {
|
|
12068
12079
|
const selected = e.target.value;
|
|
12069
|
-
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { showGridLines: selected.includes("grid"), showSymbols: selected.includes("symbols"), smoothLines: selected.includes("smooth")
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
tooltip: "Tooltip",
|
|
12076
|
-
toolbox: "Toolbox",
|
|
12077
|
-
yAxisNames: "Y-Axis Names",
|
|
12078
|
-
};
|
|
12079
|
-
return (React__default.createElement("span", { style: { fontSize: "0.75rem" } }, selected
|
|
12080
|
-
.map((val) => labels[val])
|
|
12081
|
-
.join(", ")));
|
|
12082
|
-
} },
|
|
12080
|
+
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { showGridLines: selected.includes("grid"), showSymbols: selected.includes("symbols"), smoothLines: selected.includes("smooth") &&
|
|
12081
|
+
!selected.includes("stepped"), steppedLines: selected.includes("stepped"), showTooltip: selected.includes("tooltip"), showToolbox: selected.includes("toolbox"), showYAxisNames: selected.includes("yAxisNames") })));
|
|
12082
|
+
}, renderValue: (selected) => (React__default.createElement("span", { style: { fontSize: "0.75rem" } },
|
|
12083
|
+
"Chart: ",
|
|
12084
|
+
selected.length,
|
|
12085
|
+
" options")) },
|
|
12083
12086
|
React__default.createElement(MenuItem, { value: "grid", style: { padding: 0 } },
|
|
12084
12087
|
React__default.createElement(Checkbox, { checked: customOptions.showGridLines, size: "small" }),
|
|
12085
12088
|
React__default.createElement(ListItemText, null, "Grid")),
|
|
@@ -12089,6 +12092,9 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12089
12092
|
React__default.createElement(MenuItem, { value: "smooth", style: { padding: 0 } },
|
|
12090
12093
|
React__default.createElement(Checkbox, { checked: customOptions.smoothLines, size: "small" }),
|
|
12091
12094
|
React__default.createElement(ListItemText, null, "Smooth")),
|
|
12095
|
+
React__default.createElement(MenuItem, { value: "stepped", style: { padding: 0 } },
|
|
12096
|
+
React__default.createElement(Checkbox, { checked: customOptions.steppedLines, size: "small" }),
|
|
12097
|
+
React__default.createElement(ListItemText, null, "Stepped")),
|
|
12092
12098
|
React__default.createElement(MenuItem, { value: "tooltip", style: { padding: 0 } },
|
|
12093
12099
|
React__default.createElement(Checkbox, { checked: customOptions.showTooltip, size: "small" }),
|
|
12094
12100
|
React__default.createElement(ListItemText, null, "Tooltip")),
|
|
@@ -12098,11 +12104,18 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12098
12104
|
React__default.createElement(MenuItem, { value: "yAxisNames", style: { padding: 0 } },
|
|
12099
12105
|
React__default.createElement(Checkbox, { checked: customOptions.showYAxisNames, size: "small" }),
|
|
12100
12106
|
React__default.createElement(ListItemText, null, "Y-Axis Names"))))),
|
|
12107
|
+
React__default.createElement(Box, { sx: { minWidth: 150 } },
|
|
12108
|
+
React__default.createElement(FormControl, { fullWidth: true, size: "small" },
|
|
12109
|
+
React__default.createElement(Select, { value: aggregationMode, onChange: (e) => {
|
|
12110
|
+
setAggregationModeState(e.target.value);
|
|
12111
|
+
}, renderValue: (selected) => selected === "last" ? "Agg: Last" : "Agg: Avg" },
|
|
12112
|
+
React__default.createElement(MenuItem, { value: "avg" }, "Average"),
|
|
12113
|
+
React__default.createElement(MenuItem, { value: "last" }, "Last value")))),
|
|
12101
12114
|
React__default.createElement(Divider, { orientation: "vertical", flexItem: true }),
|
|
12102
12115
|
React__default.createElement(FormControlLabel, { checked: customOptions.combinedView, control: React__default.createElement(Switch, { color: "primary", size: "small" }), label: React__default.createElement("span", { style: { fontSize: "0.75rem", fontWeight: 600 } }, "Combined"), style: { margin: "0" }, onChange: (e, checked) => {
|
|
12103
12116
|
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { combinedView: checked })));
|
|
12104
12117
|
} }),
|
|
12105
|
-
React__default.createElement(FormControlLabel, { checked: autoRefresh, control: React__default.createElement(Switch, { color: "primary", size: "small" }), label: React__default.createElement("span", { style: { fontSize: "0.75rem", fontWeight: 600 } }, "Auto
|
|
12118
|
+
React__default.createElement(FormControlLabel, { checked: autoRefresh, control: React__default.createElement(Switch, { color: "primary", size: "small" }), label: React__default.createElement("span", { style: { fontSize: "0.75rem", fontWeight: 600 } }, "Auto"), style: { margin: "0" }, onChange: (e, checked) => {
|
|
12106
12119
|
if (checked) {
|
|
12107
12120
|
// When enabling auto-refresh, set end to now
|
|
12108
12121
|
// and keep the current period to calculate start
|
|
@@ -12121,8 +12134,12 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12121
12134
|
setAutoRefresh(checked);
|
|
12122
12135
|
} }),
|
|
12123
12136
|
React__default.createElement(Divider, { orientation: "vertical", flexItem: true }),
|
|
12124
|
-
React__default.createElement(
|
|
12125
|
-
|
|
12137
|
+
React__default.createElement(Tooltip, { title: "Area zoom", arrow: true },
|
|
12138
|
+
React__default.createElement(IconButton$1, { color: "primary", onClick: handleZoomIn, size: "small" },
|
|
12139
|
+
React__default.createElement(ZoomIn, { fontSize: "small" }))),
|
|
12140
|
+
React__default.createElement(Tooltip, { title: "Restore zoom", arrow: true },
|
|
12141
|
+
React__default.createElement(IconButton$1, { color: "primary", onClick: handleRestoreZoom, size: "small" },
|
|
12142
|
+
React__default.createElement(Restore, { fontSize: "small" })))))),
|
|
12126
12143
|
React__default.createElement(Grid2, { size: { md: 2, sm: 6, xs: 12 }, container: true, justifyContent: "flex-end", alignItems: "center" },
|
|
12127
12144
|
React__default.createElement(Paper, { elevation: 0, sx: {
|
|
12128
12145
|
p: 1,
|
|
@@ -14513,13 +14530,25 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14513
14530
|
const opts = customOptions || {
|
|
14514
14531
|
showGridLines: true,
|
|
14515
14532
|
showSymbols: false,
|
|
14516
|
-
smoothLines:
|
|
14533
|
+
smoothLines: false,
|
|
14534
|
+
steppedLines: true,
|
|
14517
14535
|
showLegend: true,
|
|
14518
14536
|
showTooltip: true,
|
|
14519
|
-
combinedView:
|
|
14537
|
+
combinedView: true,
|
|
14520
14538
|
showToolbox: true,
|
|
14521
|
-
showYAxisNames:
|
|
14539
|
+
showYAxisNames: false,
|
|
14522
14540
|
};
|
|
14541
|
+
const getTagName = useCallback((tag) => tag.Alias || tag.TagName, []);
|
|
14542
|
+
const getActiveAxisTag = useCallback((tags) => {
|
|
14543
|
+
if (tags.length === 0)
|
|
14544
|
+
return null;
|
|
14545
|
+
if (highlightedSeries) {
|
|
14546
|
+
const highlightedTag = tags.find((tag) => tag.IsVisible && getTagName(tag) === highlightedSeries);
|
|
14547
|
+
if (highlightedTag)
|
|
14548
|
+
return highlightedTag;
|
|
14549
|
+
}
|
|
14550
|
+
return tags.find((tag) => tag.IsVisible) || null;
|
|
14551
|
+
}, [highlightedSeries, getTagName]);
|
|
14523
14552
|
// Clear zoom state when time scope changes or combined view toggles
|
|
14524
14553
|
useEffect(() => {
|
|
14525
14554
|
const currentTimeScope = `${timeScopeStart.getTime()}-${timeScopeEnd.getTime()}`;
|
|
@@ -14538,13 +14567,14 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14538
14567
|
prevCombinedViewRef.current = opts.combinedView;
|
|
14539
14568
|
}, [timeScopeStart, timeScopeEnd, opts.combinedView]);
|
|
14540
14569
|
// Helper to build yAxis config with scale settings
|
|
14541
|
-
const buildYAxisConfig = useCallback((tag, gridIndex, position, offset = 0) => {
|
|
14570
|
+
const buildYAxisConfig = useCallback((tag, gridIndex, position, offset = 0, isAxisVisible = true) => {
|
|
14542
14571
|
const baseConfig = {
|
|
14543
14572
|
gridIndex,
|
|
14544
14573
|
type: "value",
|
|
14545
|
-
|
|
14574
|
+
show: isAxisVisible,
|
|
14575
|
+
name: isAxisVisible && opts.showYAxisNames ? getTagName(tag) : "",
|
|
14546
14576
|
nameLocation: "middle",
|
|
14547
|
-
nameGap: 45
|
|
14577
|
+
nameGap: 45,
|
|
14548
14578
|
position,
|
|
14549
14579
|
offset,
|
|
14550
14580
|
splitNumber: 8, // Suggest 8 divisions, ECharts will adjust for readability
|
|
@@ -14554,21 +14584,24 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14554
14584
|
fontWeight: "bold",
|
|
14555
14585
|
},
|
|
14556
14586
|
axisLine: {
|
|
14557
|
-
show:
|
|
14587
|
+
show: isAxisVisible,
|
|
14558
14588
|
lineStyle: {
|
|
14559
14589
|
color: tag.Color,
|
|
14590
|
+
width: 2,
|
|
14560
14591
|
},
|
|
14561
14592
|
},
|
|
14562
14593
|
axisTick: {
|
|
14563
|
-
show:
|
|
14594
|
+
show: isAxisVisible,
|
|
14564
14595
|
},
|
|
14565
14596
|
axisLabel: {
|
|
14566
|
-
show:
|
|
14597
|
+
show: isAxisVisible,
|
|
14567
14598
|
color: tag.Color,
|
|
14568
14599
|
fontSize: 10,
|
|
14569
14600
|
},
|
|
14570
14601
|
splitLine: {
|
|
14571
|
-
show: position === "left" && offset === 0
|
|
14602
|
+
show: isAxisVisible && position === "left" && offset === 0
|
|
14603
|
+
? opts.showGridLines
|
|
14604
|
+
: false,
|
|
14572
14605
|
lineStyle: {
|
|
14573
14606
|
color: "#e0e0e0",
|
|
14574
14607
|
type: "solid",
|
|
@@ -14600,7 +14633,7 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14600
14633
|
delete baseConfig.scale;
|
|
14601
14634
|
}
|
|
14602
14635
|
return baseConfig;
|
|
14603
|
-
}, [opts.showGridLines,
|
|
14636
|
+
}, [opts.showGridLines, opts.showYAxisNames, getTagName]);
|
|
14604
14637
|
// Determine if we should use separate grids (analog/digital)
|
|
14605
14638
|
const useSeparateGrids = !opts.combinedView &&
|
|
14606
14639
|
processedData.analogTags.length > 0 &&
|
|
@@ -14731,21 +14764,8 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14731
14764
|
isUserDraggingRef.current = false;
|
|
14732
14765
|
}, [handleCursor2Change]);
|
|
14733
14766
|
const chartOptions = useMemo(() => {
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
// Base margin is 60px, then add 60px for each additional pair
|
|
14737
|
-
const calculateMargin = (tagCount) => {
|
|
14738
|
-
if (tagCount === 0)
|
|
14739
|
-
return 60;
|
|
14740
|
-
// Number of axes on each side (alternating left/right)
|
|
14741
|
-
const axesPerSide = Math.ceil(tagCount / 2);
|
|
14742
|
-
// Last axis offset = (axesPerSide - 1) * 60
|
|
14743
|
-
// Total margin = last offset + base margin (60px)
|
|
14744
|
-
return (axesPerSide - 1) * 60 + 60;
|
|
14745
|
-
};
|
|
14746
|
-
const analogMargin = calculateMargin(processedData.analogTags.length);
|
|
14747
|
-
const digitalMargin = calculateMargin(processedData.digitalTags.length);
|
|
14748
|
-
const combinedMargin = calculateMargin(processedData.analogTags.length + processedData.digitalTags.length);
|
|
14767
|
+
const chartLeftMargin = opts.showYAxisNames ? 96 : 72;
|
|
14768
|
+
const chartRightMargin = 32;
|
|
14749
14769
|
return {
|
|
14750
14770
|
animation: false,
|
|
14751
14771
|
backgroundColor: "#fff",
|
|
@@ -14754,16 +14774,16 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14754
14774
|
? [
|
|
14755
14775
|
{
|
|
14756
14776
|
id: "analog",
|
|
14757
|
-
left: `${
|
|
14758
|
-
right: `${
|
|
14777
|
+
left: `${chartLeftMargin}px`,
|
|
14778
|
+
right: `${chartRightMargin}px`,
|
|
14759
14779
|
top: opts.showLegend ? "70px" : "50px", // Increased to prevent cursor circle clipping
|
|
14760
14780
|
bottom: "55%",
|
|
14761
14781
|
containLabel: false,
|
|
14762
14782
|
},
|
|
14763
14783
|
{
|
|
14764
14784
|
id: "digital",
|
|
14765
|
-
left: `${
|
|
14766
|
-
right: `${
|
|
14785
|
+
left: `${chartLeftMargin}px`,
|
|
14786
|
+
right: `${chartRightMargin}px`,
|
|
14767
14787
|
top: "55%",
|
|
14768
14788
|
bottom: 60,
|
|
14769
14789
|
containLabel: false,
|
|
@@ -14772,8 +14792,8 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14772
14792
|
: [
|
|
14773
14793
|
{
|
|
14774
14794
|
id: "combined",
|
|
14775
|
-
left: `${
|
|
14776
|
-
right: `${
|
|
14795
|
+
left: `${chartLeftMargin}px`,
|
|
14796
|
+
right: `${chartRightMargin}px`,
|
|
14777
14797
|
top: opts.showLegend ? "70px" : "50px", // Increased to prevent cursor circle clipping
|
|
14778
14798
|
bottom: 60,
|
|
14779
14799
|
containLabel: false,
|
|
@@ -15000,34 +15020,25 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15000
15020
|
yAxis: (() => {
|
|
15001
15021
|
const yAxisArray = [];
|
|
15002
15022
|
if (useSeparateGrids) {
|
|
15003
|
-
|
|
15004
|
-
|
|
15023
|
+
const activeAnalogTag = getActiveAxisTag(processedData.analogTags);
|
|
15024
|
+
const activeDigitalTag = getActiveAxisTag(processedData.digitalTags);
|
|
15005
15025
|
processedData.analogTags.forEach((tag, idx) => {
|
|
15006
|
-
|
|
15007
|
-
const offset = Math.floor(idx / 2) * 60;
|
|
15008
|
-
yAxisArray.push(buildYAxisConfig(tag, 0, position, offset));
|
|
15026
|
+
yAxisArray.push(buildYAxisConfig(tag, 0, "left", 0, tag === activeAnalogTag));
|
|
15009
15027
|
});
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
const position = idx % 2 === 0 ? "left" : "right";
|
|
15013
|
-
const offset = Math.floor(idx / 2) * 60;
|
|
15014
|
-
yAxisArray.push(buildYAxisConfig(tag, 1, position, offset));
|
|
15028
|
+
processedData.digitalTags.forEach((tag) => {
|
|
15029
|
+
yAxisArray.push(buildYAxisConfig(tag, 1, "left", 0, tag === activeDigitalTag));
|
|
15015
15030
|
});
|
|
15016
15031
|
}
|
|
15017
15032
|
else {
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
yAxisArray.push(buildYAxisConfig(tag, 0,
|
|
15033
|
+
const activeCombinedTag = getActiveAxisTag([
|
|
15034
|
+
...processedData.analogTags,
|
|
15035
|
+
...processedData.digitalTags,
|
|
15036
|
+
]);
|
|
15037
|
+
processedData.analogTags.forEach((tag) => {
|
|
15038
|
+
yAxisArray.push(buildYAxisConfig(tag, 0, "left", 0, tag === activeCombinedTag));
|
|
15024
15039
|
});
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
const position = idx % 2 === 0 ? "left" : "right";
|
|
15028
|
-
const baseOffset = Math.ceil(processedData.analogTags.length / 2) * 60;
|
|
15029
|
-
const offset = baseOffset + Math.floor(idx / 2) * 60;
|
|
15030
|
-
yAxisArray.push(buildYAxisConfig(tag, 0, position, offset));
|
|
15040
|
+
processedData.digitalTags.forEach((tag) => {
|
|
15041
|
+
yAxisArray.push(buildYAxisConfig(tag, 0, "left", 0, tag === activeCombinedTag));
|
|
15031
15042
|
});
|
|
15032
15043
|
}
|
|
15033
15044
|
// If no axes were created at all, add a default one to prevent errors
|
|
@@ -15057,7 +15068,8 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15057
15068
|
xAxisIndex: 0,
|
|
15058
15069
|
yAxisIndex: idx, // Map to corresponding analog yAxis
|
|
15059
15070
|
data: s.data,
|
|
15060
|
-
smooth: opts.smoothLines,
|
|
15071
|
+
smooth: opts.steppedLines ? false : opts.smoothLines,
|
|
15072
|
+
step: opts.steppedLines ? "end" : undefined,
|
|
15061
15073
|
symbol: opts.showSymbols ? "circle" : "none",
|
|
15062
15074
|
sampling: "lttb",
|
|
15063
15075
|
show: s.visible,
|
|
@@ -15126,10 +15138,25 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15126
15138
|
if (!params || params.length === 0)
|
|
15127
15139
|
return "";
|
|
15128
15140
|
const date = new Date(params[0].value[0]);
|
|
15141
|
+
const formatTooltipValue = (value) => {
|
|
15142
|
+
if (value === null || value === undefined || value === "") {
|
|
15143
|
+
return "-";
|
|
15144
|
+
}
|
|
15145
|
+
const numericValue = Number(value);
|
|
15146
|
+
if (!Number.isFinite(numericValue)) {
|
|
15147
|
+
return String(value);
|
|
15148
|
+
}
|
|
15149
|
+
if (Number.isInteger(numericValue)) {
|
|
15150
|
+
return numericValue.toString();
|
|
15151
|
+
}
|
|
15152
|
+
return numericValue.toLocaleString(undefined, {
|
|
15153
|
+
maximumFractionDigits: 5,
|
|
15154
|
+
});
|
|
15155
|
+
};
|
|
15129
15156
|
let content = `<div style="font-weight: bold; margin-bottom: 5px;">${date.toLocaleString()}</div>`;
|
|
15130
15157
|
params.forEach((param) => {
|
|
15131
15158
|
const marker = `<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background-color:${param.color};margin-right:5px;"></span>`;
|
|
15132
|
-
content += `<div>${marker}${param.seriesName}: ${param.value[1]}</div>`;
|
|
15159
|
+
content += `<div>${marker}${param.seriesName}: ${formatTooltipValue(param.value[1])}</div>`;
|
|
15133
15160
|
});
|
|
15134
15161
|
return content;
|
|
15135
15162
|
},
|
|
@@ -15200,6 +15227,7 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15200
15227
|
timeScopeStart,
|
|
15201
15228
|
timeScopeEnd,
|
|
15202
15229
|
buildYAxisConfig,
|
|
15230
|
+
getActiveAxisTag,
|
|
15203
15231
|
zoomState,
|
|
15204
15232
|
useSeparateGrids,
|
|
15205
15233
|
]);
|
|
@@ -15499,9 +15527,9 @@ const useSearchViewTags = ({ viewId }) => {
|
|
|
15499
15527
|
enabled: viewId !== null,
|
|
15500
15528
|
});
|
|
15501
15529
|
};
|
|
15502
|
-
const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
15530
|
+
const useSearchSeries = ({ start, end, tagIds, aggregationMode, autoRefresh = false, }) => {
|
|
15503
15531
|
return useQuery({
|
|
15504
|
-
queryKey: ["series-v2", start, end, tagIds],
|
|
15532
|
+
queryKey: ["series-v2", start, end, tagIds, aggregationMode],
|
|
15505
15533
|
queryFn: (_a) => __awaiter(void 0, [_a], void 0, function* ({ signal }) {
|
|
15506
15534
|
try {
|
|
15507
15535
|
if (!tagIds || tagIds.length === 0) {
|
|
@@ -15512,6 +15540,7 @@ const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
|
15512
15540
|
end: end || new Date().getTime(),
|
|
15513
15541
|
tagIds,
|
|
15514
15542
|
sampleCount: 1000,
|
|
15543
|
+
aggregationMode,
|
|
15515
15544
|
}, {
|
|
15516
15545
|
signal,
|
|
15517
15546
|
});
|
|
@@ -15528,14 +15557,60 @@ const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
|
15528
15557
|
enabled: tagIds.length > 0,
|
|
15529
15558
|
});
|
|
15530
15559
|
};
|
|
15560
|
+
const VALID_SCOPE_VALUES = [
|
|
15561
|
+
"10 min",
|
|
15562
|
+
"1 hour",
|
|
15563
|
+
"4 hours",
|
|
15564
|
+
"12 hours",
|
|
15565
|
+
"1 day",
|
|
15566
|
+
"10 days",
|
|
15567
|
+
"custom",
|
|
15568
|
+
];
|
|
15569
|
+
const getInitialUrlParams = () => {
|
|
15570
|
+
if (typeof window === "undefined") {
|
|
15571
|
+
return {
|
|
15572
|
+
viewId: null,
|
|
15573
|
+
start: null,
|
|
15574
|
+
end: null,
|
|
15575
|
+
period: null,
|
|
15576
|
+
};
|
|
15577
|
+
}
|
|
15578
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
15579
|
+
const viewParam = Number(searchParams.get("view"));
|
|
15580
|
+
const startParam = Number(searchParams.get("start"));
|
|
15581
|
+
const endParam = Number(searchParams.get("end"));
|
|
15582
|
+
const periodParam = searchParams.get("period");
|
|
15583
|
+
return {
|
|
15584
|
+
viewId: Number.isInteger(viewParam) ? viewParam : null,
|
|
15585
|
+
start: Number.isFinite(startParam) ? startParam : null,
|
|
15586
|
+
end: Number.isFinite(endParam) ? endParam : null,
|
|
15587
|
+
period: VALID_SCOPE_VALUES.includes(periodParam)
|
|
15588
|
+
? periodParam
|
|
15589
|
+
: null,
|
|
15590
|
+
};
|
|
15591
|
+
};
|
|
15531
15592
|
const TrendingsPageV2 = () => {
|
|
15532
15593
|
const [autoRefresh, setAutoRefresh] = useState(false);
|
|
15533
|
-
const [chartOptions, setChartOptions] = useState(
|
|
15594
|
+
const [chartOptions, setChartOptions] = useState({
|
|
15595
|
+
showGridLines: true,
|
|
15596
|
+
showSymbols: false,
|
|
15597
|
+
smoothLines: false,
|
|
15598
|
+
steppedLines: true,
|
|
15599
|
+
showLegend: false,
|
|
15600
|
+
showTooltip: true,
|
|
15601
|
+
combinedView: true,
|
|
15602
|
+
showToolbox: true,
|
|
15603
|
+
showYAxisNames: false,
|
|
15604
|
+
});
|
|
15605
|
+
const [aggregationMode, setAggregationMode] = useState("avg");
|
|
15534
15606
|
const [error, setError] = useState("");
|
|
15535
15607
|
const [viewId, setViewId] = useState(null);
|
|
15536
15608
|
const [chartInstance, setChartInstance] = useState(null);
|
|
15537
15609
|
const [dataLoadedTrigger, setDataLoadedTrigger] = useState(0);
|
|
15538
|
-
const { state: { viewSelected, viewTags, timeScopeStart, timeScopeEnd }, actions: { setViews, setViewTagsAndRefetch, setViewSelected, setSeriesMinMax, resetCursors, }, } = useTrendingContextV2();
|
|
15610
|
+
const { state: { viewSelected, viewTags, timeScopeStart, timeScopeEnd, scope }, actions: { setViews, setViewTagsAndRefetch, setViewSelected, setTotalScope, setSeriesMinMax, resetCursors, }, } = useTrendingContextV2();
|
|
15611
|
+
const initialUrlParamsRef = useRef(getInitialUrlParams());
|
|
15612
|
+
const initialTimeScopeAppliedRef = useRef(false);
|
|
15613
|
+
const initialViewSelectionResolvedRef = useRef(false);
|
|
15539
15614
|
// Fetch views
|
|
15540
15615
|
const { data: views, isLoading: viewsLoading, isError: viewsIsError, error: viewsError, isSuccess: viewSuccess, } = useSearchViews({ autoRefresh });
|
|
15541
15616
|
// Fetch view tags
|
|
@@ -15580,6 +15655,7 @@ const TrendingsPageV2 = () => {
|
|
|
15580
15655
|
start: timeScopeStart.getTime(),
|
|
15581
15656
|
end: timeScopeEnd.getTime(),
|
|
15582
15657
|
tagIds: queryTagIds,
|
|
15658
|
+
aggregationMode,
|
|
15583
15659
|
autoRefresh,
|
|
15584
15660
|
});
|
|
15585
15661
|
// Filter and reorder series to match current viewTags order
|
|
@@ -15634,6 +15710,21 @@ const TrendingsPageV2 = () => {
|
|
|
15634
15710
|
}, [series, tagIds, queryTagIds, viewTags]);
|
|
15635
15711
|
// Calculate overall min/max values from filtered series data
|
|
15636
15712
|
const seriesMinMaxData = useSeriesMinMax(filteredSeries, tagIds);
|
|
15713
|
+
// Apply explicit time range from URL once on initial load
|
|
15714
|
+
useEffect(() => {
|
|
15715
|
+
if (initialTimeScopeAppliedRef.current)
|
|
15716
|
+
return;
|
|
15717
|
+
const { start, end, period } = initialUrlParamsRef.current;
|
|
15718
|
+
initialTimeScopeAppliedRef.current = true;
|
|
15719
|
+
if (start === null || end === null || period === null || start >= end) {
|
|
15720
|
+
return;
|
|
15721
|
+
}
|
|
15722
|
+
setTotalScope({
|
|
15723
|
+
start: new Date(start),
|
|
15724
|
+
end: new Date(end),
|
|
15725
|
+
scope: period,
|
|
15726
|
+
});
|
|
15727
|
+
}, [setTotalScope]);
|
|
15637
15728
|
// Load initial view when views are fetched
|
|
15638
15729
|
useEffect(() => {
|
|
15639
15730
|
if (!viewSuccess || !views || !Array.isArray(views))
|
|
@@ -15642,12 +15733,26 @@ const TrendingsPageV2 = () => {
|
|
|
15642
15733
|
setViews(views);
|
|
15643
15734
|
// Only set initial view if none is selected
|
|
15644
15735
|
if (!viewSelected) {
|
|
15736
|
+
const initialViewId = initialUrlParamsRef.current.viewId;
|
|
15737
|
+
if (!initialViewSelectionResolvedRef.current && initialViewId !== null) {
|
|
15738
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15739
|
+
const urlView = views.find((view) => view.ViewId === initialViewId);
|
|
15740
|
+
if (urlView) {
|
|
15741
|
+
setViewId(urlView.ViewId);
|
|
15742
|
+
setViewSelected(urlView);
|
|
15743
|
+
return;
|
|
15744
|
+
}
|
|
15745
|
+
}
|
|
15645
15746
|
const lastCreated = views.reduce((prev, current) => prev && prev.ViewId > current.ViewId ? prev : current, null);
|
|
15646
15747
|
if (lastCreated) {
|
|
15748
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15647
15749
|
setViewId(lastCreated.ViewId);
|
|
15648
15750
|
setViewSelected(lastCreated);
|
|
15649
15751
|
}
|
|
15650
15752
|
}
|
|
15753
|
+
else {
|
|
15754
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15755
|
+
}
|
|
15651
15756
|
}, [viewSuccess, views, viewSelected, setViews, setViewSelected]);
|
|
15652
15757
|
// Update viewId when viewSelected changes (e.g., from LoadViewModal)
|
|
15653
15758
|
useEffect(() => {
|
|
@@ -15655,6 +15760,26 @@ const TrendingsPageV2 = () => {
|
|
|
15655
15760
|
setViewId(viewSelected.ViewId);
|
|
15656
15761
|
}
|
|
15657
15762
|
}, [viewSelected]);
|
|
15763
|
+
useEffect(() => {
|
|
15764
|
+
if (typeof window === "undefined" ||
|
|
15765
|
+
!initialTimeScopeAppliedRef.current ||
|
|
15766
|
+
!initialViewSelectionResolvedRef.current) {
|
|
15767
|
+
return;
|
|
15768
|
+
}
|
|
15769
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
15770
|
+
if (viewSelected) {
|
|
15771
|
+
searchParams.set("view", String(viewSelected.ViewId));
|
|
15772
|
+
}
|
|
15773
|
+
else {
|
|
15774
|
+
searchParams.delete("view");
|
|
15775
|
+
}
|
|
15776
|
+
searchParams.set("start", String(timeScopeStart.getTime()));
|
|
15777
|
+
searchParams.set("end", String(timeScopeEnd.getTime()));
|
|
15778
|
+
searchParams.set("period", scope);
|
|
15779
|
+
const newSearch = searchParams.toString();
|
|
15780
|
+
const newUrl = `${window.location.pathname}${newSearch ? `?${newSearch}` : ""}${window.location.hash}`;
|
|
15781
|
+
window.history.replaceState(null, "", newUrl);
|
|
15782
|
+
}, [viewSelected, timeScopeStart, timeScopeEnd, scope]);
|
|
15658
15783
|
// Load view tags when fetched - ONLY when viewId changes, not on every data refetch
|
|
15659
15784
|
// This preserves local order changes (from drag-and-drop) until a new view is loaded
|
|
15660
15785
|
const loadedViewIdRef = useRef(null);
|
|
@@ -15806,7 +15931,7 @@ const TrendingsPageV2 = () => {
|
|
|
15806
15931
|
} },
|
|
15807
15932
|
React__default.createElement(CircularProgress, { size: "3rem" }))),
|
|
15808
15933
|
React__default.createElement("div", { style: { flexShrink: 0 } },
|
|
15809
|
-
React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, chartInstance: chartInstance })),
|
|
15934
|
+
React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, setAggregationMode: setAggregationMode, chartInstance: chartInstance })),
|
|
15810
15935
|
React__default.createElement(Divider, { sx: { my: 2 } }),
|
|
15811
15936
|
React__default.createElement("div", { style: {
|
|
15812
15937
|
flexGrow: 1,
|