Add some dummy data for the plugin panels

This commit is contained in:
Oliver Walters 2024-06-18 13:12:40 +00:00
parent 15ebbb6f04
commit 299839312f
6 changed files with 97 additions and 45 deletions

View File

@ -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')
]),

View File

@ -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'))

View File

@ -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/',

View File

@ -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;

View File

@ -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
};
}

View File

@ -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>