diff --git a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Dashboard.tsx b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Dashboard.tsx index b4d225f..742fe56 100644 --- a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Dashboard.tsx +++ b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Dashboard.tsx @@ -38,7 +38,7 @@ function {{ cookiecutter.plugin_name }}DashboardItem({ // This is the function which is called by InvenTree to render the actual dashboard // component -export function render{{ cookiecutter.plugin_name }}DashboardItem(context: InvenTreePluginContext) { +export function Render{{ cookiecutter.plugin_name }}DashboardItem(context: InvenTreePluginContext) { checkPluginVersion(context); return <{{ cookiecutter.plugin_name }}DashboardItem context={context} />; } diff --git a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Panel.tsx b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Panel.tsx index ab08c70..32815a6 100644 --- a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Panel.tsx +++ b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Panel.tsx @@ -249,7 +249,7 @@ function {{ cookiecutter.plugin_name }}Panel({ } // This is the function which is called by InvenTree to render the actual panel component -export function render{{ cookiecutter.plugin_name }}Panel(context: InvenTreePluginContext) { +export function Render{{ cookiecutter.plugin_name }}Panel(context: InvenTreePluginContext) { checkPluginVersion(context); {% if cookiecutter.frontend.translation -%} diff --git a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Settings.tsx b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Settings.tsx index 4ff70e6..cf74844 100644 --- a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Settings.tsx +++ b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/src/Settings.tsx @@ -27,8 +27,8 @@ function PluginSettingsDisplay({ } -export function renderPluginSettings(context: InvenTreePluginContext) { +export function RenderPluginSettings(context: InvenTreePluginContext) { return ( ); -} \ No newline at end of file +} diff --git a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/vite.dev.config.ts b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/vite.dev.config.ts index 9b7506d..67338aa 100644 --- a/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/vite.dev.config.ts +++ b/plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/vite.dev.config.ts @@ -8,6 +8,42 @@ import react from "@vitejs/plugin-react-swc" import { lingui } from "@lingui/vite-plugin" {%- endif %} +import type { Plugin } from 'vite' + +// Enable HMR support for this plugin by hooking into the InvenTree vite dev server +function inventreeHmrPlugin(): Plugin { + const fileRegex = /\.(js|jsx|ts|tsx)(\?|$)/; + + const hmrBlock = [ + '', + '// __inventree_hmr_injected__', + 'if (import.meta.hot) {', + ' import.meta.hot.accept((newModule) => {', + ' const key = new URL(import.meta.url).origin + new URL(import.meta.url).pathname;', + ' window.__plugin_hmr_callbacks?.[key]?.forEach(callback => {', + ' callback(newModule);', + ' });', + ' })', + '}', + ]; + + return { + name: 'inventree-hmr-plugin', + enforce: 'post', + + transform(code, id) { + if (!fileRegex.test(id)) return; + if (id.includes('node_modules')) return; + if (code.includes('__inventree_hmr_injected__')) return; + + return { + code: code + hmrBlock.join('\n'), + map: null, + } + } + } +} + /** * Vite config to run the frontend plugin in development mode. * @@ -40,10 +76,12 @@ export default defineConfig((cfg) => { {% if cookiecutter.frontend.translation -%} lingui(), react({ - plugins: [["@lingui/swc-plugin", {}]] + plugins: [["@lingui/swc-plugin", {}]], + reactRefreshHost: 'http://localhost:5173', }), {%- endif %} viteExternalsPlugin(externalLibs), + inventreeHmrPlugin(), ]; return config; diff --git a/plugin_creator/template/{{ cookiecutter.plugin_name }}/{{ cookiecutter.package_name }}/core.py b/plugin_creator/template/{{ cookiecutter.plugin_name }}/{{ cookiecutter.package_name }}/core.py index 2b15b3a..d06063f 100644 --- a/plugin_creator/template/{{ cookiecutter.plugin_name }}/{{ cookiecutter.package_name }}/core.py +++ b/plugin_creator/template/{{ cookiecutter.plugin_name }}/{{ cookiecutter.package_name }}/core.py @@ -42,7 +42,7 @@ class {{ cookiecutter.plugin_name }}(InvenTreePlugin): {% if "UserInterfaceMixin" in cookiecutter.plugin_mixins.mixin_list -%} {%- if cookiecutter.frontend.features.settings -%} # Render custom UI elements to the plugin settings page - ADMIN_SOURCE = "Settings.js:renderPluginSettings" + ADMIN_SOURCE = "Settings.js:RenderPluginSettings" {%- endif -%} {%- endif -%} @@ -156,7 +156,7 @@ def get_ui_panels(self, request, context: dict, **kwargs): 'title': '{{ cookiecutter.plugin_title }}', 'description': 'Custom panel description', 'icon': 'ti:mood-smile:outline', - 'source': self.plugin_static_file('Panel.js:render{{ cookiecutter.plugin_name }}Panel'), + 'source': self.plugin_static_file('Panel.js:Render{{ cookiecutter.plugin_name }}Panel'), 'context': { # Provide additional context data to the panel {%- if "SettingsMixin" in cookiecutter.plugin_mixins.mixin_list %} @@ -185,7 +185,7 @@ def get_ui_dashboard_items(self, request, context: dict, **kwargs): 'title': '{{ cookiecutter.plugin_title }} Dashboard Item', 'description': 'Custom dashboard item', 'icon': 'ti:dashboard:outline', - 'source': self.plugin_static_file('Dashboard.js:render{{ cookiecutter.plugin_name }}DashboardItem'), + 'source': self.plugin_static_file('Dashboard.js:Render{{ cookiecutter.plugin_name }}DashboardItem'), 'context': { # Provide additional context data to the dashboard item {%- if "SettingsMixin" in cookiecutter.plugin_mixins.mixin_list %} @@ -207,7 +207,9 @@ def get_ui_spotlight_actions(self, request, context, **kwargs): 'title': 'Hello Action', 'description': 'Hello from {{ cookiecutter.plugin_name }}', 'icon': 'ti:heart-handshake:outline', - 'source': self.plugin_static_file('Spotlight.js:{{ cookiecutter.plugin_name }}SpotlightAction'), + 'source': self.plugin_static_file( + 'Spotlight.js:{{ cookiecutter.plugin_name[0]|upper }}{{ cookiecutter.plugin_name[1:] }}SpotlightAction' + ), } ] {%- endif -%}