@dexteel/mesf-core 7.5.2 → 7.7.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/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
2
2
  export * from '@microsoft/signalr';
3
3
  export { LicenseManager } from 'ag-grid-enterprise';
4
- import { styled, DialogTitle as DialogTitle$1, DialogContent as DialogContent$1, DialogActions as DialogActions$1, Grid2, Button, Box, MenuItem, ListItemIcon, createTheme, TextField, Alert as Alert$2, useTheme, InputAdornment, Popover, MenuList, ListItemText, alpha, Dialog as Dialog$1, Paper, List, ListItem, Chip, SvgIcon, Typography as Typography$1, Checkbox, IconButton as IconButton$1, CircularProgress, FormControl, FormHelperText, FormControlLabel, Snackbar, DialogContentText, Badge, InputLabel, Select, Input, Divider, Card, CardContent, CardActions, Collapse, Tooltip, CssBaseline, AppBar, Toolbar, Container, Menu, Switch, Hidden, Drawer, useMediaQuery, ListSubheader, ListItemButton, Autocomplete as Autocomplete$1, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, debounce, StyledEngineProvider, ThemeProvider, ListItemSecondaryAction } from '@mui/material';
4
+ import { styled, DialogTitle as DialogTitle$1, DialogContent as DialogContent$1, DialogActions as DialogActions$1, Grid2, Button, Box, MenuItem, ListItemIcon, createTheme, TextField, Alert as Alert$2, useTheme, InputAdornment, Popover, MenuList, ListItemText, alpha, Dialog as Dialog$1, Paper, List, ListItem, Chip, SvgIcon, Typography as Typography$1, Checkbox, IconButton as IconButton$1, CircularProgress, FormControl, FormHelperText, FormControlLabel, Snackbar, DialogContentText, Badge, InputLabel, Select, Input, Divider, Card, CardContent, CardActions, Collapse, Tooltip, CssBaseline, AppBar, Toolbar, Container, Menu, Switch, Hidden, Drawer, Grid, Accordion, AccordionSummary, AccordionDetails, Tabs, Tab, Autocomplete as Autocomplete$1, useMediaQuery, ListSubheader, ListItemButton, TableContainer, Table, TableHead, TableRow, TableCell, TableBody, debounce, StyledEngineProvider, ThemeProvider, ListItemSecondaryAction } from '@mui/material';
5
5
  import { useMutation, useQuery, useQueryClient, QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
6
  import * as React from 'react';
7
7
  import React__default, { createContext, useContext, useRef, useState, useEffect, useCallback, useMemo, Component, lazy, Suspense } from 'react';
@@ -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, Square as Square$1, Timeline, Send, Menu as Menu$1, People, Storage, Group, Assignment, Chat, ViewList, Build, Settings as Settings$2, FastRewind, FastForward, ZoomIn, Restore, Lock, Create, Delete, Folder, InsertChart, Search, PlaylistAdd, DragIndicator, Save, AttachFile, CloudUpload, GetApp } from '@mui/icons-material';
28
+ import { ArrowRight, ArrowBackRounded, ArrowForwardRounded, SkipNext, ChevronLeft, ChevronRight, Cloud, Square as Square$1, Timeline, Send, Menu as Menu$1, People, Storage, Group, Assignment, Chat, ViewList, Build, Settings as Settings$2, Code as Code$1, FastRewind, FastForward, ZoomIn, Restore, Lock, Create, Delete, Folder, InsertChart, Search, PlaylistAdd, DragIndicator, Save, AttachFile, CloudUpload, GetApp } from '@mui/icons-material';
29
29
  import FormatListBulletedSharpIcon from '@mui/icons-material/FormatListBulletedSharp';
30
30
  import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
31
31
  import CloseIcon from '@mui/icons-material/Close';
@@ -55,7 +55,11 @@ import { DndProvider } from 'react-dnd';
55
55
  import { HTML5Backend } from 'react-dnd-html5-backend';
56
56
  import MenuIcon from '@mui/icons-material/Menu';
57
57
  import ShowChartIcon from '@mui/icons-material/ShowChart';
58
+ import { DateTimePicker as DateTimePicker$1 } from '@mui/x-date-pickers/DateTimePicker';
59
+ import ClearAllIcon from '@mui/icons-material/ClearAll';
60
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
58
61
  import axios from 'axios';
62
+ import { Group as Group$1, Panel, Separator } from 'react-resizable-panels';
59
63
  import { LocalizationProvider as LocalizationProvider$1 } from '@mui/x-date-pickers/LocalizationProvider';
60
64
  import InsertChartIcon from '@mui/icons-material/InsertChart';
61
65
  import ReactECharts from 'echarts-for-react';
@@ -3856,13 +3860,13 @@ var INITIAL_VALUES$2 = {
3856
3860
  };
3857
3861
 
3858
3862
  var CreateProfile = function (_a) {
3859
- var _b;
3863
+ var _b, _c;
3860
3864
  var show = _a.show, onHide = _a.onHide, suffixTitle = _a.suffixTitle;
3861
- var _c = useState(false), openSnackbar = _c[0], setOpenSnackbar = _c[1];
3862
- var _d = useState(""), message = _d[0], setMessage = _d[1];
3863
- var _e = useState(false), isSubmitLoading = _e[0], setIsSubmitLoading = _e[1];
3864
- var _f = useState(""), error = _f[0], setError = _f[1];
3865
- var _g = useForm({ defaultValues: INITIAL_VALUES$2 }), register = _g.register, handleSubmit = _g.handleSubmit, reset = _g.reset, errors = _g.formState.errors;
3865
+ var _d = useState(false), openSnackbar = _d[0], setOpenSnackbar = _d[1];
3866
+ var _e = useState(""), message = _e[0], setMessage = _e[1];
3867
+ var _f = useState(false), isSubmitLoading = _f[0], setIsSubmitLoading = _f[1];
3868
+ var _g = useState(""), error = _g[0], setError = _g[1];
3869
+ var _h = useForm({ defaultValues: INITIAL_VALUES$2 }), register = _h.register, handleSubmit = _h.handleSubmit, reset = _h.reset, errors = _h.formState.errors;
3866
3870
  var createProfile = useMutation({
3867
3871
  mutationFn: upsertProfile,
3868
3872
  onSuccess: function () {
@@ -3912,9 +3916,18 @@ var CreateProfile = function (_a) {
3912
3916
  React.createElement(MesfModal.Content, { style: { padding: "15px 30px" } },
3913
3917
  React.createElement(Grid2, { container: true, spacing: 1 },
3914
3918
  React.createElement(Grid2, { size: { md: 12, xs: 12 } },
3915
- React.createElement(TextField, __assign({}, register("ProfileName", { required: true }), { label: "Profile name", variant: "outlined", error: !!errors.ProfileName, fullWidth: true, margin: "dense", autoComplete: "off" })),
3919
+ React.createElement(TextField, __assign({}, register("ProfileName", {
3920
+ required: true,
3921
+ validate: {
3922
+ notWhitespace: function (value) {
3923
+ return value.trim() !== "" ||
3924
+ "Profile name cannot be only whitespace";
3925
+ },
3926
+ },
3927
+ }), { label: "Profile name", variant: "outlined", error: !!errors.ProfileName, fullWidth: true, margin: "dense", autoComplete: "off" })),
3916
3928
  " ",
3917
- ((_b = errors.ProfileName) === null || _b === void 0 ? void 0 : _b.type) === "required" && (React.createElement("span", { style: { fontSize: 12, color: "#F44336" } }, "Profile name is required"))))),
3929
+ ((_b = errors.ProfileName) === null || _b === void 0 ? void 0 : _b.type) === "required" && (React.createElement("span", { style: { fontSize: 12, color: "#F44336" } }, "Profile name is required")),
3930
+ ((_c = errors.ProfileName) === null || _c === void 0 ? void 0 : _c.type) === "notWhitespace" && (React.createElement("span", { style: { fontSize: 12, color: "#F44336" } }, errors.ProfileName.message))))),
3918
3931
  React.createElement(MesfModal.Actions, { style: { padding: "20px 30px 30px" } },
3919
3932
  React.createElement(Grid2, { container: true, spacing: 2, justifyContent: "flex-end" },
3920
3933
  React.createElement(Grid2, { size: { md: 3, xs: 12 }, style: { margin: 0 } },
@@ -10964,6 +10977,448 @@ var Settings = function () {
10964
10977
  return React__default.createElement(SettingsPage, null);
10965
10978
  };
10966
10979
 
10980
+ var getDefaultValue = function (dataType) {
10981
+ var type = dataType.toLowerCase();
10982
+ if ([
10983
+ "int",
10984
+ "bigint",
10985
+ "smallint",
10986
+ "tinyint",
10987
+ "decimal",
10988
+ "float",
10989
+ "real",
10990
+ "money",
10991
+ "numeric",
10992
+ ].includes(type)) {
10993
+ return "";
10994
+ }
10995
+ if (["datetime", "datetime2", "date", "smalldatetime"].includes(type)) {
10996
+ return null;
10997
+ }
10998
+ if (type === "bit") {
10999
+ return false;
11000
+ }
11001
+ return "";
11002
+ };
11003
+ var renderInput = function (param, onChange, disabled) {
11004
+ var type = param.dataType.toLowerCase();
11005
+ if (["int", "bigint", "smallint", "tinyint"].includes(type)) {
11006
+ return (React__default.createElement(TextField, { type: "number", label: param.parameterName, value: param.value, onChange: function (e) {
11007
+ return onChange(e.target.value === "" ? "" : Number(e.target.value));
11008
+ }, disabled: disabled, fullWidth: true, size: "small", inputProps: { step: 1 } }));
11009
+ }
11010
+ if (["decimal", "float", "real", "money", "numeric"].includes(type)) {
11011
+ return (React__default.createElement(TextField, { type: "number", label: param.parameterName, value: param.value, onChange: function (e) {
11012
+ return onChange(e.target.value === "" ? "" : Number(e.target.value));
11013
+ }, disabled: disabled, fullWidth: true, size: "small", inputProps: { step: "any" } }));
11014
+ }
11015
+ if (["datetime", "datetime2", "date", "smalldatetime"].includes(type)) {
11016
+ return (React__default.createElement(DateTimePicker$1, { label: param.parameterName, value: param.value ? moment$8(param.value) : null, onChange: function (newValue) { return onChange((newValue === null || newValue === void 0 ? void 0 : newValue.toDate()) || null); }, disabled: disabled, slotProps: {
11017
+ textField: {
11018
+ fullWidth: true,
11019
+ size: "small",
11020
+ },
11021
+ } }));
11022
+ }
11023
+ if (type === "bit") {
11024
+ return (React__default.createElement(FormControlLabel, { control: React__default.createElement(Checkbox, { checked: !!param.value, onChange: function (e) { return onChange(e.target.checked); }, disabled: disabled }), label: param.parameterName }));
11025
+ }
11026
+ // Default: text field for varchar, nvarchar, char, etc.
11027
+ return (React__default.createElement(TextField, { label: param.parameterName, value: param.value, onChange: function (e) { return onChange(e.target.value); }, disabled: disabled, fullWidth: true, size: "small", multiline: type.includes("text") || type.includes("max"), rows: type.includes("text") || type.includes("max") ? 3 : 1 }));
11028
+ };
11029
+ var DynamicParameterForm = function (_a) {
11030
+ var parameters = _a.parameters, onExecute = _a.onExecute, isExecuting = _a.isExecuting;
11031
+ var _b = useState([]), formState = _b[0], setFormState = _b[1];
11032
+ useEffect(function () {
11033
+ var initialState = parameters.map(function (p) { return ({
11034
+ parameterName: p.ParameterName,
11035
+ include: !p.IsOptional, // Required params start included and locked
11036
+ sendAsNull: false,
11037
+ value: getDefaultValue(p.DataType),
11038
+ dataType: p.DataType,
11039
+ isOptional: p.IsOptional,
11040
+ }); });
11041
+ setFormState(initialState);
11042
+ }, [parameters]);
11043
+ var updateParam = function (index, field, value) {
11044
+ setFormState(function (prev) {
11045
+ var _a;
11046
+ var updated = __spreadArray([], prev, true);
11047
+ updated[index] = __assign(__assign({}, updated[index]), (_a = {}, _a[field] = value, _a));
11048
+ // If "sendAsNull" is checked, include must be true
11049
+ if (field === "sendAsNull" && value === true) {
11050
+ updated[index].include = true;
11051
+ }
11052
+ // If "include" is unchecked, sendAsNull must be false
11053
+ if (field === "include" && value === false) {
11054
+ updated[index].sendAsNull = false;
11055
+ }
11056
+ return updated;
11057
+ });
11058
+ };
11059
+ var handleExecute = function () {
11060
+ onExecute(formState);
11061
+ };
11062
+ if (parameters.length === 0) {
11063
+ return (React__default.createElement(Paper, { sx: { p: 2 } },
11064
+ React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary" }, "This stored procedure has no parameters."),
11065
+ React__default.createElement(Button, { variant: "contained", onClick: handleExecute, disabled: isExecuting, sx: { mt: 2 } }, isExecuting ? "Executing..." : "Execute")));
11066
+ }
11067
+ return (React__default.createElement(Paper, { sx: { p: 2 } },
11068
+ React__default.createElement(Typography$1, { variant: "subtitle1", sx: { mb: 2, fontWeight: 600 } }, "Parameters"),
11069
+ React__default.createElement(Grid, { container: true, spacing: 2 }, formState.map(function (param, index) {
11070
+ var isInputDisabled = !param.include || param.sendAsNull;
11071
+ var isIncludeDisabled = !param.isOptional; // Required params can't be unchecked
11072
+ return (React__default.createElement(Grid, { item: true, xs: 12, key: param.parameterName },
11073
+ React__default.createElement(Box, { sx: {
11074
+ display: "flex",
11075
+ alignItems: "center",
11076
+ gap: 2,
11077
+ p: 1,
11078
+ borderRadius: 1,
11079
+ bgcolor: param.include ? "transparent" : "action.hover",
11080
+ } },
11081
+ React__default.createElement(FormControlLabel, { control: React__default.createElement(Checkbox, { checked: param.include, onChange: function (e) {
11082
+ return updateParam(index, "include", e.target.checked);
11083
+ }, disabled: isIncludeDisabled, size: "small" }), label: "Include", sx: { minWidth: 100 } }),
11084
+ React__default.createElement(FormControlLabel, { control: React__default.createElement(Checkbox, { checked: param.sendAsNull, onChange: function (e) {
11085
+ return updateParam(index, "sendAsNull", e.target.checked);
11086
+ }, disabled: !param.include, size: "small" }), label: "NULL", sx: { minWidth: 80 } }),
11087
+ React__default.createElement(Box, { sx: { flexGrow: 1 } }, renderInput(param, function (value) { return updateParam(index, "value", value); }, isInputDisabled)),
11088
+ React__default.createElement(Typography$1, { variant: "caption", color: "text.secondary", sx: { minWidth: 80 } },
11089
+ param.dataType,
11090
+ !param.isOptional && (React__default.createElement(Typography$1, { component: "span", color: "error", sx: { ml: 0.5 } }, "*"))))));
11091
+ })),
11092
+ React__default.createElement(Box, { sx: { mt: 3, display: "flex", justifyContent: "flex-end" } },
11093
+ React__default.createElement(Button, { variant: "contained", onClick: handleExecute, disabled: isExecuting, size: "large" }, isExecuting ? "Executing..." : "Execute"))));
11094
+ };
11095
+
11096
+ var SESSION_KEY = "sp-executor-authenticated";
11097
+ var getCurrentPin = function () {
11098
+ var now = new Date();
11099
+ var hours = now.getHours().toString().padStart(2, "0");
11100
+ var minutes = now.getMinutes().toString().padStart(2, "0");
11101
+ return "".concat(hours).concat(minutes);
11102
+ };
11103
+ var PinGate = function (_a) {
11104
+ var children = _a.children;
11105
+ var _b = useState(function () {
11106
+ return sessionStorage.getItem(SESSION_KEY) === "true";
11107
+ }), isAuthenticated = _b[0], setIsAuthenticated = _b[1];
11108
+ var _c = useState(""), pin = _c[0], setPin = _c[1];
11109
+ var _d = useState(""), error = _d[0], setError = _d[1];
11110
+ var handleUnlock = function () {
11111
+ if (pin === getCurrentPin()) {
11112
+ sessionStorage.setItem(SESSION_KEY, "true");
11113
+ setIsAuthenticated(true);
11114
+ setError("");
11115
+ }
11116
+ else {
11117
+ setError("Incorrect PIN. Please try again.");
11118
+ setPin("");
11119
+ }
11120
+ };
11121
+ var handleKeyDown = function (e) {
11122
+ if (e.key === "Enter") {
11123
+ handleUnlock();
11124
+ }
11125
+ };
11126
+ if (isAuthenticated) {
11127
+ return React__default.createElement(React__default.Fragment, null, children);
11128
+ }
11129
+ return (React__default.createElement(Box, { sx: {
11130
+ display: "flex",
11131
+ justifyContent: "center",
11132
+ alignItems: "center",
11133
+ minHeight: "60vh",
11134
+ } },
11135
+ React__default.createElement(Paper, { elevation: 3, sx: {
11136
+ p: 4,
11137
+ maxWidth: 400,
11138
+ width: "100%",
11139
+ textAlign: "center",
11140
+ } },
11141
+ React__default.createElement(LockIcon, { sx: { fontSize: 48, color: "primary.main", mb: 2 } }),
11142
+ React__default.createElement(Typography$1, { variant: "h5", sx: { mb: 1, fontWeight: 600 } }, "Access Required"),
11143
+ React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary", sx: { mb: 3 } }, "Enter PIN to access the SP Executor"),
11144
+ React__default.createElement(TextField, { type: "password", label: "PIN", variant: "outlined", fullWidth: true, value: pin, onChange: function (e) { return setPin(e.target.value); }, onKeyDown: handleKeyDown, error: !!error, helperText: error, sx: { mb: 2 }, autoFocus: true }),
11145
+ React__default.createElement(Button, { variant: "contained", fullWidth: true, onClick: handleUnlock, disabled: !pin }, "Unlock"))));
11146
+ };
11147
+
11148
+ var defaultColDef = {
11149
+ flex: 1,
11150
+ filter: false,
11151
+ sortable: true,
11152
+ resizable: true,
11153
+ };
11154
+ var parseResults = function (data) {
11155
+ if (!data || !data.tables)
11156
+ return [];
11157
+ return data.tables.map(function (table) {
11158
+ var _a;
11159
+ var rows = table.rows || [];
11160
+ var columns = rows.length > 0
11161
+ ? Object.keys(rows[0])
11162
+ : ((_a = table.columns) === null || _a === void 0 ? void 0 : _a.map(function (c) { return c.name; })) || [];
11163
+ return { rows: rows, columns: columns };
11164
+ });
11165
+ };
11166
+ var formatTimestamp = function (date) {
11167
+ return date.toLocaleTimeString("en-US", {
11168
+ hour: "2-digit",
11169
+ minute: "2-digit",
11170
+ second: "2-digit",
11171
+ hour12: false,
11172
+ });
11173
+ };
11174
+ var formatDuration = function (ms) {
11175
+ if (ms < 1000)
11176
+ return "".concat(ms, "ms");
11177
+ return "".concat((ms / 1000).toFixed(2), "s");
11178
+ };
11179
+ var formatParameters = function (params) {
11180
+ if (params.length === 0)
11181
+ return "No parameters";
11182
+ return params
11183
+ .map(function (p) { return "".concat(p.name, "=").concat(p.value === null ? "NULL" : p.value); })
11184
+ .join(", ");
11185
+ };
11186
+ var ResultItem = function (_a) {
11187
+ var result = _a.result, onDelete = _a.onDelete, defaultExpanded = _a.defaultExpanded;
11188
+ var _b = useState(0), activeTab = _b[0], setActiveTab = _b[1];
11189
+ var resultSets = useMemo(function () { return parseResults(result.data); }, [result.data]);
11190
+ var getColumnDefs = function (columns) {
11191
+ return columns.map(function (col) { return ({
11192
+ field: col,
11193
+ headerName: col,
11194
+ minWidth: 100,
11195
+ flex: 1,
11196
+ cellRenderer: function (params) {
11197
+ var value = params.value;
11198
+ if (value === null || value === undefined) {
11199
+ return (React__default.createElement("span", { style: { color: "#999", fontStyle: "italic" } }, "NULL"));
11200
+ }
11201
+ if (typeof value === "boolean") {
11202
+ return value ? "true" : "false";
11203
+ }
11204
+ return String(value);
11205
+ },
11206
+ }); });
11207
+ };
11208
+ var getTotalRows = function () {
11209
+ return resultSets.reduce(function (sum, rs) { return sum + rs.rows.length; }, 0);
11210
+ };
11211
+ return (React__default.createElement(Accordion, { defaultExpanded: defaultExpanded },
11212
+ React__default.createElement(AccordionSummary, { expandIcon: React__default.createElement(ExpandMoreIcon, null), sx: {
11213
+ bgcolor: result.isError ? "error.light" : "background.paper",
11214
+ "&:hover": { bgcolor: result.isError ? "error.light" : "grey.100" },
11215
+ } },
11216
+ React__default.createElement(Box, { sx: {
11217
+ display: "flex",
11218
+ alignItems: "center",
11219
+ width: "100%",
11220
+ gap: 2,
11221
+ pr: 2,
11222
+ } },
11223
+ React__default.createElement(Typography$1, { variant: "subtitle2", sx: { fontWeight: 600, minWidth: 80 } }, formatTimestamp(result.timestamp)),
11224
+ React__default.createElement(Typography$1, { variant: "body2", sx: {
11225
+ flexGrow: 1,
11226
+ overflow: "hidden",
11227
+ textOverflow: "ellipsis",
11228
+ whiteSpace: "nowrap",
11229
+ } }, result.procedureName),
11230
+ React__default.createElement(Chip, { label: formatDuration(result.duration), size: "small", color: result.duration > 5000 ? "warning" : "default", sx: { minWidth: 60 } }),
11231
+ !result.isError && (React__default.createElement(Chip, { label: "".concat(getTotalRows(), " rows"), size: "small", color: "primary", variant: "outlined", sx: { minWidth: 70 } })),
11232
+ result.isError && (React__default.createElement(Chip, { label: "Error", size: "small", color: "error", sx: { minWidth: 60 } })),
11233
+ React__default.createElement(Tooltip, { title: "Delete this result" },
11234
+ React__default.createElement(IconButton$1, { size: "small", onClick: function (e) {
11235
+ e.stopPropagation();
11236
+ onDelete();
11237
+ }, sx: { ml: 1 } },
11238
+ React__default.createElement(DeleteIcon, { fontSize: "small" }))))),
11239
+ React__default.createElement(AccordionDetails, null,
11240
+ React__default.createElement(Typography$1, { variant: "caption", color: "text.secondary", sx: { mb: 1, display: "block" } },
11241
+ "Parameters: ",
11242
+ formatParameters(result.parameters)),
11243
+ result.isError ? (React__default.createElement(Typography$1, { color: "error", variant: "body2" }, result.errorMessage)) : resultSets.length === 0 ? (React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary" }, "The stored procedure executed successfully but returned no result sets.")) : (React__default.createElement(React__default.Fragment, null,
11244
+ resultSets.length > 1 && (React__default.createElement(Tabs, { value: activeTab, onChange: function (_, newValue) { return setActiveTab(newValue); }, sx: { mb: 1 } }, resultSets.map(function (rs, index) { return (React__default.createElement(Tab, { key: index, label: "Result Set ".concat(index + 1, " (").concat(rs.rows.length, ")") })); }))),
11245
+ resultSets.map(function (resultSet, index) { return (React__default.createElement(Box, { key: index, sx: {
11246
+ display: activeTab === index ? "block" : "none",
11247
+ height: 300,
11248
+ } }, resultSet.rows.length === 0 ? (React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary" }, "No rows returned.")) : (React__default.createElement(AgGridReact, { rowData: resultSet.rows, columnDefs: getColumnDefs(resultSet.columns), defaultColDef: defaultColDef, domLayout: "normal" })))); }))))));
11249
+ };
11250
+ var ResultsList = function (_a) {
11251
+ var results = _a.results, onDeleteResult = _a.onDeleteResult, onClearAll = _a.onClearAll;
11252
+ if (results.length === 0) {
11253
+ return (React__default.createElement(Paper, { sx: { p: 3, textAlign: "center" } },
11254
+ React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary" }, "Execute a stored procedure to see results here.")));
11255
+ }
11256
+ return (React__default.createElement(Paper, { sx: { p: 2 } },
11257
+ React__default.createElement(Box, { sx: {
11258
+ display: "flex",
11259
+ justifyContent: "space-between",
11260
+ alignItems: "center",
11261
+ mb: 2,
11262
+ } },
11263
+ React__default.createElement(Typography$1, { variant: "subtitle1", sx: { fontWeight: 600 } },
11264
+ "Execution Results (",
11265
+ results.length,
11266
+ ")"),
11267
+ React__default.createElement(Button, { variant: "outlined", color: "error", size: "small", startIcon: React__default.createElement(ClearAllIcon, null), onClick: onClearAll }, "Clear All")),
11268
+ React__default.createElement(Box, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, results.map(function (result, index) { return (React__default.createElement(ResultItem, { key: result.id, result: result, onDelete: function () { return onDeleteResult(result.id); }, defaultExpanded: index === 0 })); }))));
11269
+ };
11270
+
11271
+ var SPAutocomplete = function (_a) {
11272
+ var procedures = _a.procedures, value = _a.value, onChange = _a.onChange, isLoading = _a.isLoading, _b = _a.disabled, disabled = _b === void 0 ? false : _b;
11273
+ return (React__default.createElement(Autocomplete$1, { options: procedures, value: value, onChange: function (_, newValue) { return onChange(newValue); }, getOptionLabel: function (option) { return option.FullName; }, groupBy: function (option) { return option.SchemaName; }, disabled: disabled, isOptionEqualToValue: function (option, val) { return option.FullName === val.FullName; }, renderInput: function (params) { return (React__default.createElement(TextField, __assign({}, params, { label: "Select Stored Procedure", variant: "outlined", fullWidth: true, slotProps: {
11274
+ input: __assign(__assign({}, params.InputProps), { endAdornment: (React__default.createElement(React__default.Fragment, null, isLoading ? (React__default.createElement(CircularProgress, { color: "inherit", size: 20 })) : (params.InputProps.endAdornment))) }),
11275
+ } }))); }, renderOption: function (props, option) { return (React__default.createElement("li", __assign({}, props, { key: option.FullName }),
11276
+ option.SchemaName,
11277
+ ".",
11278
+ option.ProcedureName)); } }));
11279
+ };
11280
+
11281
+ var getStoredProceduresWithParameters = function (schemaFilter) { return __awaiter(void 0, void 0, void 0, function () {
11282
+ var apiService, parameters;
11283
+ return __generator(this, function (_a) {
11284
+ switch (_a.label) {
11285
+ case 0:
11286
+ apiService = new MESApiService();
11287
+ parameters = [];
11288
+ if (schemaFilter) {
11289
+ parameters.push({ name: "SchemaFilter", value: schemaFilter });
11290
+ }
11291
+ return [4 /*yield*/, apiService.callV2("[SYSTEM].[GetStoredProceduresWithParameters]", parameters)];
11292
+ case 1: return [2 /*return*/, _a.sent()];
11293
+ }
11294
+ });
11295
+ }); };
11296
+ var executeStoredProcedure = function (procedureName, parameters) { return __awaiter(void 0, void 0, void 0, function () {
11297
+ var apiService;
11298
+ return __generator(this, function (_a) {
11299
+ switch (_a.label) {
11300
+ case 0:
11301
+ apiService = new MESApiService();
11302
+ return [4 /*yield*/, apiService.callV2(procedureName, parameters)];
11303
+ case 1: return [2 /*return*/, _a.sent()];
11304
+ }
11305
+ });
11306
+ }); };
11307
+
11308
+ var SPExecutorPage = function () {
11309
+ var _a = useState([]), procedures = _a[0], setProcedures = _a[1];
11310
+ var _b = useState([]), allParameters = _b[0], setAllParameters = _b[1];
11311
+ var _c = useState(null), selectedProcedure = _c[0], setSelectedProcedure = _c[1];
11312
+ var _d = useState([]), executionResults = _d[0], setExecutionResults = _d[1];
11313
+ var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1];
11314
+ var _f = useState(false), isExecuting = _f[0], setIsExecuting = _f[1];
11315
+ var _g = useState(""), error = _g[0], setError = _g[1];
11316
+ var _h = useState(true), accumulateResults = _h[0], setAccumulateResults = _h[1];
11317
+ var loadData = function () { return __awaiter(void 0, void 0, void 0, function () {
11318
+ var resp, procs, params;
11319
+ return __generator(this, function (_a) {
11320
+ switch (_a.label) {
11321
+ case 0:
11322
+ setIsLoading(true);
11323
+ setError("");
11324
+ return [4 /*yield*/, getStoredProceduresWithParameters()];
11325
+ case 1:
11326
+ resp = _a.sent();
11327
+ if (resp.ok) {
11328
+ procs = get(resp, "data.tables[0].rows", []);
11329
+ params = get(resp, "data.tables[1].rows", []);
11330
+ setProcedures(procs);
11331
+ setAllParameters(params);
11332
+ }
11333
+ else {
11334
+ setError(resp.message);
11335
+ }
11336
+ setIsLoading(false);
11337
+ return [2 /*return*/];
11338
+ }
11339
+ });
11340
+ }); };
11341
+ useEffect(function () {
11342
+ loadData();
11343
+ }, []);
11344
+ var currentParameters = useMemo(function () {
11345
+ if (!selectedProcedure)
11346
+ return [];
11347
+ return allParameters.filter(function (p) { return p.FullName === selectedProcedure.FullName; });
11348
+ }, [selectedProcedure, allParameters]);
11349
+ var handleProcedureChange = function (proc) {
11350
+ setSelectedProcedure(proc);
11351
+ };
11352
+ var handleExecute = function (formState) { return __awaiter(void 0, void 0, void 0, function () {
11353
+ var startTime, parameters, resp, duration, newResult;
11354
+ return __generator(this, function (_a) {
11355
+ switch (_a.label) {
11356
+ case 0:
11357
+ if (!selectedProcedure)
11358
+ return [2 /*return*/];
11359
+ setIsExecuting(true);
11360
+ setError("");
11361
+ startTime = Date.now();
11362
+ parameters = formState
11363
+ .filter(function (p) { return p.include; })
11364
+ .map(function (p) { return ({
11365
+ name: p.parameterName,
11366
+ value: p.sendAsNull ? null : p.value,
11367
+ }); });
11368
+ return [4 /*yield*/, executeStoredProcedure(selectedProcedure.FullName, parameters)];
11369
+ case 1:
11370
+ resp = _a.sent();
11371
+ duration = Date.now() - startTime;
11372
+ newResult = {
11373
+ id: "".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9)),
11374
+ procedureName: selectedProcedure.FullName,
11375
+ parameters: parameters,
11376
+ timestamp: new Date(),
11377
+ duration: duration,
11378
+ data: resp.ok ? resp.data : null,
11379
+ isError: !resp.ok,
11380
+ errorMessage: resp.ok ? undefined : resp.message,
11381
+ };
11382
+ if (accumulateResults) {
11383
+ setExecutionResults(function (prev) { return __spreadArray([newResult], prev, true); });
11384
+ }
11385
+ else {
11386
+ setExecutionResults([newResult]);
11387
+ }
11388
+ if (!resp.ok) {
11389
+ setError(resp.message);
11390
+ }
11391
+ setIsExecuting(false);
11392
+ return [2 /*return*/];
11393
+ }
11394
+ });
11395
+ }); };
11396
+ var handleDeleteResult = function (id) {
11397
+ setExecutionResults(function (prev) { return prev.filter(function (r) { return r.id !== id; }); });
11398
+ };
11399
+ var handleClearAllResults = function () {
11400
+ setExecutionResults([]);
11401
+ };
11402
+ return (React__default.createElement(PinGate, null,
11403
+ React__default.createElement(HelmetDexteel, { title: "SP Executor" }),
11404
+ React__default.createElement(Grid, { container: true, spacing: 2, sx: { p: 2 } },
11405
+ React__default.createElement(Grid, { item: true, xs: 12 },
11406
+ React__default.createElement(Typography$1, { variant: "h5", sx: { fontWeight: 600 } }, "Stored Procedure Executor"),
11407
+ React__default.createElement(Typography$1, { variant: "body2", color: "text.secondary" }, "Select a stored procedure and configure its parameters to execute.")),
11408
+ React__default.createElement(Grid, { item: true, xs: 12 },
11409
+ React__default.createElement(Paper, { sx: { p: 2 } },
11410
+ React__default.createElement(Grid, { container: true, spacing: 2, alignItems: "center" },
11411
+ React__default.createElement(Grid, { item: true, xs: 12, md: 9 },
11412
+ React__default.createElement(SPAutocomplete, { procedures: procedures, value: selectedProcedure, onChange: handleProcedureChange, isLoading: isLoading })),
11413
+ React__default.createElement(Grid, { item: true, xs: 12, md: 3 },
11414
+ React__default.createElement(FormControlLabel, { control: React__default.createElement(Switch, { checked: accumulateResults, onChange: function (e) { return setAccumulateResults(e.target.checked); }, color: "primary" }), label: "Accumulate results" }))))),
11415
+ selectedProcedure && (React__default.createElement(Grid, { item: true, xs: 12 },
11416
+ React__default.createElement(DynamicParameterForm, { parameters: currentParameters, onExecute: handleExecute, isExecuting: isExecuting }))),
11417
+ React__default.createElement(Grid, { item: true, xs: 12 },
11418
+ React__default.createElement(ResultsList, { results: executionResults, onDeleteResult: handleDeleteResult, onClearAll: handleClearAllResults }))),
11419
+ React__default.createElement(ErrorModal, { error: error, onHide: function () { return setError(""); } })));
11420
+ };
11421
+
10967
11422
  var Configuration = function () {
10968
11423
  var option = useParams().option;
10969
11424
  var _a = useContext(ConfigurationContext), customConfiguration = _a[0], CustomSidebar = _a[1];
@@ -11017,6 +11472,11 @@ var Configuration = function () {
11017
11472
  path: "real-time/config",
11018
11473
  sidebar: function () { return React__default.createElement("div", null, "Config"); },
11019
11474
  main: function () { return React__default.createElement(QueryCacheInvalidations, null); },
11475
+ },
11476
+ {
11477
+ path: "sp-executor",
11478
+ sidebar: function () { return React__default.createElement("div", null, "SP Executor"); },
11479
+ main: function () { return React__default.createElement(SPExecutorPage, null); },
11020
11480
  }
11021
11481
  ], customConfiguration, true);
11022
11482
  // At the top level of your component, add a useEffect to handle window resizing
@@ -11094,7 +11554,11 @@ var Configuration = function () {
11094
11554
  React__default.createElement(ListItemButton, { selected: option === "settings", component: Link, to: "/configuration/settings" },
11095
11555
  React__default.createElement(ListItemIcon, null,
11096
11556
  React__default.createElement(Settings$2, null)),
11097
- React__default.createElement(ListItemText, { primary: "Settings" }))))); };
11557
+ React__default.createElement(ListItemText, { primary: "Settings" })),
11558
+ React__default.createElement(ListItemButton, { selected: option === "sp-executor", component: Link, to: "/configuration/sp-executor" },
11559
+ React__default.createElement(ListItemIcon, null,
11560
+ React__default.createElement(Code$1, null)),
11561
+ React__default.createElement(ListItemText, { primary: "SP Executor" }))))); };
11098
11562
  useEffect(function () {
11099
11563
  var handleListItemClick = function (event) {
11100
11564
  var target = event.target;
@@ -13154,6 +13618,170 @@ var TagsTreeModalV2 = function (_a) {
13154
13618
  React__default.createElement(ErrorModal, { error: error, onHide: function () { return setError(""); } })))));
13155
13619
  };
13156
13620
 
13621
+ var BitSelectorModal = function (_a) {
13622
+ var open = _a.open, handleClose = _a.handleClose, viewTags = _a.viewTags, onAddBits = _a.onAddBits, existingBitTags = _a.existingBitTags;
13623
+ var _b = useState(null), selectedTag = _b[0], setSelectedTag = _b[1];
13624
+ var _c = useState(new Set()), selectedBits = _c[0], setSelectedBits = _c[1];
13625
+ var _d = useState(false), isLoading = _d[0], setIsLoading = _d[1];
13626
+ // Get list of non-bit-extracted tags (source tags only)
13627
+ var availableTags = useMemo(function () {
13628
+ return Object.values(viewTags)
13629
+ .filter(function (t) { return t && t.viewTag && !t.viewTag.IsBitExtracted; })
13630
+ .map(function (t) { return t.viewTag; })
13631
+ .sort(function (a, b) { return a.TagName.localeCompare(b.TagName); });
13632
+ }, [viewTags]);
13633
+ // Check if a specific bit is already extracted for the selected tag
13634
+ var isBitAlreadyExtracted = useCallback(function (bitIndex) {
13635
+ if (!selectedTag)
13636
+ return false;
13637
+ return existingBitTags.has("".concat(selectedTag.TagId, "-").concat(bitIndex));
13638
+ }, [selectedTag, existingBitTags]);
13639
+ // Handle bit checkbox change
13640
+ var handleBitToggle = useCallback(function (bitIndex) {
13641
+ setSelectedBits(function (prev) {
13642
+ var newSet = new Set(prev);
13643
+ if (newSet.has(bitIndex)) {
13644
+ newSet.delete(bitIndex);
13645
+ }
13646
+ else {
13647
+ newSet.add(bitIndex);
13648
+ }
13649
+ return newSet;
13650
+ });
13651
+ }, []);
13652
+ // Select all available bits
13653
+ var handleSelectAll = useCallback(function () {
13654
+ var availableBits = new Set();
13655
+ for (var i = 0; i < 32; i++) {
13656
+ if (!isBitAlreadyExtracted(i)) {
13657
+ availableBits.add(i);
13658
+ }
13659
+ }
13660
+ setSelectedBits(availableBits);
13661
+ }, [isBitAlreadyExtracted]);
13662
+ // Clear all selections
13663
+ var handleClearAll = useCallback(function () {
13664
+ setSelectedBits(new Set());
13665
+ }, []);
13666
+ // Handle tag selection change
13667
+ var handleTagChange = useCallback(function (_event, value) {
13668
+ setSelectedTag(value);
13669
+ setSelectedBits(new Set()); // Clear bit selection when tag changes
13670
+ }, []);
13671
+ // Handle add button click
13672
+ var handleAdd = useCallback(function () {
13673
+ if (!selectedTag || selectedBits.size === 0)
13674
+ return;
13675
+ setIsLoading(true);
13676
+ onAddBits(selectedTag.TagId, Array.from(selectedBits).sort(function (a, b) { return a - b; }));
13677
+ setIsLoading(false);
13678
+ // Reset state and close
13679
+ setSelectedTag(null);
13680
+ setSelectedBits(new Set());
13681
+ handleClose();
13682
+ }, [selectedTag, selectedBits, onAddBits, handleClose]);
13683
+ // Handle cancel
13684
+ var handleCancel = useCallback(function () {
13685
+ setSelectedTag(null);
13686
+ setSelectedBits(new Set());
13687
+ handleClose();
13688
+ }, [handleClose]);
13689
+ // Render bit grid (4 rows x 8 columns)
13690
+ var renderBitGrid = function () {
13691
+ if (!selectedTag) {
13692
+ return (React__default.createElement(Box, { sx: {
13693
+ display: "flex",
13694
+ justifyContent: "center",
13695
+ alignItems: "center",
13696
+ minHeight: "200px",
13697
+ color: "text.secondary",
13698
+ } },
13699
+ React__default.createElement(Typography$1, null, "Select a tag to view available bits")));
13700
+ }
13701
+ var rows = [];
13702
+ for (var row = 0; row < 4; row++) {
13703
+ var bits = [];
13704
+ var _loop_1 = function (col) {
13705
+ var bitIndex = row * 8 + col;
13706
+ var isExtracted = isBitAlreadyExtracted(bitIndex);
13707
+ var isSelected = selectedBits.has(bitIndex);
13708
+ bits.push(React__default.createElement(Grid2, { key: bitIndex, size: 1.5 },
13709
+ React__default.createElement(FormControlLabel, { control: React__default.createElement(Checkbox, { checked: isSelected, onChange: function () { return handleBitToggle(bitIndex); }, disabled: isExtracted, size: "small", sx: {
13710
+ padding: "4px",
13711
+ } }), label: React__default.createElement(Typography$1, { variant: "body2", sx: {
13712
+ color: isExtracted ? "text.disabled" : "text.primary",
13713
+ fontSize: "0.8rem",
13714
+ minWidth: "20px",
13715
+ } }, bitIndex), sx: {
13716
+ margin: 0,
13717
+ "& .MuiFormControlLabel-label": {
13718
+ marginLeft: "2px",
13719
+ },
13720
+ } })));
13721
+ };
13722
+ for (var col = 0; col < 8; col++) {
13723
+ _loop_1(col);
13724
+ }
13725
+ rows.push(React__default.createElement(Grid2, { container: true, key: row, spacing: 0.5, sx: { mb: 0.5 } }, bits));
13726
+ }
13727
+ return rows;
13728
+ };
13729
+ var selectedCount = selectedBits.size;
13730
+ var availableCount = selectedTag
13731
+ ? 32 -
13732
+ Array.from({ length: 32 }, function (_, i) { return i; }).filter(isBitAlreadyExtracted)
13733
+ .length
13734
+ : 0;
13735
+ return (React__default.createElement(MesfModal, { open: open, handleClose: handleCancel, maxWidth: "md", "aria-labelledby": "bit-selector-modal-title", "aria-describedby": "bit-selector-modal-description", title: "Add Bits from Bit Array" },
13736
+ React__default.createElement(MesfModal.Content, { dividers: true },
13737
+ React__default.createElement(Grid2, { container: true, spacing: 2 },
13738
+ React__default.createElement(Grid2, { size: 12 },
13739
+ React__default.createElement(Typography$1, { variant: "subtitle2", sx: { mb: 1 } }, "Select Source Tag"),
13740
+ React__default.createElement(Autocomplete$1, { size: "small", id: "source-tag-selector", options: availableTags, getOptionLabel: function (option) { return option.Alias || option.TagName; }, value: selectedTag, onChange: handleTagChange, noOptionsText: "No tags available in current view", renderOption: function (props, option) { return (React__default.createElement(Box, __assign({}, props, { component: "li" }),
13741
+ React__default.createElement(Box, { sx: {
13742
+ display: "flex",
13743
+ justifyContent: "space-between",
13744
+ alignItems: "center",
13745
+ width: "100%",
13746
+ } },
13747
+ React__default.createElement(Typography$1, { variant: "body2" }, option.Alias || option.TagName),
13748
+ React__default.createElement(Typography$1, { variant: "caption", sx: { color: "text.secondary", ml: 2 } }, option.TagName !== option.Alias ? option.TagName : "")))); }, renderInput: function (params) { return (React__default.createElement(TextField, __assign({}, params, { label: "Source Tag", variant: "outlined", placeholder: "Search tags..." }))); }, sx: { width: "100%" } })),
13749
+ React__default.createElement(Grid2, { size: 12 },
13750
+ React__default.createElement(Box, { sx: {
13751
+ display: "flex",
13752
+ justifyContent: "space-between",
13753
+ alignItems: "center",
13754
+ mt: 1,
13755
+ } },
13756
+ React__default.createElement(Typography$1, { variant: "subtitle2" }, "Select Bit Positions (0-31, LSB = 0)"),
13757
+ selectedTag && (React__default.createElement(Box, { sx: { display: "flex", gap: 1 } },
13758
+ React__default.createElement(Button, { size: "small", variant: "outlined", onClick: handleSelectAll, disabled: availableCount === 0 }, "Select All"),
13759
+ React__default.createElement(Button, { size: "small", variant: "outlined", onClick: handleClearAll, disabled: selectedCount === 0 }, "Clear"))))),
13760
+ React__default.createElement(Grid2, { size: 12 },
13761
+ React__default.createElement(Box, { sx: {
13762
+ border: "1px solid",
13763
+ borderColor: "divider",
13764
+ borderRadius: 1,
13765
+ p: 2,
13766
+ minHeight: "200px",
13767
+ backgroundColor: "background.paper",
13768
+ } }, renderBitGrid())),
13769
+ selectedTag && (React__default.createElement(Grid2, { size: 12 },
13770
+ React__default.createElement(Typography$1, { variant: "body2", sx: { color: "text.secondary" } },
13771
+ selectedCount,
13772
+ " bit",
13773
+ selectedCount !== 1 ? "s" : "",
13774
+ " selected",
13775
+ availableCount < 32 &&
13776
+ " (".concat(32 - availableCount, " already extracted)")))))),
13777
+ React__default.createElement(MesfModal.Actions, null,
13778
+ React__default.createElement(Box, { sx: { display: "flex", gap: 1, pt: 1 } },
13779
+ React__default.createElement(Button, { variant: "outlined", color: "secondary", onClick: handleCancel }, "Cancel"),
13780
+ React__default.createElement(ButtonWithLoading, { onClick: handleAdd, variant: "contained", color: "primary", isLoading: isLoading, disabled: !selectedTag || selectedCount === 0 },
13781
+ "Add ",
13782
+ selectedCount > 0 ? "(".concat(selectedCount, ")") : "")))));
13783
+ };
13784
+
13157
13785
  var LoadViewModalV2 = function (_a) {
13158
13786
  var open = _a.open, handleClose = _a.handleClose;
13159
13787
  var queryClient = useQueryClient();
@@ -13316,11 +13944,12 @@ var TagsTableV2 = function () {
13316
13944
  var _f = useState(false); _f[0]; var setIsLoading = _f[1];
13317
13945
  var _g = useState(null); _g[0]; var setSelectedRowTagId = _g[1];
13318
13946
  var _h = useState(false), tagsTreeModalOpen = _h[0], setTagsTreeModalOpen = _h[1];
13319
- var _j = useState(false), saveAsViewModalOpen = _j[0], setSaveAsViewModalOpen = _j[1];
13320
- var _k = useState(false), loadViewOpen = _k[0], setLoadViewOpen = _k[1];
13321
- var _l = useState(""), snackbarMessage = _l[0], setSnackbarMessage = _l[1];
13322
- var _m = useState(null), draggedRowId = _m[0], setDraggedRowId = _m[1];
13323
- var _o = useState(null), dragOverRowId = _o[0], setDragOverRowId = _o[1];
13947
+ var _j = useState(false), bitSelectorModalOpen = _j[0], setBitSelectorModalOpen = _j[1];
13948
+ var _k = useState(false), saveAsViewModalOpen = _k[0], setSaveAsViewModalOpen = _k[1];
13949
+ var _l = useState(false), loadViewOpen = _l[0], setLoadViewOpen = _l[1];
13950
+ var _m = useState(""), snackbarMessage = _m[0], setSnackbarMessage = _m[1];
13951
+ var _o = useState(null), draggedRowId = _o[0], setDraggedRowId = _o[1];
13952
+ var _p = useState(null), dragOverRowId = _p[0], setDragOverRowId = _p[1];
13324
13953
  // Mutations
13325
13954
  var deleteAllViewTags = useMutation({
13326
13955
  mutationFn: function (viewId) { return deleteAllViewTagsFromView(viewId); },
@@ -13452,6 +14081,63 @@ var TagsTableV2 = function () {
13452
14081
  // Add the new tag
13453
14082
  handleAddTag(selectedTag);
13454
14083
  };
14084
+ // Generate synthetic ID for bit-extracted tags
14085
+ var generateBitTagId = function (sourceTagId, bitIndex) {
14086
+ return sourceTagId * 100 + bitIndex;
14087
+ };
14088
+ // Get set of existing bit tags as "sourceTagId-bitIndex" strings
14089
+ var existingBitTags = useMemo(function () {
14090
+ var bitTags = new Set();
14091
+ Object.values(viewTags).forEach(function (_a) {
14092
+ var viewTag = _a.viewTag;
14093
+ if (viewTag.IsBitExtracted &&
14094
+ viewTag.SourceTagId !== undefined &&
14095
+ viewTag.BitIndex !== undefined) {
14096
+ bitTags.add("".concat(viewTag.SourceTagId, "-").concat(viewTag.BitIndex));
14097
+ }
14098
+ });
14099
+ return bitTags;
14100
+ }, [viewTags]);
14101
+ // Handle adding bits from a bit array tag
14102
+ var handleAddBits = useCallback(function (sourceTagId, bitIndices) {
14103
+ var sourceTagEntry = viewTags[sourceTagId];
14104
+ if (!sourceTagEntry) {
14105
+ setError("Source tag not found");
14106
+ return;
14107
+ }
14108
+ var sourceTag = sourceTagEntry.viewTag;
14109
+ var newTags = __assign({}, viewTags);
14110
+ var maxOrder = Math.max.apply(Math, __spreadArray(__spreadArray([], Object.values(viewTags).map(function (v) { return v.order; }), false), [0], false));
14111
+ bitIndices.forEach(function (bitIndex) {
14112
+ // Generate unique ID for this bit extraction
14113
+ var syntheticId = generateBitTagId(sourceTagId, bitIndex);
14114
+ // Skip if already exists
14115
+ if (newTags[syntheticId])
14116
+ return;
14117
+ maxOrder++;
14118
+ newTags[syntheticId] = {
14119
+ viewTag: {
14120
+ TagId: syntheticId,
14121
+ TagName: "".concat(sourceTag.TagName, "[").concat(bitIndex, "]"),
14122
+ Alias: "".concat(sourceTag.Alias || sourceTag.TagName, "[").concat(bitIndex, "]"),
14123
+ TagType: "D", // Bit-extracted tags are always digital
14124
+ Color: getRandomColor(),
14125
+ MinScale: 0,
14126
+ MaxScale: 1,
14127
+ IsAutoScale: true,
14128
+ IsVisible: true,
14129
+ Unit: "",
14130
+ SourceTagId: sourceTagId,
14131
+ BitIndex: bitIndex,
14132
+ IsBitExtracted: true,
14133
+ },
14134
+ order: maxOrder,
14135
+ };
14136
+ });
14137
+ // Use setViewTags since bit-extracted tags don't need new API calls
14138
+ // They derive data from existing source tags
14139
+ setViewTags(newTags);
14140
+ }, [viewTags, setViewTags]);
13455
14141
  var handleRowReorder = useCallback(function (draggedId, targetId) {
13456
14142
  if (draggedId === targetId)
13457
14143
  return;
@@ -13581,6 +14267,13 @@ var TagsTableV2 = function () {
13581
14267
  setTagsTreeModalOpen(true);
13582
14268
  },
13583
14269
  },
14270
+ {
14271
+ key: "addBitFromArray",
14272
+ name: "Add Bit from Bit Array",
14273
+ onClick: function () {
14274
+ setBitSelectorModalOpen(true);
14275
+ },
14276
+ },
13584
14277
  {
13585
14278
  key: "saveView",
13586
14279
  name: "Save View",
@@ -13692,6 +14385,10 @@ var TagsTableV2 = function () {
13692
14385
  max: overallMinMax.max,
13693
14386
  overallMin: overallMinMax.min,
13694
14387
  overallMax: overallMinMax.max,
14388
+ // Bit extraction metadata
14389
+ isBitExtracted: viewTag.IsBitExtracted,
14390
+ sourceTagId: viewTag.SourceTagId,
14391
+ bitIndex: viewTag.BitIndex,
13695
14392
  };
13696
14393
  });
13697
14394
  }, [viewTags, cursorValues, seriesMinMax]);
@@ -13714,8 +14411,17 @@ var TagsTableV2 = function () {
13714
14411
  // Custom cell renderer for type (with colored badge)
13715
14412
  var renderTypeCell = useCallback(function (params) {
13716
14413
  var type = params.value;
13717
- return (React__default.createElement(Chip, { label: type, size: "small", style: {
13718
- backgroundColor: type === "A" ? "#AD48C4" : "#C46F48",
14414
+ var isBitExtracted = params.row.isBitExtracted;
14415
+ // Show "B" for bit-extracted tags, otherwise show the tag type
14416
+ var displayLabel = isBitExtracted ? "B" : type;
14417
+ // Use green for bit-extracted, purple for analog, orange for digital
14418
+ var backgroundColor = isBitExtracted
14419
+ ? "#48C4A0"
14420
+ : type === "A"
14421
+ ? "#AD48C4"
14422
+ : "#C46F48";
14423
+ return (React__default.createElement(Chip, { label: displayLabel, size: "small", style: {
14424
+ backgroundColor: backgroundColor,
13719
14425
  color: "white",
13720
14426
  fontWeight: "bold",
13721
14427
  fontSize: "0.7rem",
@@ -14112,6 +14818,7 @@ var TagsTableV2 = function () {
14112
14818
  },
14113
14819
  } }),
14114
14820
  React__default.createElement(TagsTreeModalV2, { open: tagsTreeModalOpen, handleClose: function () { return setTagsTreeModalOpen(false); }, onTagSelect: handleTagSelect }),
14821
+ React__default.createElement(BitSelectorModal, { open: bitSelectorModalOpen, handleClose: function () { return setBitSelectorModalOpen(false); }, viewTags: viewTags, onAddBits: handleAddBits, existingBitTags: existingBitTags }),
14115
14822
  React__default.createElement(SaveUpdateDeleteViewModalV2, { open: saveAsViewModalOpen, mode: "create", handleClose: function (shouldUpdate) {
14116
14823
  setSaveAsViewModalOpen(false);
14117
14824
  if (shouldUpdate) {
@@ -14573,6 +15280,9 @@ var TrendingChartV2 = function (_a) {
14573
15280
  if (tag.IsAutoScale) {
14574
15281
  // Use automatic scaling based on data
14575
15282
  baseConfig.scale = true;
15283
+ // Explicitly clear min/max to ensure auto-scaling works when switching from fixed scale
15284
+ baseConfig.min = null;
15285
+ baseConfig.max = null;
14576
15286
  }
14577
15287
  else {
14578
15288
  // Use explicit min/max values
@@ -15274,10 +15984,11 @@ var TrendingChartV2 = function (_a) {
15274
15984
  }
15275
15985
  }, [onChartReady, dataLoadedTrigger, chartOptions]);
15276
15986
  // Track chart area coordinates for cursor positioning
15987
+ var containerRef = useRef(null);
15277
15988
  useEffect(function () {
15278
15989
  var _a;
15279
15990
  var instance = (_a = chartRef.current) === null || _a === void 0 ? void 0 : _a.getEchartsInstance();
15280
- if (!instance)
15991
+ if (!instance || !containerRef.current)
15281
15992
  return;
15282
15993
  var updateChartArea = function () {
15283
15994
  try {
@@ -15320,14 +16031,18 @@ var TrendingChartV2 = function (_a) {
15320
16031
  // Silently handle chart area update failure
15321
16032
  }
15322
16033
  };
16034
+ // Create ResizeObserver to handle container resizing (panel resize)
16035
+ var resizeObserver = new ResizeObserver(function () {
16036
+ instance.resize();
16037
+ // Small delay to ensure ECharts has updated its internal state
16038
+ requestAnimationFrame(updateChartArea);
16039
+ });
16040
+ resizeObserver.observe(containerRef.current);
15323
16041
  // Update immediately
15324
16042
  updateChartArea();
15325
- // Update on window resize
15326
- var handleResize = function () {
15327
- setTimeout(updateChartArea, 100);
16043
+ return function () {
16044
+ resizeObserver.disconnect();
15328
16045
  };
15329
- window.addEventListener("resize", handleResize);
15330
- return function () { return window.removeEventListener("resize", handleResize); };
15331
16046
  }, [chartInstance, useSeparateGrids]);
15332
16047
  // Keyboard control for cursor navigation
15333
16048
  useEffect(function () {
@@ -15389,7 +16104,7 @@ var TrendingChartV2 = function (_a) {
15389
16104
  zIndex: 10,
15390
16105
  } },
15391
16106
  React__default.createElement(CircularProgress, { size: "2rem" }))),
15392
- React__default.createElement("div", { style: { height: "100%", width: "100%", position: "relative" } },
16107
+ React__default.createElement("div", { ref: containerRef, style: { height: "100%", width: "100%", position: "relative" } },
15393
16108
  React__default.createElement(ReactECharts, { key: chartKey, ref: chartRef, option: chartOptions, style: {
15394
16109
  height: "100%",
15395
16110
  width: "100%",
@@ -15481,27 +16196,37 @@ var TrendingsPageV2 = function () {
15481
16196
  .sort(function (a, b) { return b.order - a.order; }) // DESCENDING order - MUST match TrendingChartV2 sort!
15482
16197
  .map(function (tag) { return tag.viewTag.TagId; });
15483
16198
  }, [viewTags]);
16199
+ // Real tag IDs (excluding bit-extracted synthetic IDs) for API queries
16200
+ // Bit-extracted tags derive their data client-side from source tags
16201
+ var realTagIds = useMemo(function () {
16202
+ return Object.values(viewTags)
16203
+ .filter(function (tag) { return tag && tag.viewTag && !tag.viewTag.IsBitExtracted; })
16204
+ .sort(function (a, b) { return b.order - a.order; })
16205
+ .map(function (tag) { return tag.viewTag.TagId; });
16206
+ }, [viewTags]);
15484
16207
  // Stable query key that only changes on time scope or when explicitly refetching (add/zoom/pan)
15485
16208
  // This prevents refetch when removing tags from viewTags
16209
+ // IMPORTANT: Uses realTagIds (excludes bit-extracted tags) for API queries
15486
16210
  var stableTagIdsRef = useRef([]);
15487
16211
  var prevTimeScopeRef = useRef("");
15488
16212
  var queryTagIds = useMemo(function () {
15489
16213
  var currentTimeScope = "".concat(timeScopeStart.getTime(), "-").concat(timeScopeEnd.getTime());
15490
16214
  var timeScopeChanged = currentTimeScope !== prevTimeScopeRef.current;
15491
- // Check if any new tags were added (not present in stable ref)
15492
- var hasNewTags = tagIds.some(function (id) { return !stableTagIdsRef.current.includes(id); });
16215
+ // Check if any new REAL tags were added (not present in stable ref)
16216
+ // Bit-extracted tags don't trigger API refetch since they derive data client-side
16217
+ var hasNewTags = realTagIds.some(function (id) { return !stableTagIdsRef.current.includes(id); });
15493
16218
  // Update query tagIds if:
15494
16219
  // 1. It's empty (first load)
15495
- // 2. New tags were added (not just length change)
15496
- // 3. Time scope changed (zoom/pan) - use current tagIds to avoid fetching removed tags
16220
+ // 2. New REAL tags were added (not just length change)
16221
+ // 3. Time scope changed (zoom/pan) - use current realTagIds to avoid fetching removed tags
15497
16222
  if (stableTagIdsRef.current.length === 0 ||
15498
16223
  hasNewTags ||
15499
16224
  timeScopeChanged) {
15500
- stableTagIdsRef.current = tagIds;
16225
+ stableTagIdsRef.current = realTagIds;
15501
16226
  prevTimeScopeRef.current = currentTimeScope;
15502
16227
  }
15503
16228
  return stableTagIdsRef.current;
15504
- }, [tagIds, timeScopeStart, timeScopeEnd]);
16229
+ }, [realTagIds, timeScopeStart, timeScopeEnd]);
15505
16230
  // Fetch series data using stable query key
15506
16231
  var _m = useSearchSeries$1({
15507
16232
  start: timeScopeStart.getTime(),
@@ -15510,6 +16235,7 @@ var TrendingsPageV2 = function () {
15510
16235
  autoRefresh: autoRefresh,
15511
16236
  }), series = _m.data, seriesLoading = _m.isLoading, seriesIsError = _m.isError, seriesError = _m.error;
15512
16237
  // Filter and reorder series to match current viewTags order
16238
+ // Also handles bit-extracted tags by deriving their data from source tags
15513
16239
  var filteredSeries = useMemo(function () {
15514
16240
  if (!series)
15515
16241
  return [];
@@ -15525,12 +16251,39 @@ var TrendingsPageV2 = function () {
15525
16251
  seriesMap.set(tagId, series[index]);
15526
16252
  }
15527
16253
  });
16254
+ // Build viewTags array sorted by order (descending) to match tagIds order
16255
+ var viewTagsArray = Object.values(viewTags)
16256
+ .filter(function (tag) { return tag && tag.viewTag; })
16257
+ .sort(function (a, b) { return b.order - a.order; });
15528
16258
  // Return series in the SAME order as tagIds (which matches viewTags sort order)
15529
- // This ensures series[i] always corresponds to viewTagsArray[i] in the chart
16259
+ // For bit-extracted tags, derive data from source tag by extracting the specific bit
15530
16260
  return tagIds
15531
- .map(function (tagId) { return seriesMap.get(tagId); })
16261
+ .map(function (tagId, idx) {
16262
+ var viewTagEntry = viewTagsArray[idx];
16263
+ if (!viewTagEntry)
16264
+ return null;
16265
+ var viewTag = viewTagEntry.viewTag;
16266
+ // If this is a bit-extracted tag, derive data from source
16267
+ if (viewTag.IsBitExtracted &&
16268
+ viewTag.SourceTagId !== undefined &&
16269
+ viewTag.BitIndex !== undefined) {
16270
+ var sourceData = seriesMap.get(viewTag.SourceTagId);
16271
+ if (!sourceData)
16272
+ return null;
16273
+ // Extract bit from each data point
16274
+ // BitIndex 0 = LSB (least significant bit)
16275
+ return sourceData.map(function (point) { return ({
16276
+ timestamp: point.timestamp,
16277
+ value: point.value !== null
16278
+ ? (Math.floor(point.value) >> viewTag.BitIndex) & 1
16279
+ : null,
16280
+ }); });
16281
+ }
16282
+ // Regular tag - use series data directly
16283
+ return seriesMap.get(tagId);
16284
+ })
15532
16285
  .filter(Boolean);
15533
- }, [series, tagIds, queryTagIds]);
16286
+ }, [series, tagIds, queryTagIds, viewTags]);
15534
16287
  // Calculate overall min/max values from filtered series data
15535
16288
  var seriesMinMaxData = useSeriesMinMax(filteredSeries, tagIds);
15536
16289
  // Load initial view when views are fetched
@@ -15640,12 +16393,14 @@ var TrendingsPageV2 = function () {
15640
16393
  var isLoading = viewsLoading || viewTagsLoading;
15641
16394
  return (React__default.createElement(React__default.Fragment, null,
15642
16395
  React__default.createElement(HelmetDexteel, { title: "Trendings" }),
15643
- React__default.createElement(Grid2, { container: true, direction: "column", wrap: "nowrap", size: 12, sx: {
15644
- p: 2,
16396
+ React__default.createElement("div", { style: {
16397
+ padding: "16px",
15645
16398
  width: "100%",
15646
16399
  height: "92vh",
15647
16400
  position: "relative",
15648
16401
  backgroundColor: "#FAFAFA",
16402
+ display: "flex",
16403
+ flexDirection: "column",
15649
16404
  } },
15650
16405
  isLoading && (React__default.createElement("div", { style: {
15651
16406
  position: "absolute",
@@ -15660,14 +16415,38 @@ var TrendingsPageV2 = function () {
15660
16415
  zIndex: 1000,
15661
16416
  } },
15662
16417
  React__default.createElement(CircularProgress, { size: "3rem" }))),
15663
- React__default.createElement(Grid2, { size: 12, style: { flexShrink: 0 } },
16418
+ React__default.createElement("div", { style: { flexShrink: 0 } },
15664
16419
  React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, chartInstance: chartInstance })),
15665
- React__default.createElement(Grid2, { size: 12 },
15666
- React__default.createElement(Divider, { sx: { my: 2 } })),
15667
- React__default.createElement(Grid2, { size: 12, sx: { flexGrow: 1, minHeight: 0, overflow: "hidden", height: "100%" } },
15668
- React__default.createElement(TrendingChartV2, { customOptions: chartOptions, series: filteredSeries, isLoading: seriesLoading, onChartReady: setChartInstance, dataLoadedTrigger: dataLoadedTrigger })),
15669
- React__default.createElement(Grid2, { style: { flexShrink: 0, height: "160px", marginTop: "3px" } },
15670
- React__default.createElement(TagsTableV2, null))),
16420
+ React__default.createElement(Divider, { sx: { my: 2 } }),
16421
+ React__default.createElement("div", { style: {
16422
+ flexGrow: 1,
16423
+ minHeight: 0,
16424
+ display: "flex",
16425
+ width: "100%",
16426
+ } },
16427
+ React__default.createElement(Group$1, { orientation: "vertical", style: { width: "100%", height: "100%" } },
16428
+ React__default.createElement(Panel, { defaultSize: 80, minSize: 20 },
16429
+ React__default.createElement("div", { style: { height: "100%", width: "100%" } },
16430
+ React__default.createElement(TrendingChartV2, { customOptions: chartOptions, series: filteredSeries, isLoading: seriesLoading, onChartReady: setChartInstance, dataLoadedTrigger: dataLoadedTrigger }))),
16431
+ React__default.createElement(Separator, { style: {
16432
+ height: "10px",
16433
+ background: "#f0f0f0",
16434
+ cursor: "row-resize",
16435
+ display: "flex",
16436
+ alignItems: "center",
16437
+ justifyContent: "center",
16438
+ borderTop: "1px solid #e0e0e0",
16439
+ borderBottom: "1px solid #e0e0e0",
16440
+ } },
16441
+ React__default.createElement("div", { style: {
16442
+ width: "40px",
16443
+ height: "4px",
16444
+ backgroundColor: "#ccc",
16445
+ borderRadius: "2px",
16446
+ } })),
16447
+ React__default.createElement(Panel, { defaultSize: 20, minSize: 10 },
16448
+ React__default.createElement("div", { style: { height: "100%", width: "100%", overflow: "auto" } },
16449
+ React__default.createElement(TagsTableV2, null)))))),
15671
16450
  React__default.createElement(ErrorModal, { error: error, onHide: function () { return setError(""); }, size: "xl", title: "ERROR" })));
15672
16451
  };
15673
16452
 
@@ -21206,5 +21985,5 @@ var areaSelector = /*#__PURE__*/Object.freeze({
21206
21985
  AreaSelector: AreaSelector
21207
21986
  });
21208
21987
 
21209
- export { Account, AssetProvider, AssetTreePicker, AuthContext, AuthProvider, ButtonWithLoading, ChangePassword, CheckBoxControl, Configuration$1 as Configuration, ContextMenu$1 as ContextMenu, ContextMenuMESFProvider, CreateNewAssetDialog, CurrencyFormatter, DataGridControl, DateFormatter, DateTimeFormatter, ENTRY_INITIAL_VALUES, EditAssetDialog, ErrorModal, ExcelIcon, FetchError, FilterPanel, GenericPanel, GenericTable, GetCrewColor, GetShiftColor, HelmetDexteel, IntegerFormatter, LogbookSettingsInitialState, LogbookSettingsProvider, Login, Logout, LongFilterPanel, MESApiService, MESFLogbookEntry, MESFLogbookReport, MESFMain, MESSAGE_API, MESSAGE_ERRORS, MasterDetailPanel, MesfModal, ModalTreeFilterControl, MultipleSelectorControl, NumberFormatter, RemoveAssetDialog, ShiftDayNavigatorControl, ShiftNavigatorProvider, ShiftPeriodNavigatorControl, SimplePasswordControl, SimpleSelectorControl, TimeAndUserMenu, TimeFormatter, TimeService, TreePickerControl, TreePickerControlV2, TrendingsPage, USER_LABELS, UTLSettingsProvider, UserProvider, axiosInstance, deleteUser, dxtServerTimeZone, dxtToLocalServerTime, dxtToUTC, formatNumber, getAuthTypes, getCrewStyle, getDataUser, getEntries, getError, getMomentTz, getShiftByParameters, getShiftStyle, getShiftsRangeByParameters, getTokenFromLS, getUserPermissionsFromAPI, getUsers, logbookNavbar, logbookRoutesMESF, renewToken, routeLogbookEntry, routeLogbookReport, useSearchAssets as searchAssets, useSearchSeries as searchSeries, useSearchTagsTree as searchTagsTree, useSearchViewTags as searchViewTags, useSearchViews as searchViews, setPassword, setProfilesToUser, themeDXT, themeMESF, upsertUser, useAssetContext, useContextMenuMESF, useHasPermission, useHasProfile, useLogbookSettings, useMesfRealtime, useShiftNavigator, useShiftNavigatorManager, useToken, useUTLSettingsContext, useUserContext };
21988
+ export { Account, AssetProvider, AssetTreePicker, AuthContext, AuthProvider, ButtonWithLoading, ChangePassword, CheckBoxControl, Configuration$1 as Configuration, ContextMenu$1 as ContextMenu, ContextMenuMESFProvider, CreateNewAssetDialog, CurrencyFormatter, DataGridControl, DateFormatter, DateTimeFormatter, ENTRY_INITIAL_VALUES, EditAssetDialog, ErrorModal, ExcelIcon, FetchError, FilterPanel, GenericPanel, GenericTable, GetCrewColor, GetShiftColor, HelmetDexteel, IntegerFormatter, LogbookSettingsInitialState, LogbookSettingsProvider, Login, Logout, LongFilterPanel, MESApiService, MESFLogbookEntry, MESFLogbookReport, MESFMain, MESSAGE_API, MESSAGE_ERRORS, MasterDetailPanel, MesfModal, ModalTreeFilterControl, MultipleSelectorControl, NumberFormatter, RemoveAssetDialog, SPExecutorPage, ShiftDayNavigatorControl, ShiftNavigatorProvider, ShiftPeriodNavigatorControl, SimplePasswordControl, SimpleSelectorControl, TimeAndUserMenu, TimeFormatter, TimeService, TreePickerControl, TreePickerControlV2, TrendingsPage, USER_LABELS, UTLSettingsProvider, UserProvider, axiosInstance, deleteUser, dxtServerTimeZone, dxtToLocalServerTime, dxtToUTC, formatNumber, getAuthTypes, getCrewStyle, getDataUser, getEntries, getError, getMomentTz, getShiftByParameters, getShiftStyle, getShiftsRangeByParameters, getTokenFromLS, getUserPermissionsFromAPI, getUsers, logbookNavbar, logbookRoutesMESF, renewToken, routeLogbookEntry, routeLogbookReport, useSearchAssets as searchAssets, useSearchSeries as searchSeries, useSearchTagsTree as searchTagsTree, useSearchViewTags as searchViewTags, useSearchViews as searchViews, setPassword, setProfilesToUser, themeDXT, themeMESF, upsertUser, useAssetContext, useContextMenuMESF, useHasPermission, useHasProfile, useLogbookSettings, useMesfRealtime, useShiftNavigator, useShiftNavigatorManager, useToken, useUTLSettingsContext, useUserContext };
21210
21989
  //# sourceMappingURL=index.esm.js.map