2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Plugin helper function (#8220)

* Add helper function for constructing URL to static file

* Fix PluginListTable

- Allow uninstallation of plugin
- Allow deletion of plugin config

* Move helper method to InvenTreePlugin class

* Bump API version info
This commit is contained in:
Oliver 2024-09-30 23:39:38 +10:00 committed by GitHub
parent cbe4569416
commit e9640f4f15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 17 deletions

View File

@ -1,14 +1,17 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 261
INVENTREE_API_VERSION = 262
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
261 - 2024-09;26 : https://github.com/inventree/InvenTree/pull/8184
262 - 2024-09-30 : https://github.com/inventree/InvenTree/pull/8220
- Tweak permission requirements for uninstalling plugins via API
261 - 2024-09-26 : https://github.com/inventree/InvenTree/pull/8184
- Fixes for BuildOrder API serializers
v260 - 2024-09-26 : https://github.com/inventree/InvenTree/pull/8190

View File

@ -21,11 +21,11 @@ from InvenTree.filters import SEARCH_ORDER_FILTER
from InvenTree.mixins import (
CreateAPI,
ListAPI,
RetrieveDestroyAPI,
RetrieveUpdateAPI,
RetrieveUpdateDestroyAPI,
UpdateAPI,
)
from InvenTree.permissions import IsSuperuser
from InvenTree.permissions import IsSuperuser, IsSuperuserOrReadOnly
from plugin import registry
from plugin.base.action.api import ActionPluginView
from plugin.base.barcodes.api import barcode_api_urls
@ -143,7 +143,7 @@ class PluginList(ListAPI):
search_fields = ['key', 'name']
class PluginDetail(RetrieveUpdateDestroyAPI):
class PluginDetail(RetrieveDestroyAPI):
"""API detail endpoint for PluginConfig object.
get:
@ -158,6 +158,7 @@ class PluginDetail(RetrieveUpdateDestroyAPI):
queryset = PluginConfig.objects.all()
serializer_class = PluginSerializers.PluginConfigSerializer
permission_classes = [IsSuperuserOrReadOnly]
lookup_field = 'key'
lookup_url_kwarg = 'plugin'

View File

@ -438,3 +438,11 @@ class InvenTreePlugin(VersionMixin, MixinBase, MetaBase):
self.package = package
# endregion
def plugin_static_file(self, *args):
"""Construct a path to a static file within the plugin directory."""
import os
from django.conf import settings
return '/' + os.path.join(settings.STATIC_URL, 'plugins', self.SLUG, *args)

View File

@ -17,7 +17,8 @@ import {
IconHelpCircle,
IconInfoCircle,
IconPlaylistAdd,
IconRefresh
IconRefresh,
IconTrash
} from '@tabler/icons-react';
import { useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
@ -352,9 +353,10 @@ export default function PluginListTable() {
{
hidden:
record.is_builtin != false ||
record.is_installed != true ||
!record.is_installed ||
record.active != false,
title: t`Activate`,
tooltip: t`Activate selected plugin`,
color: 'green',
icon: <IconCircleCheck />,
onClick: () => {
@ -364,11 +366,9 @@ export default function PluginListTable() {
}
},
{
hidden:
record.active != true ||
record.is_package != true ||
!record.package_name,
hidden: !record.active || !record.is_package || !record.package_name,
title: t`Update`,
tooltip: t`Update selected plugin`,
color: 'blue',
icon: <IconRefresh />,
onClick: () => {
@ -377,10 +377,37 @@ export default function PluginListTable() {
}
},
{
hidden: record.is_installed != false,
title: t`Delete`,
// Uninstall an installed plugin
// Must be inactive, not a builtin, not a sample, and installed as a package
hidden:
!user.isSuperuser() ||
record.active ||
record.is_builtin ||
record.is_sample ||
!record.is_installed ||
!record.is_package,
title: t`Uninstall`,
tooltip: t`Uninstall selected plugin`,
color: 'red',
icon: <IconCircleX />,
onClick: () => {
setSelectedPlugin(record.key);
uninstallPluginModal.open();
}
},
{
// Delete a plugin configuration
// Must be inactive, not a builtin, not a sample, and not installed (i.e. no matching plugin)
hidden:
record.active ||
record.is_builtin ||
record.is_sample ||
record.is_installed ||
!user.isSuperuser(),
title: t`Delete`,
tooltip: t`Delete selected plugin configuration`,
color: 'red',
icon: <IconTrash />,
onClick: () => {
setSelectedPlugin(record.key);
deletePluginModal.open();
@ -436,7 +463,7 @@ export default function PluginListTable() {
const uninstallPluginModal = useEditApiFormModal({
title: t`Uninstall Plugin`,
url: ApiEndpoints.plugin_uninstall,
// pathParams: { key: selectedPlugin },
pathParams: { key: selectedPlugin },
fetchInitialData: false,
timeout: 30000,
fields: {
@ -460,15 +487,14 @@ export default function PluginListTable() {
const deletePluginModal = useDeleteApiFormModal({
url: ApiEndpoints.plugin_list,
pathParams: { key: selectedPlugin },
pk: selectedPlugin,
fetchInitialData: false,
title: t`Delete Plugin`,
preFormWarning: t`Deleting this plugin configuration will remove all associated settings and data. Are you sure you want to delete this plugin?`,
table: table
});
const reloadPlugins = useCallback(() => {
console.log('reloadPlugins:');
api
.post(apiUrl(ApiEndpoints.plugin_reload), {
full_reload: true,