mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[plugins] allow static files for plugins (#7425)
* Add 'clear' option to 'invoke static' * Add functions for copying static files from installed plugins * Collect plugin static files as part of 'invoke static' * Add 'activate' method for PluginConfig * Run as part of `invoke plugins`
This commit is contained in:
parent
66b2976d33
commit
9962d85570
@ -0,0 +1,13 @@
|
||||
"""Management command to collect plugin static files."""
|
||||
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""Collect static files for all installed plugins."""
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
"""Run the management command."""
|
||||
from plugin.staticfiles import collect_plugins_static_files
|
||||
|
||||
collect_plugins_static_files()
|
@ -125,7 +125,7 @@ def canAppAccessDatabase(
|
||||
excluded_commands.append('test')
|
||||
|
||||
if not allow_plugins:
|
||||
excluded_commands.extend(['collectstatic'])
|
||||
excluded_commands.extend(['collectstatic', 'collectplugins'])
|
||||
|
||||
for cmd in excluded_commands:
|
||||
if cmd in sys.argv:
|
||||
|
@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import common.models
|
||||
import InvenTree.models
|
||||
import plugin.staticfiles
|
||||
from plugin import InvenTreePlugin, registry
|
||||
|
||||
|
||||
@ -186,6 +187,20 @@ class PluginConfig(InvenTree.models.MetadataMixin, models.Model):
|
||||
|
||||
return getattr(self.plugin, 'is_package', False)
|
||||
|
||||
def activate(self, active: bool) -> None:
|
||||
"""Set the 'active' status of this plugin instance."""
|
||||
from InvenTree.tasks import check_for_migrations, offload_task
|
||||
|
||||
if self.active == active:
|
||||
return
|
||||
|
||||
self.active = active
|
||||
self.save()
|
||||
|
||||
if active:
|
||||
offload_task(check_for_migrations)
|
||||
offload_task(plugin.staticfiles.copy_plugin_static_files, self.key)
|
||||
|
||||
|
||||
class PluginSetting(common.models.BaseInvenTreeSetting):
|
||||
"""This model represents settings for individual plugins."""
|
||||
|
@ -208,15 +208,7 @@ class PluginActivateSerializer(serializers.Serializer):
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
"""Apply the new 'active' value to the plugin instance."""
|
||||
from InvenTree.tasks import check_for_migrations, offload_task
|
||||
|
||||
instance.active = validated_data.get('active', True)
|
||||
instance.save()
|
||||
|
||||
if instance.active:
|
||||
# A plugin has just been activated - check for database migrations
|
||||
offload_task(check_for_migrations)
|
||||
|
||||
instance.activate(validated_data.get('active', True))
|
||||
return instance
|
||||
|
||||
|
||||
|
92
src/backend/InvenTree/plugin/staticfiles.py
Normal file
92
src/backend/InvenTree/plugin/staticfiles.py
Normal file
@ -0,0 +1,92 @@
|
||||
"""Static files management for InvenTree plugins."""
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
|
||||
from plugin.registry import registry
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
def clear_static_dir(path, recursive=True):
|
||||
"""Clear the specified directory from the 'static' output directory.
|
||||
|
||||
Arguments:
|
||||
path: The path to the directory to clear
|
||||
recursive: If True, clear the directory recursively
|
||||
"""
|
||||
if not staticfiles_storage.exists(path):
|
||||
return
|
||||
|
||||
dirs, files = staticfiles_storage.listdir(path)
|
||||
|
||||
for f in files:
|
||||
staticfiles_storage.delete(f'{path}/{f}')
|
||||
|
||||
if recursive:
|
||||
for d in dirs:
|
||||
clear_static_dir(f'{path}/{d}', recursive=True)
|
||||
staticfiles_storage.delete(d)
|
||||
|
||||
|
||||
def collect_plugins_static_files():
|
||||
"""Copy static files from all installed plugins into the static directory."""
|
||||
registry.check_reload()
|
||||
|
||||
logger.info('Collecting static files for all installed plugins.')
|
||||
|
||||
for slug in registry.plugins.keys():
|
||||
copy_plugin_static_files(slug)
|
||||
|
||||
|
||||
def copy_plugin_static_files(slug):
|
||||
"""Copy static files for the specified plugin."""
|
||||
registry.check_reload()
|
||||
|
||||
plugin = registry.get_plugin(slug)
|
||||
|
||||
if not plugin:
|
||||
return
|
||||
|
||||
logger.info("Copying static files for plugin '%s'")
|
||||
|
||||
# Get the source path for the plugin
|
||||
source_path = plugin.path().joinpath('static')
|
||||
|
||||
if not source_path.is_dir():
|
||||
return
|
||||
|
||||
# Create prefix for the destination path
|
||||
destination_prefix = f'plugins/{slug}/'
|
||||
|
||||
# Clear the destination path
|
||||
clear_static_dir(destination_prefix)
|
||||
|
||||
items = list(source_path.glob('*'))
|
||||
|
||||
idx = 0
|
||||
copied = 0
|
||||
|
||||
while idx < len(items):
|
||||
item = items[idx]
|
||||
|
||||
idx += 1
|
||||
|
||||
if item.is_dir():
|
||||
items.extend(item.glob('*'))
|
||||
continue
|
||||
|
||||
if item.is_file():
|
||||
relative_path = item.relative_to(source_path)
|
||||
|
||||
destination_path = f'{destination_prefix}{relative_path}'
|
||||
|
||||
with item.open('rb') as src:
|
||||
staticfiles_storage.save(destination_path, src)
|
||||
|
||||
logger.debug(f'- copied {item} to {destination_path}')
|
||||
copied += 1
|
||||
|
||||
logger.info(f"Copied %s static files for plugin '%s'.", copied, slug)
|
18
tasks.py
18
tasks.py
@ -227,6 +227,9 @@ def plugins(c, uv=False):
|
||||
c.run('pip3 install --no-cache-dir --disable-pip-version-check uv')
|
||||
c.run(f"uv pip install -r '{plugin_file}'")
|
||||
|
||||
# Collect plugin static files
|
||||
manage(c, 'collectplugins')
|
||||
|
||||
|
||||
@task(help={'uv': 'Use UV package manager (experimental)'})
|
||||
def install(c, uv=False):
|
||||
@ -317,8 +320,8 @@ def remove_mfa(c, mail=''):
|
||||
manage(c, f'remove_mfa {mail}')
|
||||
|
||||
|
||||
@task(help={'frontend': 'Build the frontend'})
|
||||
def static(c, frontend=False):
|
||||
@task(help={'frontend': 'Build the frontend', 'clear': 'Remove existing static files'})
|
||||
def static(c, frontend=False, clear=True):
|
||||
"""Copies required static files to the STATIC_ROOT directory, as per Django requirements."""
|
||||
manage(c, 'prerender')
|
||||
|
||||
@ -327,7 +330,16 @@ def static(c, frontend=False):
|
||||
frontend_build(c)
|
||||
|
||||
print('Collecting static files...')
|
||||
manage(c, 'collectstatic --no-input --clear --verbosity 0')
|
||||
|
||||
cmd = 'collectstatic --no-input --verbosity 0'
|
||||
|
||||
if clear:
|
||||
cmd += ' --clear'
|
||||
|
||||
manage(c, cmd)
|
||||
|
||||
# Collect plugin static files
|
||||
manage(c, 'collectplugins')
|
||||
|
||||
|
||||
@task
|
||||
|
Loading…
Reference in New Issue
Block a user