You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8c90572
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CHANGELOG.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,9 +5,11 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
5
5
6
6
---
7
7
8
-
## [Unreleased]
8
+
## [0.19.0] - 2026-08-01
9
9
10
10
### 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.
11
13
-**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".
12
14
13
15
## [0.18.0] - 2026-07-25
@@ -41,8 +43,6 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
41
43
## [0.17.1] - 2026-07-23
42
44
43
45
### 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.
46
46
-**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.
47
47
-**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.
48
48
-**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.
0 commit comments