mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-17 12:35:46 +00:00
Adds <PluginPanel> component for handling panel render
This commit is contained in:
93
src/frontend/src/components/plugins/PluginPanel.tsx
Normal file
93
src/frontend/src/components/plugins/PluginPanel.tsx
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { Alert, Text } from '@mantine/core';
|
||||||
|
import { AxiosInstance } from 'axios';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import { api } from '../../App';
|
||||||
|
import { ModelType } from '../../enums/ModelType';
|
||||||
|
import { PanelType } from '../nav/Panel';
|
||||||
|
|
||||||
|
interface PluginPanelProps extends PanelType {
|
||||||
|
src?: string;
|
||||||
|
params?: any;
|
||||||
|
targetModel?: ModelType | string;
|
||||||
|
targetId?: string | number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definition of what we pass into a plugin panel
|
||||||
|
*/
|
||||||
|
interface PluginPanelParameters {
|
||||||
|
target: HTMLDivElement;
|
||||||
|
props: PluginPanelProps;
|
||||||
|
targetModel?: ModelType | string;
|
||||||
|
targetId?: number;
|
||||||
|
api: AxiosInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Provide more context information to the plugin renderer:
|
||||||
|
*
|
||||||
|
* - api instance
|
||||||
|
* - custom context data from server
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom panel which can be used to display plugin content.
|
||||||
|
*
|
||||||
|
* - Content is loaded dynamically (via the API) when a page is first loaded
|
||||||
|
* - Content can be provided from an external javascript module, or with raw HTML
|
||||||
|
*
|
||||||
|
* If content is provided from an external source, it is expected to define a function `render_panel` which will render the content.
|
||||||
|
* const render_panel = (element: HTMLElement, params: any) => {...}
|
||||||
|
*
|
||||||
|
* Where:
|
||||||
|
* - `element` is the HTML element to render the content into
|
||||||
|
* - `params` is the set of run-time parameters to pass to the content rendering function
|
||||||
|
*/
|
||||||
|
export default function PluginPanel({ props }: { props: PluginPanelProps }) {
|
||||||
|
const ref = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const loadExternalSource = async () => {
|
||||||
|
// Load content from external source
|
||||||
|
const src = await import(/* @vite-ignore */ props.src ?? '');
|
||||||
|
|
||||||
|
// We expect the external source to define a function which will render the content
|
||||||
|
if (src && src.render_panel && typeof src.render_panel === 'function') {
|
||||||
|
src.render_panel({
|
||||||
|
target: ref.current,
|
||||||
|
props: props,
|
||||||
|
api: api,
|
||||||
|
targetModel: props.targetModel,
|
||||||
|
targetId: props.targetId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.src) {
|
||||||
|
// Load content from external source
|
||||||
|
loadExternalSource();
|
||||||
|
} else if (props.content) {
|
||||||
|
// If content is provided directly, render it into the panel
|
||||||
|
// ref.current.innerHTML = props.content;
|
||||||
|
} else {
|
||||||
|
// Something... went wrong?
|
||||||
|
}
|
||||||
|
}, [props]);
|
||||||
|
|
||||||
|
if (!props.content && !props.src) {
|
||||||
|
return <PanelNoContent />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div ref={ref as any}>{props.content}</div>;
|
||||||
|
}
|
@ -5,6 +5,7 @@ import { useMemo } from 'react';
|
|||||||
|
|
||||||
import { api } from '../App';
|
import { api } from '../App';
|
||||||
import { PanelType } from '../components/nav/Panel';
|
import { PanelType } from '../components/nav/Panel';
|
||||||
|
import PluginPanel from '../components/plugins/PluginPanel';
|
||||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||||
import { ModelType } from '../enums/ModelType';
|
import { ModelType } from '../enums/ModelType';
|
||||||
import { identifierString } from '../functions/conversion';
|
import { identifierString } from '../functions/conversion';
|
||||||
@ -16,15 +17,6 @@ export type PluginPanelState = {
|
|||||||
panels: PanelType[];
|
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 usePluginPanels({
|
export function usePluginPanels({
|
||||||
targetModel,
|
targetModel,
|
||||||
targetId
|
targetId
|
||||||
@ -39,6 +31,7 @@ export function usePluginPanels({
|
|||||||
[globalSettings]
|
[globalSettings]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// API query to fetch information on available plugin panels
|
||||||
const { isFetching, data } = useQuery({
|
const { isFetching, data } = useQuery({
|
||||||
enabled: pluginPanelsEnabled && !!targetModel,
|
enabled: pluginPanelsEnabled && !!targetModel,
|
||||||
queryKey: [targetModel, targetId],
|
queryKey: [targetModel, targetId],
|
||||||
@ -70,7 +63,7 @@ export function usePluginPanels({
|
|||||||
name: identifierString(`${pluginKey}-${panel.name}`),
|
name: identifierString(`${pluginKey}-${panel.name}`),
|
||||||
label: panel.label || t`Plugin Panel`,
|
label: panel.label || t`Plugin Panel`,
|
||||||
icon: <InvenTreeIcon icon={panel.icon ?? 'plugin'} />,
|
icon: <InvenTreeIcon icon={panel.icon ?? 'plugin'} />,
|
||||||
content: panel.content || <PanelNoContent />
|
content: <PluginPanel props={panel} />
|
||||||
};
|
};
|
||||||
}) ?? []
|
}) ?? []
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user