mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add some dummy data for the plugin panels
This commit is contained in:
parent
15ebbb6f04
commit
299839312f
@ -424,8 +424,33 @@ class PluginPanelList(APIView):
|
||||
|
||||
# Extract all plugins from the registry which provide custom panels
|
||||
for _plugin in registry.with_mixin('panel', active=True):
|
||||
# TODO: Allow plugins to fill this data out
|
||||
...
|
||||
|
||||
panels = [
|
||||
{
|
||||
'plugin': 'myplugin',
|
||||
'name': 'test-plugin',
|
||||
'label': 'My Plugin',
|
||||
'icon': 'part',
|
||||
'content': '<div>hello world</div>',
|
||||
},
|
||||
{
|
||||
'plugin': 'myplugin',
|
||||
'name': 'test-plugin-2',
|
||||
'label': 'My Plugin 2',
|
||||
'icon': 'email',
|
||||
'content': '<div>hello world 2</div>',
|
||||
},
|
||||
{
|
||||
'plugin': 'myplugin',
|
||||
'name': 'test-plugin-3',
|
||||
'label': 'My Plugin 3',
|
||||
'icon': 'website',
|
||||
'content': '<div>hello world 3</div>',
|
||||
},
|
||||
]
|
||||
|
||||
return Response(PluginSerializers.PluginPanelSerializer(panels, many=True).data)
|
||||
|
||||
|
||||
@ -437,7 +462,7 @@ plugin_api_urls = [
|
||||
'plugins/',
|
||||
include([
|
||||
path(
|
||||
'panel/',
|
||||
'panels/',
|
||||
include([
|
||||
path('', PluginPanelList.as_view(), name='api-plugin-panel-list')
|
||||
]),
|
||||
|
@ -311,9 +311,10 @@ class PluginPanelSerializer(serializers.Serializer):
|
||||
class Meta:
|
||||
"""Meta for serializer."""
|
||||
|
||||
fields = ['plugin', 'title', 'description', 'icon']
|
||||
fields = ['plugin', 'name', 'label', 'icon']
|
||||
|
||||
plugin = serializers.CharField(label=_('Plugin Key'))
|
||||
title = serializers.CharField(label=_('Panel Title'))
|
||||
description = serializers.CharField(label=_('Panel Description'))
|
||||
name = serializers.CharField(label=_('Panel Name'))
|
||||
label = serializers.CharField(label=_('Panel Label'))
|
||||
icon = serializers.CharField(label=_('Panel Icon'))
|
||||
content = serializers.CharField(label=_('Panel Content'))
|
||||
|
@ -144,6 +144,7 @@ export enum ApiEndpoints {
|
||||
plugin_reload = 'plugins/reload/',
|
||||
plugin_activate = 'plugins/:key/activate/',
|
||||
plugin_uninstall = 'plugins/:key/uninstall/',
|
||||
plugin_panel_list = 'plugins/panels/',
|
||||
|
||||
// Machine API endpoints
|
||||
machine_types_list = 'machine/types/',
|
||||
|
@ -50,6 +50,7 @@ import {
|
||||
IconPaperclip,
|
||||
IconPhone,
|
||||
IconPhoto,
|
||||
IconPlug,
|
||||
IconPoint,
|
||||
IconPrinter,
|
||||
IconProgressCheck,
|
||||
@ -199,7 +200,8 @@ const icons = {
|
||||
destination: IconFlag,
|
||||
repeat_destination: IconFlagShare,
|
||||
unlink: IconUnlink,
|
||||
success: IconCircleCheck
|
||||
success: IconCircleCheck,
|
||||
plugin: IconPlug
|
||||
};
|
||||
|
||||
export type InvenTreeIconType = keyof typeof icons;
|
||||
|
@ -1,58 +1,70 @@
|
||||
import { t } from '@lingui/macro';
|
||||
import { Alert, Text } from '@mantine/core';
|
||||
import { useTimeout } from '@mantine/hooks';
|
||||
import { Icon24Hours } from '@tabler/icons-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { ReactNode, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { api } from '../App';
|
||||
import { PanelType } from '../components/nav/Panel';
|
||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||
import { identifierString } from '../functions/conversion';
|
||||
import { InvenTreeIcon } from '../functions/icons';
|
||||
import { apiUrl } from '../states/ApiState';
|
||||
|
||||
export interface PluginPanelState extends PanelType {
|
||||
pluginKey: string;
|
||||
targetType: string;
|
||||
targetId?: string | number | null;
|
||||
export type PluginPanelState = {
|
||||
panels: PanelType[];
|
||||
};
|
||||
|
||||
// Placeholder content for a panel with no content
|
||||
function PanelNoContent() {
|
||||
return (
|
||||
<Alert color="red" title={t`No Content`}>
|
||||
<Text>{t`No content provided for this plugin`}</Text>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export function usePluginPanel({
|
||||
pluginKey,
|
||||
panelName,
|
||||
export function usePluginPanels({
|
||||
targetModel,
|
||||
targetId
|
||||
}: {
|
||||
pluginKey: string;
|
||||
panelName: string;
|
||||
targetModel: string;
|
||||
targetId?: string | number | null;
|
||||
}): PluginPanelState {
|
||||
// TODO: Query to fetch the "content" for the plugin
|
||||
const { isFetching, data } = useQuery({
|
||||
queryKey: [targetModel, targetId],
|
||||
queryFn: () => {
|
||||
return api
|
||||
.get(apiUrl(ApiEndpoints.plugin_panel_list), {
|
||||
params: {
|
||||
target_model: targetModel,
|
||||
target_id: targetId
|
||||
}
|
||||
})
|
||||
.then((response: any) => response.data)
|
||||
.catch((error: any) => {
|
||||
console.error('Failed to fetch plugin panels:', error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const [loaded, setLoaded] = useState<boolean>(false);
|
||||
|
||||
const { start } = useTimeout(() => setLoaded(true), 5000);
|
||||
|
||||
useEffect(() => {
|
||||
start();
|
||||
console.log('starting timer!');
|
||||
}, []);
|
||||
|
||||
const content = useMemo(() => {
|
||||
return loaded ? (
|
||||
'plugin content loaded!'
|
||||
) : (
|
||||
<div>
|
||||
<p>Plugin content goes here...</p>
|
||||
<p>Plugin Key: {pluginKey}</p>
|
||||
<p>Panel Name: {panelName}</p>
|
||||
<p>Target Model: {targetModel}</p>
|
||||
<p>Target ID: {targetId}</p>
|
||||
</div>
|
||||
const panels: PanelType[] = useMemo(() => {
|
||||
return (
|
||||
data?.map((panel: any) => {
|
||||
const pluginKey = panel.plugin || 'plugin';
|
||||
return {
|
||||
name: identifierString(`${pluginKey}-${panel.name}`),
|
||||
label: panel.label || t`Plugin Panel`,
|
||||
icon: <InvenTreeIcon icon={panel.icon ?? 'plugin'} />,
|
||||
content: panel.content || <PanelNoContent />
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
}, [loaded, pluginKey, panelName, targetModel, targetId]);
|
||||
}, [data]);
|
||||
|
||||
return {
|
||||
content: content,
|
||||
name: panelName,
|
||||
pluginKey: pluginKey,
|
||||
targetType: targetModel,
|
||||
targetId: targetId,
|
||||
label: 'A plugin panel',
|
||||
icon: <Icon24Hours />
|
||||
panels: panels
|
||||
};
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ import {
|
||||
import { PlaceholderPanel } from '../../components/items/Placeholder';
|
||||
import NavigationTree from '../../components/nav/NavigationTree';
|
||||
import { PageDetail } from '../../components/nav/PageDetail';
|
||||
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
|
||||
import { PanelType } from '../../components/nav/Panel';
|
||||
import { PanelGroup } from '../../components/nav/PanelGroup';
|
||||
import { formatPriceRange } from '../../defaults/formatters';
|
||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
import { ModelType } from '../../enums/ModelType';
|
||||
@ -75,6 +76,7 @@ import {
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { useInstance } from '../../hooks/UseInstance';
|
||||
import { usePluginPanels } from '../../hooks/UsePluginPanels';
|
||||
import { apiUrl } from '../../states/ApiState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { BomTable } from '../../tables/bom/BomTable';
|
||||
@ -640,6 +642,15 @@ export default function PartDetail() {
|
||||
];
|
||||
}, [id, part, user]);
|
||||
|
||||
const pluginPanels = usePluginPanels({
|
||||
targetModel: ModelType.part,
|
||||
targetId: id
|
||||
});
|
||||
|
||||
const panels: PanelType[] = useMemo(() => {
|
||||
return [...partPanels, ...pluginPanels.panels];
|
||||
}, [partPanels, pluginPanels]);
|
||||
|
||||
const breadcrumbs = useMemo(
|
||||
() => [
|
||||
{ name: t`Parts`, url: '/part' },
|
||||
@ -844,7 +855,7 @@ export default function PartDetail() {
|
||||
}}
|
||||
actions={partActions}
|
||||
/>
|
||||
<PanelGroup pageKey="part" panels={partPanels} />
|
||||
<PanelGroup pageKey="part" panels={panels} />
|
||||
{transferStockItems.modal}
|
||||
{countStockItems.modal}
|
||||
</Stack>
|
||||
|
Loading…
Reference in New Issue
Block a user