@dexteel/mesf-core 7.6.0 → 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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "7.6.0"
2
+ ".": "7.7.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.7.0](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.6.0...@dexteel/mesf-core-v7.7.0) (2025-12-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * **Trendings V2:** add resizable-panels to Trendings V2 ([9c7dd08](https://github.com/dexteel/mesf-core-frontend/commit/9c7dd0846792dc3a8f18f7c70f4cc7e3db98650a))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **CreateProfile:** add validation to ProfileName field to prevent whitespace input ([#573](https://github.com/dexteel/mesf-core-frontend/issues/573)) ([0c31f95](https://github.com/dexteel/mesf-core-frontend/commit/0c31f95a87286bc8a7dd9247ad37e05051227b8e))
14
+ * **Trendings V2:** fix autoscale functionality ([3ce4265](https://github.com/dexteel/mesf-core-frontend/commit/3ce42652c305afa5391abd5cbe835c17f248b2bf))
15
+
3
16
  ## [7.6.0](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.5.2...@dexteel/mesf-core-v7.6.0) (2025-12-17)
4
17
 
5
18
 
package/GEMINI.md ADDED
@@ -0,0 +1,92 @@
1
+ # @dexteel/mesf-core
2
+
3
+ ## Project Overview
4
+
5
+ `@dexteel/mesf-core` is a React component library built with TypeScript and bundled using Rollup. It provides a comprehensive set of components, contexts, and utilities designed for building Manufacturing Execution Systems (MES). It acts as a core foundation for MESF-based applications, handling common concerns like authentication, navigation, settings, and layout.
6
+
7
+ **Key Technologies:**
8
+ * **Core:** React 18, TypeScript
9
+ * **Build Tool:** Rollup
10
+ * **UI Framework:** Material-UI (MUI) v6
11
+ * **Data Grid:** AG Grid
12
+ * **Data Visualization:** Chart.js, ECharts
13
+ * **State Management:** React Context, Redux Toolkit, React Query
14
+ * **Authentication:** Azure MSAL
15
+ * **Real-time:** SignalR
16
+
17
+ ## Building and Running
18
+
19
+ This project is a library, so "running" it typically means building it for consumption or watching for changes while linked to a consuming application.
20
+
21
+ * **Build for Production:**
22
+ ```bash
23
+ npm run build
24
+ ```
25
+ This cleans the `dist` folder and runs Rollup to produce the production bundle.
26
+
27
+ * **Watch Mode (Development):**
28
+ ```bash
29
+ npm run watch
30
+ # OR
31
+ npm start
32
+ ```
33
+ This runs Rollup in watch mode, rebuilding on file changes.
34
+
35
+ * **CI Build:**
36
+ ```bash
37
+ npm run ci
38
+ ```
39
+ Performs a clean build suitable for CI environments.
40
+
41
+ * **Type Check:**
42
+ ```bash
43
+ npm run type-check
44
+ ```
45
+
46
+ ## Development Conventions
47
+
48
+ * **Code Formatting:** The project uses [Biome](https://biomejs.dev/) for formatting and organizing imports.
49
+ * Run check and fix: `npx @biomejs/biome check --write ./src`
50
+ * **Note:** A pre-commit hook is configured to automatically run Biome on staged files.
51
+ * **Linting:** Linting rules are currently disabled in `biome.json`.
52
+
53
+ * **Project Structure:**
54
+ * `src/index.ts`: The main entry point that exports all public APIs (components, hooks, utilities).
55
+ * `src/MESFMain.tsx`: The main "shell" component that wraps the application with necessary providers (Auth, Theme, Router, etc.).
56
+
57
+ ## Architecture
58
+
59
+ The library follows a modular architecture designed to be consumed as a single package.
60
+
61
+ ### Key Components & Modules
62
+
63
+ * **`MESFMain`**: The top-level component that consumes applications should use. It accepts `routes`, `navbar`, and `authentication` configuration, setting up the entire application shell.
64
+ * **Contexts**: Extensive use of React Context for global state:
65
+ * `userContext`: Authentication and user profile.
66
+ * `UTLSettingContext`: User settings and preferences.
67
+ * `assetContext`: Management of plant assets.
68
+ * `LogbookSettingsContext`: Configuration for logbook features.
69
+ * **Services**: `src/services` contains singletons for API communication (`ApiService`) and time handling (`TimeService`).
70
+ * **Configuration**: `src/configuration` contains admin modules and pages for managing system settings.
71
+
72
+ ### Directory Map
73
+
74
+ * `src/account/`: Authentication logic (Azure AD, Login strategies).
75
+ * `src/components/`: Reusable UI components (Modals, Navigation, Shared buttons/icons).
76
+ * `src/configuration/`: Admin pages and configuration logic.
77
+ * `src/context/`: React Context providers.
78
+ * `src/controls/`: Complex form controls (Asset pickers, Tree pickers, Date filters).
79
+ * `src/hooks/`: Custom hooks (e.g., `useMesfRealtime`).
80
+ * `src/pages/`: Domain-specific pages provided by the core (Logbook, Trending, SP Executor).
81
+ * `src/utils/`: Helper functions.
82
+
83
+ ## Dependencies
84
+
85
+ This library relies heavily on **peer dependencies**. Consuming applications are expected to provide:
86
+ * React & React DOM
87
+ * Material-UI (MUI) components & styling
88
+ * AG Grid
89
+ * React Router DOM
90
+ * Date management libraries (Moment, Date-fns)
91
+
92
+ Check `package.json` for the full list of peer dependencies and their required versions.
package/dist/index.esm.js CHANGED
@@ -59,6 +59,7 @@ import { DateTimePicker as DateTimePicker$1 } from '@mui/x-date-pickers/DateTime
59
59
  import ClearAllIcon from '@mui/icons-material/ClearAll';
60
60
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
61
61
  import axios from 'axios';
62
+ import { Group as Group$1, Panel, Separator } from 'react-resizable-panels';
62
63
  import { LocalizationProvider as LocalizationProvider$1 } from '@mui/x-date-pickers/LocalizationProvider';
63
64
  import InsertChartIcon from '@mui/icons-material/InsertChart';
64
65
  import ReactECharts from 'echarts-for-react';
@@ -3859,13 +3860,13 @@ var INITIAL_VALUES$2 = {
3859
3860
  };
3860
3861
 
3861
3862
  var CreateProfile = function (_a) {
3862
- var _b;
3863
+ var _b, _c;
3863
3864
  var show = _a.show, onHide = _a.onHide, suffixTitle = _a.suffixTitle;
3864
- var _c = useState(false), openSnackbar = _c[0], setOpenSnackbar = _c[1];
3865
- var _d = useState(""), message = _d[0], setMessage = _d[1];
3866
- var _e = useState(false), isSubmitLoading = _e[0], setIsSubmitLoading = _e[1];
3867
- var _f = useState(""), error = _f[0], setError = _f[1];
3868
- 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;
3869
3870
  var createProfile = useMutation({
3870
3871
  mutationFn: upsertProfile,
3871
3872
  onSuccess: function () {
@@ -3915,9 +3916,18 @@ var CreateProfile = function (_a) {
3915
3916
  React.createElement(MesfModal.Content, { style: { padding: "15px 30px" } },
3916
3917
  React.createElement(Grid2, { container: true, spacing: 1 },
3917
3918
  React.createElement(Grid2, { size: { md: 12, xs: 12 } },
3918
- 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" })),
3919
3928
  " ",
3920
- ((_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))))),
3921
3931
  React.createElement(MesfModal.Actions, { style: { padding: "20px 30px 30px" } },
3922
3932
  React.createElement(Grid2, { container: true, spacing: 2, justifyContent: "flex-end" },
3923
3933
  React.createElement(Grid2, { size: { md: 3, xs: 12 }, style: { margin: 0 } },
@@ -15270,6 +15280,9 @@ var TrendingChartV2 = function (_a) {
15270
15280
  if (tag.IsAutoScale) {
15271
15281
  // Use automatic scaling based on data
15272
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;
15273
15286
  }
15274
15287
  else {
15275
15288
  // Use explicit min/max values
@@ -15971,10 +15984,11 @@ var TrendingChartV2 = function (_a) {
15971
15984
  }
15972
15985
  }, [onChartReady, dataLoadedTrigger, chartOptions]);
15973
15986
  // Track chart area coordinates for cursor positioning
15987
+ var containerRef = useRef(null);
15974
15988
  useEffect(function () {
15975
15989
  var _a;
15976
15990
  var instance = (_a = chartRef.current) === null || _a === void 0 ? void 0 : _a.getEchartsInstance();
15977
- if (!instance)
15991
+ if (!instance || !containerRef.current)
15978
15992
  return;
15979
15993
  var updateChartArea = function () {
15980
15994
  try {
@@ -16017,14 +16031,18 @@ var TrendingChartV2 = function (_a) {
16017
16031
  // Silently handle chart area update failure
16018
16032
  }
16019
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);
16020
16041
  // Update immediately
16021
16042
  updateChartArea();
16022
- // Update on window resize
16023
- var handleResize = function () {
16024
- setTimeout(updateChartArea, 100);
16043
+ return function () {
16044
+ resizeObserver.disconnect();
16025
16045
  };
16026
- window.addEventListener("resize", handleResize);
16027
- return function () { return window.removeEventListener("resize", handleResize); };
16028
16046
  }, [chartInstance, useSeparateGrids]);
16029
16047
  // Keyboard control for cursor navigation
16030
16048
  useEffect(function () {
@@ -16086,7 +16104,7 @@ var TrendingChartV2 = function (_a) {
16086
16104
  zIndex: 10,
16087
16105
  } },
16088
16106
  React__default.createElement(CircularProgress, { size: "2rem" }))),
16089
- 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" } },
16090
16108
  React__default.createElement(ReactECharts, { key: chartKey, ref: chartRef, option: chartOptions, style: {
16091
16109
  height: "100%",
16092
16110
  width: "100%",
@@ -16375,12 +16393,14 @@ var TrendingsPageV2 = function () {
16375
16393
  var isLoading = viewsLoading || viewTagsLoading;
16376
16394
  return (React__default.createElement(React__default.Fragment, null,
16377
16395
  React__default.createElement(HelmetDexteel, { title: "Trendings" }),
16378
- React__default.createElement(Grid2, { container: true, direction: "column", wrap: "nowrap", size: 12, sx: {
16379
- p: 2,
16396
+ React__default.createElement("div", { style: {
16397
+ padding: "16px",
16380
16398
  width: "100%",
16381
16399
  height: "92vh",
16382
16400
  position: "relative",
16383
16401
  backgroundColor: "#FAFAFA",
16402
+ display: "flex",
16403
+ flexDirection: "column",
16384
16404
  } },
16385
16405
  isLoading && (React__default.createElement("div", { style: {
16386
16406
  position: "absolute",
@@ -16395,14 +16415,38 @@ var TrendingsPageV2 = function () {
16395
16415
  zIndex: 1000,
16396
16416
  } },
16397
16417
  React__default.createElement(CircularProgress, { size: "3rem" }))),
16398
- React__default.createElement(Grid2, { size: 12, style: { flexShrink: 0 } },
16418
+ React__default.createElement("div", { style: { flexShrink: 0 } },
16399
16419
  React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, chartInstance: chartInstance })),
16400
- React__default.createElement(Grid2, { size: 12 },
16401
- React__default.createElement(Divider, { sx: { my: 2 } })),
16402
- React__default.createElement(Grid2, { size: 12, sx: { flexGrow: 1, minHeight: 0, overflow: "hidden", height: "100%" } },
16403
- React__default.createElement(TrendingChartV2, { customOptions: chartOptions, series: filteredSeries, isLoading: seriesLoading, onChartReady: setChartInstance, dataLoadedTrigger: dataLoadedTrigger })),
16404
- React__default.createElement(Grid2, { style: { flexShrink: 0, height: "160px", marginTop: "3px" } },
16405
- 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)))))),
16406
16450
  React__default.createElement(ErrorModal, { error: error, onHide: function () { return setError(""); }, size: "xl", title: "ERROR" })));
16407
16451
  };
16408
16452