Skip to content

Commit 8c90572

Browse files
Merge pull request #222 from Mes-Open/develop
Release v0.19.0 β€” version bump + CHANGELOG finalization
2 parents f119330 + 3c37ea2 commit 8c90572

6 files changed

Lines changed: 8 additions & 8 deletions

File tree

β€ŽCHANGELOG.mdβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
55

66
---
77

8-
## [Unreleased]
8+
## [0.19.0] - 2026-08-01
99

1010
### Fixed
11+
- **Module event hooks never fired (and new CRUD / scheduling hooks added)**: the module extension system defined nine domain events, but **seven were never dispatched** β€” a module listening for `WorkOrderCreated`, `WorkOrderUpdated`, `WorkOrderCompleted`, `BatchCreated`, `StepStarted`, `StepCompleted` or `UserAssignedToLine` would silently never run (only `WorkstationStateChanged` and `MachineMessageReceived` actually fired; outbound webhooks use a separate `WebhookDispatcher` path). These are now wired to the model lifecycle so they fire on **every** save path (admin UI, CSV import, ERP API, services): `WorkOrder` gets a `WorkOrderEventObserver` (created/updated, plus `WorkOrderCompleted` on the first transition into `DONE`), `Batch` dispatches `BatchCreated` via `$dispatchesEvents`, and `BatchStep` gets a `BatchStepEventObserver` (`StepStarted`/`StepCompleted` on status transitions). Two new hooks broaden coverage: a **generic CRUD hook** `Resource\ResourceChanged($model, $action)` β€” one wildcard Eloquent listener re-dispatches it for every curated resource (`SoftDeleteRegistry::MODELS`: work orders, customers, materials, lines, … on `created`/`updated`/`deleted`), so a module can react to any resource save without wiring each model; and `Schedule\WorkOrderScheduled($workOrder, $changes)` fired from the planner when a work order is assigned, moved, resized or unassigned. The typed events remain for a specific entity; `ResourceChanged` is the "any resource" catch-all. `ExampleShowcase` demonstrates both new hooks.
12+
- **Module menu hooks stopped appearing after the React migration**: modules extend the navigation by calling `MenuRegistry::addItem()` / `addGroup()` / `addGroupItem()` in their service provider (the PrestaShop-style "hook a tab into the menu" mechanism). The old Blade sidebar read that registry directly via `View::share('menuRegistry')`, but when the sidebar moved to React/Inertia (`resources/js/layouts/adminNav.js`) nothing consumed it anymore β€” so an enabled module could register a menu item or a whole dropdown and **it silently rendered nowhere** in the SPA. `MenuRegistry` is now bridged to the frontend as the **`moduleNav`** Inertia prop (`HandleInertiaRequests`), and `AppLayout` merges those entries into the sidebar: items inject into the matching built-in dropdown (`orders` / `production` / `structure` / `hr` / `maintenance` / `admin`, the last aliased to the React `adminGroup`), and custom groups render as their own top-level dropdowns. Module pages are legacy server-rendered, so their links do a **full navigation** (not an Inertia visit, which would fetch JSON and fail) and also surface in the menu search. Only **enabled** modules populate the registry (their providers boot via `ModuleManager::loadEnabled`), so the bridge is self-gating. **`WidgetRegistry` (dashboard widget hooks) is bridged the same way**: its Blade-view contract β€” dead since the Blade dashboard was deleted β€” is replaced with **structured widget data** (`title` / `metric` / `body` / `href`, no raw HTML), surfaced as the **`moduleWidgets`** Inertia prop (`DashboardController`) and rendered by the React dashboard as standard cards across the `kpi` / `main` / `sidebar` zones (React escapes every field β€” consistent with the no-`dangerouslySetInnerHTML` rule). Shipped alongside a new reference module **`modules/ExampleShowcase`** (disabled by default) that exercises **every** extension point β€” all nine domain events (one handler method per hook), all three `MenuRegistry` APIs and all three `WidgetRegistry` zones β€” purely additively, as a copy-me starting point for real modules.
1113
- **Deleting an already-removed record dumped a bare 404 instead of a message**: deleting an admin CRUD record that was already gone β€” soft-deleted in another tab, a stale list, or a double submit β€” hit route-model binding, which excludes soft-deleted rows, and returned a raw 404 with no feedback. A `DELETE` to `/admin/*` whose record no longer exists now bounces back to the list with an informational flash ("That item was already removed.") instead β€” the delete's intent is already satisfied. Handled centrally in `bootstrap/app.php` for **every** admin resource in one place; a normal single delete still shows "deleted successfully".
1214

1315
## [0.18.0] - 2026-07-25
@@ -41,8 +43,6 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
4143
## [0.17.1] - 2026-07-23
4244

4345
### Fixed
44-
- **Module event hooks never fired (and new CRUD / scheduling hooks added)**: the module extension system defined nine domain events, but **seven were never dispatched** β€” a module listening for `WorkOrderCreated`, `WorkOrderUpdated`, `WorkOrderCompleted`, `BatchCreated`, `StepStarted`, `StepCompleted` or `UserAssignedToLine` would silently never run (only `WorkstationStateChanged` and `MachineMessageReceived` actually fired; outbound webhooks use a separate `WebhookDispatcher` path). These are now wired to the model lifecycle so they fire on **every** save path (admin UI, CSV import, ERP API, services): `WorkOrder` gets a `WorkOrderEventObserver` (created/updated, plus `WorkOrderCompleted` on the first transition into `DONE`), `Batch` dispatches `BatchCreated` via `$dispatchesEvents`, and `BatchStep` gets a `BatchStepEventObserver` (`StepStarted`/`StepCompleted` on status transitions). Two new hooks broaden coverage: a **generic CRUD hook** `Resource\ResourceChanged($model, $action)` β€” one wildcard Eloquent listener re-dispatches it for every curated resource (`SoftDeleteRegistry::MODELS`: work orders, customers, materials, lines, … on `created`/`updated`/`deleted`), so a module can react to any resource save without wiring each model; and `Schedule\WorkOrderScheduled($workOrder, $changes)` fired from the planner when a work order is assigned, moved, resized or unassigned. The typed events remain for a specific entity; `ResourceChanged` is the "any resource" catch-all. `ExampleShowcase` demonstrates both new hooks.
45-
- **Module menu hooks stopped appearing after the React migration**: modules extend the navigation by calling `MenuRegistry::addItem()` / `addGroup()` / `addGroupItem()` in their service provider (the PrestaShop-style "hook a tab into the menu" mechanism). The old Blade sidebar read that registry directly via `View::share('menuRegistry')`, but when the sidebar moved to React/Inertia (`resources/js/layouts/adminNav.js`) nothing consumed it anymore β€” so an enabled module could register a menu item or a whole dropdown and **it silently rendered nowhere** in the SPA. `MenuRegistry` is now bridged to the frontend as the **`moduleNav`** Inertia prop (`HandleInertiaRequests`), and `AppLayout` merges those entries into the sidebar: items inject into the matching built-in dropdown (`orders` / `production` / `structure` / `hr` / `maintenance` / `admin`, the last aliased to the React `adminGroup`), and custom groups render as their own top-level dropdowns. Module pages are legacy server-rendered, so their links do a **full navigation** (not an Inertia visit, which would fetch JSON and fail) and also surface in the menu search. Only **enabled** modules populate the registry (their providers boot via `ModuleManager::loadEnabled`), so the bridge is self-gating. **`WidgetRegistry` (dashboard widget hooks) is bridged the same way**: its Blade-view contract β€” dead since the Blade dashboard was deleted β€” is replaced with **structured widget data** (`title` / `metric` / `body` / `href`, no raw HTML), surfaced as the **`moduleWidgets`** Inertia prop (`DashboardController`) and rendered by the React dashboard as standard cards across the `kpi` / `main` / `sidebar` zones (React escapes every field β€” consistent with the no-`dangerouslySetInnerHTML` rule). Shipped alongside a new reference module **`modules/ExampleShowcase`** (disabled by default) that exercises **every** extension point β€” all nine domain events (one handler method per hook), all three `MenuRegistry` APIs and all three `WidgetRegistry` zones β€” purely additively, as a copy-me starting point for real modules.
4646
- **Login, 2FA and registration errors were never translated**: messages such as "The provided credentials are incorrect.", "Invalid username or PIN." and the registration validation errors stayed English on a Polish (or any non-English) UI. They were **hardcoded English literals** in the auth controllers rather than translation calls, so no `lang/*.json` entry could ever match them β€” adding a translation had no effect. All 29 user-facing strings across `AuthController`, `AuthService`, `TwoFactorController`, `TwoFactorChallengeController`, `RegisterController` and `RegisterRequest` now go through `__()`, with 24 new keys added to `lang/en.json` and `lang/pl.json`. The login screen is covered because `SetLocale` runs in the `web` group, so a guest request already resolves the configured locale.
4747
- **Planner poll hammered the server with 401s after a session expired** *(telemetry: `http_error` was ~57% one endpoint)*: the production planner short-polls `/admin/schedule/check-updates` every 5-10s to sync across tabs. When the session expired on a left-open planner tab, each poll returned **401** and the client silently retried forever, quietly generating hundreds of error events per stale tab. Both pollers (`LiveRefresh` and the planner's tracking poll) now **stop on a 401/419** (session gone) instead of retrying indefinitely β€” a real navigation still bounces the user to login.
4848
- **Customers and Priority Settings links 403'd for non-admin roles** *(telemetry)*: `/admin/customers` and `/admin/priority-rules` sat outside every `TabRegistry` tab, so `TabAccessMiddleware` treated them as **Admin-only (403)** β€” yet the sidebar showed them under the **Orders** group to anyone holding the `orders` tab, so a Supervisor/Operator with Orders access saw the links and got a 403 on click. They now resolve to the **Orders tab**, matching where the nav places them, so access and visibility agree.

β€Žbackend/config/version.phpβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

33
return [
4-
'current' => 'v0.17.1',
4+
'current' => 'v0.19.0',
55
'archive_url' => env('UPDATE_ARCHIVE_URL', 'https://github.com/Mes-Open/OpenMes/archive/refs/tags/{version}.zip'),
66
];

β€Ždesktop/package.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "openmes-desktop",
33
"private": true,
4-
"version": "0.18.0",
4+
"version": "0.19.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

β€Ždesktop/src-tauri/Cargo.lockβ€Ž

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

β€Ždesktop/src-tauri/Cargo.tomlβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "openmes-desktop"
3-
version = "0.18.0"
3+
version = "0.19.0"
44
description = "OpenMES Desktop β€” lokalny serwer MES w aplikacji desktopowej"
55
authors = ["OpenMES"]
66
edition = "2021"

β€Ždesktop/src-tauri/tauri.conf.jsonβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "openmes-desktop",
4-
"version": "0.18.0",
4+
"version": "0.19.0",
55
"identifier": "com.openmes.desktop",
66
"build": {
77
"beforeDevCommand": "npm run dev",

0 commit comments

Comments
Β (0)