[Bug 42189] New: Allow plugins to inject dashboard widgets via a shared Vue widget registry
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Bug ID: 42189 Summary: Allow plugins to inject dashboard widgets via a shared Vue widget registry Initiative type: --- Sponsorship --- status: Product: Koha Version: Main Hardware: All OS: All Status: NEW Severity: enhancement Priority: P5 - low Component: Plugin architecture Assignee: koha-bugs@lists.koha-community.org Reporter: paul.derscheid@lmscloud.de QA Contact: testopia@bugs.koha-community.org Koha's Vue module dashboards (ERM, Preservation, etc.) currently have a hardcoded set of widgets. There is no mechanism for plugins to contribute their own widgets that integrate with the existing dashboard infrastructure (WidgetWrapper, WidgetPicker, drag-and-drop, localStorage persistence). This patch set introduces a widget registry that plugins can extend from their intranet_js() hook, along with the build infrastructure needed to make it work correctly across bundle boundaries. -- You are receiving this mail because: You are watching all bug changes. You are the assignee for the bug.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Depends on| |42150 Assignee|koha-bugs@lists.koha-commun |paul.derscheid@lmscloud.de |ity.org | Referenced Bugs: https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42150 [Bug 42150] Allow plugins to register Vue islands via registerIsland() -- You are receiving this mail because: You are watching all bug changes. You are the assignee for the bug.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |Needs Signoff -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #1 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196223 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196223&action=edit Bug 42189: Add widget registry for plugin-provided dashboard widgets - Add widget-registry.ts with shared window.__kohaWidgetRegistry Map - registerWidget() validates entries and dispatches a DOM CustomEvent so ModuleDashboard can discover widgets registered after mount - getRegisteredWidgets() returns markRaw-wrapped components for a given module, with defineAsyncComponent support for lazy loading - ModuleDashboard accepts a module prop and discovers plugin widgets via onMounted catch-up + koha:widget-registered event listener - Home.vue passes module="erm" to ModuleDashboard To test: - Build with yarn js:build, verify .esm.js bundles are produced - Verify ERM, Preservation, Acquisitions, Admin > Record sources, and SIP2 pages load without errors - Install the test plugin (test-widgetdemo-0.1.0.kpz) - Navigate to ERM home, plugin widget should appear on the dashboard - Click the counter button, verify reactivity works (shared Vue) - Open Widget Picker, plugin widget should be listed with Add/Remove - Remove and re-add the widget, verify it works - Refresh the page, verify widget position is restored from localStorage - Verify the widget renders with WidgetWrapper chrome (header, drag handle, settings menu) matching core widgets -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #2 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196224 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196224&action=edit Bug 42189: Build shared Vue runtime via ESM and import map - Restructure rspack.config.js into three config blocks: - Vue runtime ESM: builds vue-runtime.ts which re-exports all of Vue through DefinePlugin so feature flags (__VUE_OPTIONS_API__ etc.) are correctly applied in both development and production builds - App ESM bundles: all Vue modules (islands, erm, preservation, etc.) externalize vue via externalsType "module-import", resolved by the browser's import map to the shared vue.esm.js - Cypress CJS: unchanged - Add import map to doc-head-close.inc mapping "vue", "jQuery", and "DataTable" bare specifiers to their respective ESM files - Add jQuery and DataTables ESM shim files that re-export the globals loaded by classic script tags (window.jQuery, window.DataTable) - This ensures a single Vue runtime instance across all bundles, enabling Composition API reactivity to work across bundle boundaries -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #3 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196225 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196225&action=edit Bug 42189: Switch Vue module templates to ESM bundles - Replace Asset.js() regular script includes with type="module" script tags loading .esm.js bundles for erm, preservation, acquisitions, admin/record_sources, and sip2 - Load islands.esm.js on ERM page so plugins can discover it via querySelector for widget registration - Update about.tt build health check from erm.js to erm.esm.js - Standardize Asset.js().match() pattern in main-container.inc to use single capture group consistent with all other template files - Remove redundant nonce-less script tag from main-container.inc -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #4 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196226 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196226&action=edit Bug 42189: Re-export Vue APIs and widget components from islands - Add explicit named re-exports of Vue APIs (h, ref, computed, provide, inject, onMounted, etc.) from islands.ts for plugin use - With Vue externalized, export * from "vue" produces no output since rspack cannot statically resolve external module exports; explicit re-exports are required instead - Export WidgetWrapper component so plugins can render widgets with the same chrome as core dashboard widgets - Export useBaseWidget composable for plugin widget lifecycle management - Plugins import everything from a single source: islands.esm.js -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #5 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196227 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196227&action=edit Bug 42189: Fix .name on async plugin widgets in widget registry - defineAsyncComponent wrappers do not carry the original component's .name property, causing ModuleDashboard to fail on deduplication, localStorage persistence, and v-for key generation - getRegisteredWidgets now stamps entry.id as the component name when .name is missing, ensuring a stable identity for all widget types - Replace any type with Component & { name?: string } for type safety -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #6 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196228 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196228&action=edit Test plugin for widget injection. -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Pedro Amorim <pedro.amorim@openfifth.co.uk> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |clemens.tubach@kit.edu, | |matt.blenkinsop@openfifth.c | |o.uk, | |michaela.sieber@kit.edu, | |pedro.amorim@openfifth.co.u | |k -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Michaela Sieber <michaela.sieber@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Needs Signoff |Failed QA --- Comment #7 from Michaela Sieber <michaela.sieber@kit.edu> --- This is awsome, we love it! we followed the test plan and everything worked except the widget position. It is restored from localStorage if you have changed the position of the plugin widget -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #8 from Michaela Sieber <michaela.sieber@kit.edu> --- Sorry, seems I forgot the most relevant word ;-) it is NOT restored from localStorage if you have changed the position of the plugin widget -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Failed QA |Needs Signoff -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #9 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196512 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196512&action=edit Bug 42189: (follow-up) Restore plugin widget positions from localStorage - Merge registry widgets into availableWidgets before localStorage restore so saved positions are found during the lookup phase - In the late-registration event handler, check localStorage for saved column and index instead of using the default addWidget() placement To test: - Install test-widgetdemo plugin, navigate to ERM home - Move the plugin widget to a different column/position - Refresh the page - Verify the plugin widget reappears in the saved position -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #10 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196513 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196513&action=edit Bug 42189: (follow-up) Guard localStorage JSON.parse against corrupt data - Wrap JSON.parse in try/catch in onMounted so corrupt or stale localStorage does not abort dashboard initialization - On parse failure, remove the bad key and fall through to the default layout instead of leaving the dashboard empty - Apply the same guard in onWidgetRegistered event handler To test: - Set localStorage "dashboard-widgets" to invalid JSON (e.g. "{bad") - Load the ERM dashboard - Verify widgets render with default layout instead of a blank page - Verify localStorage is cleaned up after the failed parse -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #11 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196514 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196514&action=edit Bug 42189: (follow-up) Update widget-registry docs for shared Vue runtime - Remove outdated warning that plugins must use Options API only - Document that both Composition API and Options API work since all bundles share a single Vue instance via the import map - Update example to show idiomatic Composition API with useBaseWidget, WidgetWrapper, and ref To test: - Read the JSDoc on registerWidget() in widget-registry.ts - Verify the example matches the actual plugin contract -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #12 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196515 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196515&action=edit Bug 42189: (follow-up) Cache resolved component at registration time - Move defineAsyncComponent wrapping, name fallback, and markRaw from getRegisteredWidgets into registerWidget so the component is resolved once and the same object reference is returned on every call - Simplify getRegisteredWidgets to a plain filter over the registry To test: - Register a plugin widget with an async factory function - Verify the widget renders correctly on the dashboard - Verify that calling getRegisteredWidgets multiple times returns the same component reference (no duplicate wrappers) -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #13 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196516 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196516&action=edit Bug 42189: (follow-up) Fix onWidgetRegistered to target single widget - Filter to just the newly arrived widget via e.detail.id instead of re-evaluating all registered widgets, which could re-add widgets the user had previously removed - Replace splice-by-saved-index with push to avoid inserting at a stale index into a partially populated array To test: - Install two plugin widgets targeting the same module - Register the second one after the first is already on the dashboard - Verify only the new widget is added, not a duplicate of the first -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #14 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 196517 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196517&action=edit Bug 42189: (follow-up) Track known widgets to preserve removal state - Persist a "known" array in localStorage alongside left/right so the dashboard can distinguish genuinely new widgets from deliberately removed ones - On restore, only auto-add widgets whose name is not in known - In onWidgetRegistered, skip widgets present in known to prevent removed widgets from reappearing on subsequent registration events To test: - Add the plugin widget to the ERM dashboard, then remove it - Refresh — verify the removed widget does not reappear - Clear localStorage and refresh — verify all widgets appear - Install a new plugin widget — verify it auto-adds on first visit even when other widgets have saved state -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #15 from Paul Derscheid <paul.derscheid@lmscloud.de> --- (I found more bugs :D) -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 David Cook <dcook@prosentient.com.au> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |dcook@prosentient.com.au --- Comment #16 from David Cook <dcook@prosentient.com.au> --- (In reply to Paul Derscheid from comment #15)
(I found more bugs :D)
Hehehe This sounds interesting! I don't really have anyone using the Vue-based modules but this sounds very cool and like it could be useful in the long-term. I'm going to make a note to check this out later. -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Michael Skarupianski <michael.skarupianski@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |michael.skarupianski@gmail. | |com -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Needs Signoff |Signed Off -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196223|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196224|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196225|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196226|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196227|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196512|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196513|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196514|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196515|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196516|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Clemens Tubach <clemens.tubach@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196517|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #17 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196550 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196550&action=edit Bug 42189: Add widget registry for plugin-provided dashboard widgets - Add widget-registry.ts with shared window.__kohaWidgetRegistry Map - registerWidget() validates entries and dispatches a DOM CustomEvent so ModuleDashboard can discover widgets registered after mount - getRegisteredWidgets() returns markRaw-wrapped components for a given module, with defineAsyncComponent support for lazy loading - ModuleDashboard accepts a module prop and discovers plugin widgets via onMounted catch-up + koha:widget-registered event listener - Home.vue passes module="erm" to ModuleDashboard To test: - Build with yarn js:build, verify .esm.js bundles are produced - Verify ERM, Preservation, Acquisitions, Admin > Record sources, and SIP2 pages load without errors - Install the test plugin (test-widgetdemo-0.1.0.kpz) - Navigate to ERM home, plugin widget should appear on the dashboard - Click the counter button, verify reactivity works (shared Vue) - Open Widget Picker, plugin widget should be listed with Add/Remove - Remove and re-add the widget, verify it works - Refresh the page, verify widget position is restored from localStorage - Verify the widget renders with WidgetWrapper chrome (header, drag handle, settings menu) matching core widgets Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #18 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196551 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196551&action=edit Bug 42189: Build shared Vue runtime via ESM and import map - Restructure rspack.config.js into three config blocks: - Vue runtime ESM: builds vue-runtime.ts which re-exports all of Vue through DefinePlugin so feature flags (__VUE_OPTIONS_API__ etc.) are correctly applied in both development and production builds - App ESM bundles: all Vue modules (islands, erm, preservation, etc.) externalize vue via externalsType "module-import", resolved by the browser's import map to the shared vue.esm.js - Cypress CJS: unchanged - Add import map to doc-head-close.inc mapping "vue", "jQuery", and "DataTable" bare specifiers to their respective ESM files - Add jQuery and DataTables ESM shim files that re-export the globals loaded by classic script tags (window.jQuery, window.DataTable) - This ensures a single Vue runtime instance across all bundles, enabling Composition API reactivity to work across bundle boundaries Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #19 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196552 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196552&action=edit Bug 42189: Switch Vue module templates to ESM bundles - Replace Asset.js() regular script includes with type="module" script tags loading .esm.js bundles for erm, preservation, acquisitions, admin/record_sources, and sip2 - Load islands.esm.js on ERM page so plugins can discover it via querySelector for widget registration - Update about.tt build health check from erm.js to erm.esm.js - Standardize Asset.js().match() pattern in main-container.inc to use single capture group consistent with all other template files - Remove redundant nonce-less script tag from main-container.inc Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #20 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196553 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196553&action=edit Bug 42189: Re-export Vue APIs and widget components from islands - Add explicit named re-exports of Vue APIs (h, ref, computed, provide, inject, onMounted, etc.) from islands.ts for plugin use - With Vue externalized, export * from "vue" produces no output since rspack cannot statically resolve external module exports; explicit re-exports are required instead - Export WidgetWrapper component so plugins can render widgets with the same chrome as core dashboard widgets - Export useBaseWidget composable for plugin widget lifecycle management - Plugins import everything from a single source: islands.esm.js Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #21 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196554 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196554&action=edit Bug 42189: Fix .name on async plugin widgets in widget registry - defineAsyncComponent wrappers do not carry the original component's .name property, causing ModuleDashboard to fail on deduplication, localStorage persistence, and v-for key generation - getRegisteredWidgets now stamps entry.id as the component name when .name is missing, ensuring a stable identity for all widget types - Replace any type with Component & { name?: string } for type safety Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #22 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196555 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196555&action=edit Bug 42189: (follow-up) Restore plugin widget positions from localStorage - Merge registry widgets into availableWidgets before localStorage restore so saved positions are found during the lookup phase - In the late-registration event handler, check localStorage for saved column and index instead of using the default addWidget() placement To test: - Install test-widgetdemo plugin, navigate to ERM home - Move the plugin widget to a different column/position - Refresh the page - Verify the plugin widget reappears in the saved position Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #23 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196556 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196556&action=edit Bug 42189: (follow-up) Guard localStorage JSON.parse against corrupt data - Wrap JSON.parse in try/catch in onMounted so corrupt or stale localStorage does not abort dashboard initialization - On parse failure, remove the bad key and fall through to the default layout instead of leaving the dashboard empty - Apply the same guard in onWidgetRegistered event handler To test: - Set localStorage "dashboard-widgets" to invalid JSON (e.g. "{bad") - Load the ERM dashboard - Verify widgets render with default layout instead of a blank page - Verify localStorage is cleaned up after the failed parse Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #24 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196557 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196557&action=edit Bug 42189: (follow-up) Update widget-registry docs for shared Vue runtime - Remove outdated warning that plugins must use Options API only - Document that both Composition API and Options API work since all bundles share a single Vue instance via the import map - Update example to show idiomatic Composition API with useBaseWidget, WidgetWrapper, and ref To test: - Read the JSDoc on registerWidget() in widget-registry.ts - Verify the example matches the actual plugin contract Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #25 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196558 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196558&action=edit Bug 42189: (follow-up) Cache resolved component at registration time - Move defineAsyncComponent wrapping, name fallback, and markRaw from getRegisteredWidgets into registerWidget so the component is resolved once and the same object reference is returned on every call - Simplify getRegisteredWidgets to a plain filter over the registry To test: - Register a plugin widget with an async factory function - Verify the widget renders correctly on the dashboard - Verify that calling getRegisteredWidgets multiple times returns the same component reference (no duplicate wrappers) Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #26 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196559 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196559&action=edit Bug 42189: (follow-up) Fix onWidgetRegistered to target single widget - Filter to just the newly arrived widget via e.detail.id instead of re-evaluating all registered widgets, which could re-add widgets the user had previously removed - Replace splice-by-saved-index with push to avoid inserting at a stale index into a partially populated array To test: - Install two plugin widgets targeting the same module - Register the second one after the first is already on the dashboard - Verify only the new widget is added, not a duplicate of the first Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #27 from Clemens Tubach <clemens.tubach@kit.edu> --- Created attachment 196560 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=196560&action=edit Bug 42189: (follow-up) Track known widgets to preserve removal state - Persist a "known" array in localStorage alongside left/right so the dashboard can distinguish genuinely new widgets from deliberately removed ones - On restore, only auto-add widgets whose name is not in known - In onWidgetRegistered, skip widgets present in known to prevent removed widgets from reappearing on subsequent registration events To test: - Add the plugin widget to the ERM dashboard, then remove it - Refresh — verify the removed widget does not reappear - Clear localStorage and refresh — verify all widgets appear - Install a new plugin widget — verify it auto-adds on first visit even when other widgets have saved state Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Michaela Sieber <michaela.sieber@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jan.kissig@th-wildau.de, | |katrin.fischer@bsz-bw.de -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Signed Off |Passed QA --- Comment #28 from Thomas Klausner <domm@plix.at> --- I followed the main test plan in comment #17, and everything worked as described there. I also tried some of the smaller test plans in other comments, and what I could test worked. The QA script reported OK. So I say, wow, nice feature, please apply! -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196550|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196551|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196552|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196553|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196554|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196555|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196556|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196557|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196558|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196559|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Thomas Klausner <domm@plix.at> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #196560|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #29 from Thomas Klausner <domm@plix.at> --- Created attachment 198141 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198141&action=edit Bug 42189: Add widget registry for plugin-provided dashboard widgets - Add widget-registry.ts with shared window.__kohaWidgetRegistry Map - registerWidget() validates entries and dispatches a DOM CustomEvent so ModuleDashboard can discover widgets registered after mount - getRegisteredWidgets() returns markRaw-wrapped components for a given module, with defineAsyncComponent support for lazy loading - ModuleDashboard accepts a module prop and discovers plugin widgets via onMounted catch-up + koha:widget-registered event listener - Home.vue passes module="erm" to ModuleDashboard To test: - Build with yarn js:build, verify .esm.js bundles are produced - Verify ERM, Preservation, Acquisitions, Admin > Record sources, and SIP2 pages load without errors - Install the test plugin (test-widgetdemo-0.1.0.kpz) - Navigate to ERM home, plugin widget should appear on the dashboard - Click the counter button, verify reactivity works (shared Vue) - Open Widget Picker, plugin widget should be listed with Add/Remove - Remove and re-add the widget, verify it works - Refresh the page, verify widget position is restored from localStorage - Verify the widget renders with WidgetWrapper chrome (header, drag handle, settings menu) matching core widgets Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #30 from Thomas Klausner <domm@plix.at> --- Created attachment 198142 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198142&action=edit Bug 42189: Build shared Vue runtime via ESM and import map - Restructure rspack.config.js into three config blocks: - Vue runtime ESM: builds vue-runtime.ts which re-exports all of Vue through DefinePlugin so feature flags (__VUE_OPTIONS_API__ etc.) are correctly applied in both development and production builds - App ESM bundles: all Vue modules (islands, erm, preservation, etc.) externalize vue via externalsType "module-import", resolved by the browser's import map to the shared vue.esm.js - Cypress CJS: unchanged - Add import map to doc-head-close.inc mapping "vue", "jQuery", and "DataTable" bare specifiers to their respective ESM files - Add jQuery and DataTables ESM shim files that re-export the globals loaded by classic script tags (window.jQuery, window.DataTable) - This ensures a single Vue runtime instance across all bundles, enabling Composition API reactivity to work across bundle boundaries Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #31 from Thomas Klausner <domm@plix.at> --- Created attachment 198143 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198143&action=edit Bug 42189: Switch Vue module templates to ESM bundles - Replace Asset.js() regular script includes with type="module" script tags loading .esm.js bundles for erm, preservation, acquisitions, admin/record_sources, and sip2 - Load islands.esm.js on ERM page so plugins can discover it via querySelector for widget registration - Update about.tt build health check from erm.js to erm.esm.js - Standardize Asset.js().match() pattern in main-container.inc to use single capture group consistent with all other template files - Remove redundant nonce-less script tag from main-container.inc Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #32 from Thomas Klausner <domm@plix.at> --- Created attachment 198144 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198144&action=edit Bug 42189: Re-export Vue APIs and widget components from islands - Add explicit named re-exports of Vue APIs (h, ref, computed, provide, inject, onMounted, etc.) from islands.ts for plugin use - With Vue externalized, export * from "vue" produces no output since rspack cannot statically resolve external module exports; explicit re-exports are required instead - Export WidgetWrapper component so plugins can render widgets with the same chrome as core dashboard widgets - Export useBaseWidget composable for plugin widget lifecycle management - Plugins import everything from a single source: islands.esm.js Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #33 from Thomas Klausner <domm@plix.at> --- Created attachment 198145 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198145&action=edit Bug 42189: Fix .name on async plugin widgets in widget registry - defineAsyncComponent wrappers do not carry the original component's .name property, causing ModuleDashboard to fail on deduplication, localStorage persistence, and v-for key generation - getRegisteredWidgets now stamps entry.id as the component name when .name is missing, ensuring a stable identity for all widget types - Replace any type with Component & { name?: string } for type safety Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #34 from Thomas Klausner <domm@plix.at> --- Created attachment 198146 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198146&action=edit Bug 42189: (follow-up) Restore plugin widget positions from localStorage - Merge registry widgets into availableWidgets before localStorage restore so saved positions are found during the lookup phase - In the late-registration event handler, check localStorage for saved column and index instead of using the default addWidget() placement To test: - Install test-widgetdemo plugin, navigate to ERM home - Move the plugin widget to a different column/position - Refresh the page - Verify the plugin widget reappears in the saved position Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #35 from Thomas Klausner <domm@plix.at> --- Created attachment 198147 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198147&action=edit Bug 42189: (follow-up) Guard localStorage JSON.parse against corrupt data - Wrap JSON.parse in try/catch in onMounted so corrupt or stale localStorage does not abort dashboard initialization - On parse failure, remove the bad key and fall through to the default layout instead of leaving the dashboard empty - Apply the same guard in onWidgetRegistered event handler To test: - Set localStorage "dashboard-widgets" to invalid JSON (e.g. "{bad") - Load the ERM dashboard - Verify widgets render with default layout instead of a blank page - Verify localStorage is cleaned up after the failed parse Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #36 from Thomas Klausner <domm@plix.at> --- Created attachment 198148 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198148&action=edit Bug 42189: (follow-up) Update widget-registry docs for shared Vue runtime - Remove outdated warning that plugins must use Options API only - Document that both Composition API and Options API work since all bundles share a single Vue instance via the import map - Update example to show idiomatic Composition API with useBaseWidget, WidgetWrapper, and ref To test: - Read the JSDoc on registerWidget() in widget-registry.ts - Verify the example matches the actual plugin contract Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #37 from Thomas Klausner <domm@plix.at> --- Created attachment 198149 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198149&action=edit Bug 42189: (follow-up) Cache resolved component at registration time - Move defineAsyncComponent wrapping, name fallback, and markRaw from getRegisteredWidgets into registerWidget so the component is resolved once and the same object reference is returned on every call - Simplify getRegisteredWidgets to a plain filter over the registry To test: - Register a plugin widget with an async factory function - Verify the widget renders correctly on the dashboard - Verify that calling getRegisteredWidgets multiple times returns the same component reference (no duplicate wrappers) Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #38 from Thomas Klausner <domm@plix.at> --- Created attachment 198150 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198150&action=edit Bug 42189: (follow-up) Fix onWidgetRegistered to target single widget - Filter to just the newly arrived widget via e.detail.id instead of re-evaluating all registered widgets, which could re-add widgets the user had previously removed - Replace splice-by-saved-index with push to avoid inserting at a stale index into a partially populated array To test: - Install two plugin widgets targeting the same module - Register the second one after the first is already on the dashboard - Verify only the new widget is added, not a duplicate of the first Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #39 from Thomas Klausner <domm@plix.at> --- Created attachment 198151 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198151&action=edit Bug 42189: (follow-up) Track known widgets to preserve removal state - Persist a "known" array in localStorage alongside left/right so the dashboard can distinguish genuinely new widgets from deliberately removed ones - On restore, only auto-add widgets whose name is not in known - In onWidgetRegistered, skip widgets present in known to prevent removed widgets from reappearing on subsequent registration events To test: - Add the plugin widget to the ERM dashboard, then remove it - Refresh — verify the removed widget does not reappear - Clear localStorage and refresh — verify all widgets appear - Install a new plugin widget — verify it auto-adds on first visit even when other widgets have saved state Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Michaela Sieber <michaela.sieber@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- QA Contact|testopia@bugs.koha-communit |domm@plix.at |y.org | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Michaela Sieber <michaela.sieber@kit.edu> changed: What |Removed |Added ---------------------------------------------------------------------------- Text to go in the| |Koha’s dashboards (such as release notes| |ERM home page) currently | |offer only a fixed set of | |widgets, and plugins can’t | |add new ones. | | | |This enhancement introduces | |a widget registry, which | |allows plugins to provide | |their own widgets. These | |widgets integrate smoothly | |into the existing | |dashboards — including | |selection and drag-and-drop | |layout. -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Lucas Gass (lukeg) <lucas@bywatersolutions.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Passed QA |Patch doesn't apply CC| |lucas@bywatersolutions.com -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Patch doesn't apply |Passed QA -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198141|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198142|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198143|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198144|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198145|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198146|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198147|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198148|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198149|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198150|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Paul Derscheid <paul.derscheid@lmscloud.de> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #198151|0 |1 is obsolete| | -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #40 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198926 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198926&action=edit Bug 42189: Add widget registry for plugin-provided dashboard widgets - Add widget-registry.ts with shared window.__kohaWidgetRegistry Map - registerWidget() validates entries and dispatches a DOM CustomEvent so ModuleDashboard can discover widgets registered after mount - getRegisteredWidgets() returns markRaw-wrapped components for a given module, with defineAsyncComponent support for lazy loading - ModuleDashboard accepts a module prop and discovers plugin widgets via onMounted catch-up + koha:widget-registered event listener - Home.vue passes module="erm" to ModuleDashboard To test: - Build with yarn js:build, verify .esm.js bundles are produced - Verify ERM, Preservation, Acquisitions, Admin > Record sources, and SIP2 pages load without errors - Install the test plugin (test-widgetdemo-0.1.0.kpz) - Navigate to ERM home, plugin widget should appear on the dashboard - Click the counter button, verify reactivity works (shared Vue) - Open Widget Picker, plugin widget should be listed with Add/Remove - Remove and re-add the widget, verify it works - Refresh the page, verify widget position is restored from localStorage - Verify the widget renders with WidgetWrapper chrome (header, drag handle, settings menu) matching core widgets Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #41 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198927 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198927&action=edit Bug 42189: Build shared Vue runtime via ESM and import map - Restructure rspack.config.js into three config blocks: - Vue runtime ESM: builds vue-runtime.ts which re-exports all of Vue through DefinePlugin so feature flags (__VUE_OPTIONS_API__ etc.) are correctly applied in both development and production builds - App ESM bundles: all Vue modules (islands, erm, preservation, etc.) externalize vue via externalsType "module-import", resolved by the browser's import map to the shared vue.esm.js - Cypress CJS: unchanged - Add import map to doc-head-close.inc mapping "vue", "jQuery", and "DataTable" bare specifiers to their respective ESM files - Add jQuery and DataTables ESM shim files that re-export the globals loaded by classic script tags (window.jQuery, window.DataTable) - This ensures a single Vue runtime instance across all bundles, enabling Composition API reactivity to work across bundle boundaries Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #42 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198928 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198928&action=edit Bug 42189: Switch Vue module templates to ESM bundles - Replace Asset.js() regular script includes with type="module" script tags loading .esm.js bundles for erm, preservation, acquisitions, admin/record_sources, and sip2 - Load islands.esm.js on ERM page so plugins can discover it via querySelector for widget registration - Update about.tt build health check from erm.js to erm.esm.js - Standardize Asset.js().match() pattern in main-container.inc to use single capture group consistent with all other template files - Remove redundant nonce-less script tag from main-container.inc Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #43 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198929 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198929&action=edit Bug 42189: Re-export Vue APIs and widget components from islands - Add explicit named re-exports of Vue APIs (h, ref, computed, provide, inject, onMounted, etc.) from islands.ts for plugin use - With Vue externalized, export * from "vue" produces no output since rspack cannot statically resolve external module exports; explicit re-exports are required instead - Export WidgetWrapper component so plugins can render widgets with the same chrome as core dashboard widgets - Export useBaseWidget composable for plugin widget lifecycle management - Plugins import everything from a single source: islands.esm.js Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #44 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198930 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198930&action=edit Bug 42189: Fix .name on async plugin widgets in widget registry - defineAsyncComponent wrappers do not carry the original component's .name property, causing ModuleDashboard to fail on deduplication, localStorage persistence, and v-for key generation - getRegisteredWidgets now stamps entry.id as the component name when .name is missing, ensuring a stable identity for all widget types - Replace any type with Component & { name?: string } for type safety Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #45 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198931 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198931&action=edit Bug 42189: (follow-up) Restore plugin widget positions from localStorage - Merge registry widgets into availableWidgets before localStorage restore so saved positions are found during the lookup phase - In the late-registration event handler, check localStorage for saved column and index instead of using the default addWidget() placement To test: - Install test-widgetdemo plugin, navigate to ERM home - Move the plugin widget to a different column/position - Refresh the page - Verify the plugin widget reappears in the saved position Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #46 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198932 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198932&action=edit Bug 42189: (follow-up) Guard localStorage JSON.parse against corrupt data - Wrap JSON.parse in try/catch in onMounted so corrupt or stale localStorage does not abort dashboard initialization - On parse failure, remove the bad key and fall through to the default layout instead of leaving the dashboard empty - Apply the same guard in onWidgetRegistered event handler To test: - Set localStorage "dashboard-widgets" to invalid JSON (e.g. "{bad") - Load the ERM dashboard - Verify widgets render with default layout instead of a blank page - Verify localStorage is cleaned up after the failed parse Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #47 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198933 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198933&action=edit Bug 42189: (follow-up) Update widget-registry docs for shared Vue runtime - Remove outdated warning that plugins must use Options API only - Document that both Composition API and Options API work since all bundles share a single Vue instance via the import map - Update example to show idiomatic Composition API with useBaseWidget, WidgetWrapper, and ref To test: - Read the JSDoc on registerWidget() in widget-registry.ts - Verify the example matches the actual plugin contract Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #48 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198934 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198934&action=edit Bug 42189: (follow-up) Cache resolved component at registration time - Move defineAsyncComponent wrapping, name fallback, and markRaw from getRegisteredWidgets into registerWidget so the component is resolved once and the same object reference is returned on every call - Simplify getRegisteredWidgets to a plain filter over the registry To test: - Register a plugin widget with an async factory function - Verify the widget renders correctly on the dashboard - Verify that calling getRegisteredWidgets multiple times returns the same component reference (no duplicate wrappers) Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #49 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198935 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198935&action=edit Bug 42189: (follow-up) Fix onWidgetRegistered to target single widget - Filter to just the newly arrived widget via e.detail.id instead of re-evaluating all registered widgets, which could re-add widgets the user had previously removed - Replace splice-by-saved-index with push to avoid inserting at a stale index into a partially populated array To test: - Install two plugin widgets targeting the same module - Register the second one after the first is already on the dashboard - Verify only the new widget is added, not a duplicate of the first Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #50 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198936 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198936&action=edit Bug 42189: (follow-up) Track known widgets to preserve removal state - Persist a "known" array in localStorage alongside left/right so the dashboard can distinguish genuinely new widgets from deliberately removed ones - On restore, only auto-add widgets whose name is not in known - In onWidgetRegistered, skip widgets present in known to prevent removed widgets from reappearing on subsequent registration events To test: - Add the plugin widget to the ERM dashboard, then remove it - Refresh — verify the removed widget does not reappear - Clear localStorage and refresh — verify all widgets appear - Install a new plugin widget — verify it auto-adds on first visit even when other widgets have saved state Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu> Signed-off-by: Thomas Klausner <domm@plix.at> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #51 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198937 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198937&action=edit Bug 42189: (QA follow-up) Document shim timing constraints - Spell out in jquery.esm.js and datatables.esm.js that the shims capture window.jQuery / window.DataTable as read-once snapshots at module evaluation time, not live bindings - Note the ordering requirement (classic <script> tag must run before any importing module) and the failure modes if it does not, so future template changes do not regress it silently - No functional change; standard staff-client templates already satisfy the ordering via the implicit defer on type="module" To test: - Load any Vue module page (e.g. /cgi-bin/koha/erm/erm.pl) and confirm jQuery and DataTables still work inside the ESM bundles -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #52 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198938 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198938&action=edit Bug 42189: (QA follow-up) Document import map ordering constraint - Add a TT comment above the import map in doc-head-close.inc explaining it must precede every type="module" script that uses bare specifiers, per the HTML spec - Spell out the practical rule: do not move the block below any module-script tag, and do not inline a module script in <head> before this point, otherwise bare imports break silently To test: - Load any Vue module page (e.g. /cgi-bin/koha/erm/erm.pl) - View source and confirm the import map renders above the bundle <script> tag; DevTools shows no warnings about an import map arriving too late -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #53 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198939 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198939&action=edit Bug 42189: (QA follow-up) Use Asset.js attrs and Asset.url for ESM - Drop the hand-rolled [% SET x = Asset.js("foo.esm.js").match('src="([^"]+)"').0 %] pattern; use Asset.js's existing attributes hashref to emit the type="module" nonced script tag, and Asset.url(path) for URL-only callers (importmap entries, inline import statements) - The original regex re-parsed Asset.js's own output back into a URL, so a future change to its tag format (extra attribute, different quote style) would silently break every consumer - Asset.css already takes attributes the same way (see t/db_dependent/Koha/Template/Plugin/Asset.t for the media="print" example), so this is an existing pattern - Fix wrapper-staff-tool-plugin.inc which the original patch missed; it still carried the old double-capture regex and the redundant nonce-less <script> tag that was removed from main-container.inc To test: - prove t/db_dependent/Koha/Template/Plugin/Asset.t - yarn js:build and load each affected page: /cgi-bin/koha/acqui/vendors.pl /cgi-bin/koha/admin/record_sources.pl /cgi-bin/koha/erm/erm.pl /cgi-bin/koha/preservation/home.pl /cgi-bin/koha/sip2/sip2.pl any tool/report plugin (uses wrapper-staff-tool-plugin.inc) - View source; confirm each bundle is loaded via <script src="..." type="module" nonce="..."></script> -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #54 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198940 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198940&action=edit Bug 42189: (QA follow-up) Stop bundling Cypress fixtures into prod - Convert rspack.config.js to function form so it can branch on argv.mode at config-load time - Drop the @cypress alias from commonResolve in production builds; only inject it when argv.mode is not "production" - Guard componentResolver.js's require.context("@cypress", ...) with process.env.NODE_ENV !== "production" so the bundler dead-codes the eager Cypress fixture collection - Throw at runtime if a @cypress/ path is ever passed to loadComponent in production, so the failure is loud rather than a silent miss - The two guards together prevent t/cypress/.vue files from reaching staff-client bundles even if a future change regresses one half To test: - yarn js:clean && yarn js:build (dev should succeed) - yarn js:clean && yarn js:build:prod (prod should succeed) - grep -l 't/cypress\|cypress/component' \ koha-tmpl/intranet-tmpl/prog/js/vue/dist/*.esm.js Production output: no matches expected (the bare string "@cypress/" survives as a runtime check; that is harmless) - ERM page and dashboard widgets should still work -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #55 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 198941 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=198941&action=edit Bug 42189: (QA follow-up) Stop mutating caller input in registerWidget - registerWidget previously assigned markRaw(component) back onto the caller's WidgetRegistryEntry and, for sync components, set .name directly on the caller's component - Shallow-clone the sync component before defaulting its name and applying markRaw, and store a fresh entry in the registry via { ...entry, component: markRaw(component) } instead of reusing the caller's object - defineAsyncComponent already returns a fresh wrapper, so the async path is unchanged in spirit - Closes three concrete failure modes for plugin authors: - Object.freeze'd entries hit TypeError on the .component assignment and registration silently aborts before the koha:widget-registered event fires - Entry reuse across two registerWidget calls carries state from the first into the second - Reading entry.component after register() returns the markRaw'd value rather than what was passed in - No public API change; the registry stores the same data, just without touching caller-owned objects To test: - yarn js:build - In a browser console on /cgi-bin/koha/erm/erm.pl, dynamic- import islands.esm.js, then call registerWidget on a frozen entry, e.g.: const e = Object.freeze({ id: "T", module: "erm", component: { name: "T", setup() { return () => null } } }); registerWidget(e); Confirm no TypeError and the koha:widget-registered event fires -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Pedro Amorim (ammopt) <pedro.amorim@openfifth.co.uk> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|Passed QA |Failed QA --- Comment #56 from Pedro Amorim (ammopt) <pedro.amorim@openfifth.co.uk> --- Hi all, great work. Some minor comments mostly due to bug 37762 now being in main (it wasn't when this work was first developed): 1) js/vue/dist/ill.js needs to part of 'Switch Vue module templates' commit 2) Having to set and include islands_esm_src in erm.tt when it's already been done in main-container.inc looks redundant. Please confirm. Ideally it would only be loaded once in main-container.inc (as opposed to every future new module dashboard having to explicitly also import that). 3) The original implementation added the following: module="erm" but at the time, ModuleDashboard did not have the 'name' parameter. Do we still need to add the 'module' attribute or can we now just use the existing 'name' for uniqueness purposes of widgets filtering? i.e. drop the 'module' attribute that this patchset is adding (it's redundant). -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #57 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 201076 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=201076&action=edit Bug 42189: (QA follow-up) Switch ILL dashboard template to ESM - Bug 37762 (VueJS ILL module) landed in main after this patch set was first written, so ill.tt was not covered by the earlier "Switch Vue module templates to ESM bundles" change - rspack now builds ill as an ESM bundle (ill.esm.js) only; the legacy ill.js is no longer produced, so ill.tt's old Asset.js("js/vue/dist/ill.js") include 404s on this branch - Load islands.esm.js and ill.esm.js as type="module" nonced script tags, matching erm/preservation/acquisitions/sip2 and enabling plugin widget discovery on the ILL dashboard To test: - yarn js:build, verify ill.esm.js is produced - Load /cgi-bin/koha/ill/ill.pl - View source; confirm islands.esm.js and ill.esm.js load via <script src="..." type="module" nonce="..."></script> - Confirm the ILL dashboard renders with no console errors -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #58 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Created attachment 201077 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=201077&action=edit Bug 42189: (QA follow-up) Derive widget module id from dashboard name - ModuleDashboard gained a required "module" prop in this patch set to filter plugin widgets, but bug 37762 had since added a "name" prop (the localStorage key, e.g. "ERM"/"ILL"), making "module" redundant - Drop the "module" prop; derive the filter id from name.toLowerCase() ("ERM" -> "erm"), so callers pass a single prop - ERM/Home.vue no longer passes module="erm"; ILL/Home.vue, which only ever passed name="ILL", no longer trips the now-removed required-prop check and filters widgets correctly - Plugin contract is unchanged: widgets still register with a lowercase module id (e.g. module: "erm"); document that it must match the target dashboard's name lowercased To test: - yarn js:build - Install test-widgetdemo plugin, navigate to ERM home - Verify the plugin widget appears and is reactive - Verify no Vue warnings about a missing "module" prop on ILL home -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 --- Comment #59 from Paul Derscheid <paul.derscheid@lmscloud.de> --- Hi Pedro, regarding 2, it looks that erm.tt is not wrapping main-container.inc so I don't think it's redundant in this case. However I think centralizing this is the right move, but maybe in a follow-up bug? -- You are receiving this mail because: You are watching all bug changes.
https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42189 Bug 42189 depends on bug 42150, which changed state. Bug 42150 Summary: Allow plugins to register Vue islands via registerIsland() https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=42150 What |Removed |Added ---------------------------------------------------------------------------- Status|Needs documenting |RESOLVED Resolution|--- |FIXED -- You are receiving this mail because: You are watching all bug changes.
participants (1)
-
bugzilla-daemon@bugs.koha-community.org