2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-16 20:15:44 +00:00
Files
InvenTree/src/frontend/src/hooks/UseDataExport.tsx
Oliver 8d51aa1563 [Feature] Data export plugins (#9096)
* Move data export code out of "importer" directory

* Refactoring to allow data export via plugin

* Add brief docs framework

* Add basic DataExportMixin class

* Pass context data through to the serializer

* Extract custom serializer

* Refactoring

* Add builtin plugin for BomExport

* More refactoring

* Cleanup for UseForm hooks

* Allow GET methods in forms

* Create new 'exporter' app

* Refactor imports

* Run cleanup task on boot

* Add enumeration for plugin mixin types

* Refactor with_mixin call

* Generate export options serializer

* Pass plugin information through

* Offload export functionality to the plugin

* Generate output

* Download generated file

* Refactor frontend code

* Generate params for downloading

* Pass custom fields through to the plugin

* Implement multi-level export for BOM data

* Export supplier and manufacturer information

* Export substitute data

* Remove old BOM exporter

* Export part parameter data

* Try different app order

* Use GET instead of POST request

- Less 'dangerous' - no chance of performing a destructive operation

* Fix for constructing query parameters

- Ignore any undefined values!

* Trying something

* Revert to POST

- Required, other query data are ignored

* Fix spelling mistakes

* Remove SettingsMixin

* Revert python version

* Fix for settings.py

* Fix missing return

* Fix for label mixin code

* Run playwright tests in --host mode

* Fix for choice field

- Prevent empty value if field is required

* Remove debug prints

* Update table header

* Playwright tests for data export

* Rename app from "exporter" to "data_exporter"

* Add frontend table for export sessions

* Updated playwright testing

* Fix for unit test

* Fix build order unit test

* Back to using GET instead of POST

- Otherwise, users need POST permissions to export!
- A bit of trickery with the forms architecture

* Fix remaining unit tests

* Implement unit test for BOM export

- Including test for custom plugin

* Fix unit test

* Bump API version

* Enhanced playwright tests

* Add debug for CI testing

* Single unit test only (for debugging)

* Fix typo

* typo fix

* Remove debugs

* Docs updates

* Revert typo

* Update tests

* Serializer fix

* Fix typo

* Offload data export to the background worker

- Requires mocking the original request object
- Will need some further unit testing!

* Refactor existing models into DataOutput

- Remove LabelOutput table
- Remove ReportOutput table
- Remove ExportOutput table
- Consolidate into single API endpoint

* Remove "output" tables from frontend

* Refactor frontend hook to be generic

* Frontend now works with background data export

* Fix tasks.py

* Adjust unit tests

* Revert 'plugin_key' to 'plugin'

* Improve user checking when printing

* Updates

* Remove erroneous migration file

* Tweak plugin registry

* Adjust playwright tests

* Refactor data export

- Convert into custom hook
- Enable for calendar view also

* Add playwright tests

* Adjust unit testing

* Tweak unit tests

* Add extra timeout to data export

* Fix for RUF045
2025-03-18 11:35:44 +11:00

126 lines
3.1 KiB
TypeScript

import { t } from '@lingui/macro';
import { useQuery } from '@tanstack/react-query';
import { useMemo, useState } from 'react';
import type { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { useApi } from '../contexts/ApiContext';
import { extractAvailableFields } from '../functions/forms';
import useDataOutput from './UseDataOutput';
import { useCreateApiFormModal } from './UseForm';
/**
* Custom hook for managing data export functionality
* This is intended to be used from a table or calendar view,
* to export the data displayed in the table or calendar
*/
export default function useDataExport({
url,
enabled,
filters,
searchTerm
}: {
url: string;
enabled: boolean;
filters: any;
searchTerm?: string;
}) {
const api = useApi();
// Selected plugin to use for data export
const [pluginKey, setPluginKey] = useState<string>('inventree-exporter');
const [exportId, setExportId] = useState<number | undefined>(undefined);
const progress = useDataOutput({
title: t`Exporting Data`,
id: exportId
});
// Construct a set of export parameters
const exportParams = useMemo(() => {
const queryParams: Record<string, any> = {
export: true
};
if (!!pluginKey) {
queryParams.export_plugin = pluginKey;
}
// Add in any additional parameters which have a defined value
for (const [key, value] of Object.entries(filters ?? {})) {
if (value != undefined) {
queryParams[key] = value;
}
}
if (!!searchTerm) {
queryParams.search = searchTerm;
}
return queryParams;
}, [pluginKey, filters, searchTerm]);
// Fetch available export fields via OPTIONS request
const extraExportFields = useQuery({
enabled: !!url && enabled,
queryKey: ['export-fields', pluginKey, url, exportParams],
gcTime: 500,
queryFn: () =>
api
.options(url, {
params: exportParams
})
.then((response: any) => {
return extractAvailableFields(response, 'GET') || {};
})
.catch(() => {
return {};
})
});
// Construct a field set for the export form
const exportFields: ApiFormFieldSet = useMemo(() => {
const extraFields: ApiFormFieldSet = extraExportFields.data || {};
const fields: ApiFormFieldSet = {
export_format: {},
export_plugin: {},
...extraFields
};
fields.export_format = {
...fields.export_format,
required: true
};
fields.export_plugin = {
...fields.export_plugin,
required: true,
onValueChange: (value: string) => {
if (!!value) {
setPluginKey(value);
}
}
};
return fields;
}, [extraExportFields]);
// Modal for exporting data
const exportModal = useCreateApiFormModal({
url: url,
queryParams: new URLSearchParams(exportParams),
title: t`Export Data`,
method: 'GET',
fields: exportFields,
submitText: t`Export`,
successMessage: null,
timeout: 30 * 1000,
onFormSuccess: (response: any) => {
setExportId(response.pk);
setPluginKey('inventree-exporter');
}
});
return exportModal;
}