Plugin missing fix (#5653)

* Add 'is_installed' property to PluginConfig model

- Allow us to show users which plugins are "outdated"

* Cleanup plugin table

- Display clearly if a plugin is no longer installed

* Fixes for plugin table

* Revert change due to failing CI
This commit is contained in:
Oliver 2023-10-03 19:44:10 +11:00 committed by GitHub
parent 88314da7b3
commit 78905a45c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 24 deletions

View File

@ -83,6 +83,18 @@ class PluginList(ListAPI):
queryset = queryset.filter(pk__in=matches) queryset = queryset.filter(pk__in=matches)
# Filter queryset by 'installed' flag
if 'installed' in params:
installed = str2bool(params['installed'])
matches = []
for result in queryset:
if result.is_installed() == installed:
matches.append(result.pk)
queryset = queryset.filter(pk__in=matches)
return queryset return queryset
filter_backends = SEARCH_ORDER_FILTER filter_backends = SEARCH_ORDER_FILTER

View File

@ -104,9 +104,9 @@ class PluginConfig(InvenTree.models.MetadataMixin, models.Model):
self.plugin: InvenTreePlugin = plugin self.plugin: InvenTreePlugin = plugin
def __getstate__(self): def __getstate__(self):
"""Customize pickeling behaviour.""" """Customize pickling behavior."""
state = super().__getstate__() state = super().__getstate__()
state.pop("plugin", None) # plugin cannot be pickelt in some circumstances when used with drf views, remove it (#5408) state.pop("plugin", None) # plugin cannot be pickled in some circumstances when used with drf views, remove it (#5408)
return state return state
def save(self, force_insert=False, force_update=False, *args, **kwargs): def save(self, force_insert=False, force_update=False, *args, **kwargs):
@ -120,14 +120,23 @@ class PluginConfig(InvenTree.models.MetadataMixin, models.Model):
self.active = True self.active = True
if not reload: if not reload:
if (self.active is False and self.__org_active is True) or \ if self.active != self.__org_active:
(self.active is True and self.__org_active is False):
if settings.PLUGIN_TESTING: if settings.PLUGIN_TESTING:
warnings.warn('A reload was triggered', stacklevel=2) warnings.warn('A reload was triggered', stacklevel=2)
registry.reload_plugins() registry.reload_plugins()
return ret return ret
@admin.display(boolean=True, description=_('Installed'))
def is_installed(self) -> bool:
"""Simple check to determine if this plugin is installed.
A plugin might not be installed if it has been removed from the system,
but the PluginConfig associated with it still exists.
"""
return self.plugin is not None
@admin.display(boolean=True, description=_('Sample plugin')) @admin.display(boolean=True, description=_('Sample plugin'))
def is_sample(self) -> bool: def is_sample(self) -> bool:
"""Is this plugin a sample app?""" """Is this plugin a sample app?"""

View File

@ -56,12 +56,14 @@ class PluginConfigSerializer(serializers.ModelSerializer):
'mixins', 'mixins',
'is_builtin', 'is_builtin',
'is_sample', 'is_sample',
'is_installed',
] ]
read_only_fields = [ read_only_fields = [
'key', 'key',
'is_builtin', 'is_builtin',
'is_sample', 'is_sample',
'is_installed',
] ]
meta = serializers.DictField(read_only=True) meta = serializers.DictField(read_only=True)

View File

@ -45,34 +45,24 @@ function loadPluginTable(table, options={}) {
return '{% trans "No plugins found" %}'; return '{% trans "No plugins found" %}';
}, },
columns: [ columns: [
{
field: 'active',
title: '',
sortable: true,
formatter: function(value, row) {
if (row.active) {
return `<span class='fa fa-check-circle icon-green' title='{% trans "This plugin is active" %}'></span>`;
} else {
return `<span class='fa fa-times-circle icon-red' title ='{% trans "This plugin is not active" %}'></span>`;
}
}
},
{ {
field: 'name', field: 'name',
title: '{% trans "Plugin Description" %}', title: '{% trans "Plugin" %}',
sortable: true, sortable: true,
switchable: false,
formatter: function(value, row) { formatter: function(value, row) {
let html = ''; let html = '';
if (row.active) { if (!row.is_installed) {
html += `<strong>${value}</strong>`; html += `<span class='fa fa-question-circle' title='{% trans "This plugin is no longer installed" %}'></span>`;
if (row.meta && row.meta.description) { } else if (row.active) {
html += ` - <small>${row.meta.description}</small>`; html += `<span class='fa fa-check-circle icon-green' title='{% trans "This plugin is active" %}'></span>`;
}
} else { } else {
html += `<em>${value}</em>`; html += `<span class='fa fa-times-circle icon-red' title ='{% trans "This plugin is installed but not active" %}'></span>`;
} }
html += `&nbsp;<span>${value}</span>`;
if (row.is_builtin) { if (row.is_builtin) {
html += `<span class='badge bg-success rounded-pill badge-right'>{% trans "Builtin" %}</span>`; html += `<span class='badge bg-success rounded-pill badge-right'>{% trans "Builtin" %}</span>`;
} }
@ -84,6 +74,12 @@ function loadPluginTable(table, options={}) {
return html; return html;
} }
}, },
{
field: 'meta.description',
title: '{% trans "Description" %}',
sortable: false,
switchable: true,
},
{ {
field: 'meta.version', field: 'meta.version',
title: '{% trans "Version" %}', title: '{% trans "Version" %}',
@ -104,15 +100,18 @@ function loadPluginTable(table, options={}) {
{ {
field: 'meta.author', field: 'meta.author',
title: '{% trans "Author" %}', title: '{% trans "Author" %}',
sortable: false,
}, },
{ {
field: 'actions', field: 'actions',
title: '', title: '',
switchable: false,
sortable: false,
formatter: function(value, row) { formatter: function(value, row) {
let buttons = ''; let buttons = '';
// Check if custom plugins are enabled for this instance // Check if custom plugins are enabled for this instance
if (options.custom && !row.is_builtin) { if (options.custom && !row.is_builtin && row.is_installed) {
if (row.active) { if (row.active) {
buttons += makeIconButton('fa-stop-circle icon-red', 'btn-plugin-disable', row.pk, '{% trans "Disable Plugin" %}'); buttons += makeIconButton('fa-stop-circle icon-red', 'btn-plugin-disable', row.pk, '{% trans "Disable Plugin" %}');
} else { } else {

View File

@ -471,6 +471,10 @@ function getPluginTableFilters() {
type: 'bool', type: 'bool',
title: '{% trans "Sample" %}', title: '{% trans "Sample" %}',
}, },
installed: {
type: 'bool',
title: '{% trans "Installed" %}'
},
}; };
} }