mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds <PluginPanel> component for handling panel render
This commit is contained in:
parent
a23bfdfc6f
commit
f2153bfb60
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 { PanelType } from '../components/nav/Panel';
|
||||
import PluginPanel from '../components/plugins/PluginPanel';
|
||||
import { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||
import { ModelType } from '../enums/ModelType';
|
||||
import { identifierString } from '../functions/conversion';
|
||||
@ -16,15 +17,6 @@ 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 usePluginPanels({
|
||||
targetModel,
|
||||
targetId
|
||||
@ -39,6 +31,7 @@ export function usePluginPanels({
|
||||
[globalSettings]
|
||||
);
|
||||
|
||||
// API query to fetch information on available plugin panels
|
||||
const { isFetching, data } = useQuery({
|
||||
enabled: pluginPanelsEnabled && !!targetModel,
|
||||
queryKey: [targetModel, targetId],
|
||||
@ -70,7 +63,7 @@ export function usePluginPanels({
|
||||
name: identifierString(`${pluginKey}-${panel.name}`),
|
||||
label: panel.label || t`Plugin Panel`,
|
||||
icon: <InvenTreeIcon icon={panel.icon ?? 'plugin'} />,
|
||||
content: panel.content || <PanelNoContent />
|
||||
content: <PluginPanel props={panel} />
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user