2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 03:26:45 +00:00
Oliver 5e7e258289
[Plugin] Plugin context (#9439)
* Pass more stuff to window

* Expose form functions to plugin context

* Breaking: Render plugin component in context tree

- Required due to createRoot function
- Adds necessary context providers

* Fix context

* Provide MantineThemeContext

* Bundle mantine/core

* Hack for useNavigate within ApiForm

- Errors out if called within plugin context
- Workaround to catch the error

* Update build cmd

* Define config for building "Library" mode

* Update package.json

* Add basic index file

* Factor out ApiEndpoints

* factor out ModelType

* Factor out role enums

* Further refactoring

* More refactoring

* Cleanup

* Expose apiUrl function

* Add instance data to plugin context type def

* Tweaks for loading plugin components

- LanguageContext must be on the inside

* Tweak StylishText

* Externalize notifications system

* Update lingui config

* Add functions for checking plugin interface version

* Extract package version at build time

* Enhance version checking

* Revert variable name change

* Public package

* Add README.md

* adjust packge name

* Adjust name to include org

* Update project files

* Add basic changelog info

* Refactoring to expose URL functions

* Refactor navigation functions

* Update package and README

* Improve navigateToLink function

* Refactor stylish text

- Move into ./lib
- Do not require user state

* Revert changes

- StylishText throws error in plugin
- Low priority, can work out later

* expose function to refresh page index

* Provide RemoteComponent with a method to reload itself

* Bump version

* Cleanup tests

* Prevent duplicate --emptyOutDir arg

* Tweak playwright tests

* Expose role and permission enums

* Fix imports

* Updated docs

* Fix spelling, typos, etc

* Include more package version information

* Expose more version context

* Cleanup

* Probably don't need hooks

* Fix links

* Docs updates

* Fix links
2025-04-16 00:30:34 +10:00

174 lines
4.5 KiB
TypeScript

import { t } from '@lingui/core/macro';
import {
Alert,
Button,
Divider,
Drawer,
Group,
Loader,
LoadingOverlay,
Paper,
Space,
Stack,
Stepper,
Text
} from '@mantine/core';
import { IconCheck } from '@tabler/icons-react';
import { type ReactNode, useMemo } from 'react';
import { ModelType } from '@lib/enums/ModelType';
import { useImportSession } from '../../hooks/UseImportSession';
import useStatusCodes from '../../hooks/UseStatusCodes';
import { StylishText } from '../items/StylishText';
import ImporterDataSelector from './ImportDataSelector';
import ImporterColumnSelector from './ImporterColumnSelector';
import ImporterImportProgress from './ImporterImportProgress';
/*
* Stepper component showing the current step of the data import process.
*/
function ImportDrawerStepper({
currentStep
}: Readonly<{ currentStep: number }>) {
/* TODO: Enhance this with:
* - Custom icons
* - Loading indicators for "background" states
*/
return (
<Stepper
active={currentStep}
onStepClick={undefined}
allowNextStepsSelect={false}
iconSize={20}
size='xs'
>
<Stepper.Step label={t`Upload File`} />
<Stepper.Step label={t`Map Columns`} />
<Stepper.Step label={t`Import Data`} />
<Stepper.Step label={t`Process Data`} />
<Stepper.Step label={t`Complete Import`} />
</Stepper>
);
}
export default function ImporterDrawer({
sessionId,
opened,
onClose
}: Readonly<{
sessionId: number;
opened: boolean;
onClose: () => void;
}>) {
const session = useImportSession({ sessionId: sessionId });
const importSessionStatus = useStatusCodes({
modelType: ModelType.importsession
});
// Map from import steps to stepper steps
const currentStep = useMemo(() => {
switch (session.status) {
case importSessionStatus.INITIAL:
return 0;
case importSessionStatus.MAPPING:
return 1;
case importSessionStatus.IMPORTING:
return 2;
case importSessionStatus.PROCESSING:
return 3;
case importSessionStatus.COMPLETE:
return 4;
default:
return 0;
}
}, [session.status]);
const widget = useMemo(() => {
if (session.sessionQuery.isLoading || session.sessionQuery.isFetching) {
return <Loader />;
}
switch (session.status) {
case importSessionStatus.INITIAL:
return <Text>Initial : TODO</Text>;
case importSessionStatus.MAPPING:
return <ImporterColumnSelector session={session} />;
case importSessionStatus.IMPORTING:
return <ImporterImportProgress session={session} />;
case importSessionStatus.PROCESSING:
return <ImporterDataSelector session={session} />;
case importSessionStatus.COMPLETE:
return (
<Stack gap='xs'>
<Alert
color='green'
title={t`Import Complete`}
icon={<IconCheck />}
>
{t`Data has been imported successfully`}
</Alert>
<Button color='blue' onClick={onClose}>{t`Close`}</Button>
</Stack>
);
default:
return (
<Stack gap='xs'>
<Alert color='red' title={t`Unknown Status`} icon={<IconCheck />}>
{t`Import session has unknown status`}: {session.status}
</Alert>
<Button color='red' onClick={onClose}>{t`Close`}</Button>
</Stack>
);
}
}, [session.status, session.sessionQuery]);
const title: ReactNode = useMemo(() => {
return (
<Stack gap='xs' style={{ width: '100%' }}>
<Group
gap='xs'
wrap='nowrap'
justify='space-apart'
grow
preventGrowOverflow={false}
>
<StylishText size='lg'>
{session.sessionData?.statusText ?? t`Importing Data`}
</StylishText>
<ImportDrawerStepper currentStep={currentStep} />
<Space />
</Group>
<Divider />
</Stack>
);
}, [session.sessionData]);
return (
<Drawer
position='bottom'
size='80%'
title={title}
opened={opened}
onClose={onClose}
withCloseButton={true}
closeOnEscape={false}
closeOnClickOutside={false}
styles={{
header: {
width: '100%'
},
title: {
width: '100%'
}
}}
>
<Stack gap='xs'>
<LoadingOverlay visible={session.sessionQuery.isFetching} />
<Paper p='md'>{session.sessionQuery.isFetching || widget}</Paper>
</Stack>
</Drawer>
);
}