2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

[PUI] Instance hook (#5564)

* Custom hook for fetching instance data from the server

* Refactor pages to use new hookr

* Allow useInstance hook to handle parameters
This commit is contained in:
Oliver 2023-09-18 21:07:01 +10:00 committed by GitHub
parent fe68598c1b
commit ad8df52b73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 82 deletions

View File

@ -0,0 +1,58 @@
import { useQuery } from '@tanstack/react-query';
import { useCallback, useState } from 'react';
import { api } from '../App';
/**
* Custom hook for loading a single instance of an instance from the API
*
* - Queries the API for a single instance of an object, and returns the result.
* - Provides a callback function to refresh the instance
*
* To use this hook:
* const { instance, refreshInstance } = useInstance(url: string, pk: number)
*/
export function useInstance(
url: string,
pk: string | undefined,
params: any = {}
) {
const [instance, setInstance] = useState<any>({});
const instanceQuery = useQuery({
queryKey: ['instance', url, pk, params],
enabled: pk != null && pk != undefined && pk.length > 0,
queryFn: async () => {
return api
.get(url + pk + '/', {
params: params
})
.then((response) => {
switch (response.status) {
case 200:
setInstance(response.data);
return response.data;
default:
setInstance({});
return null;
}
})
.catch((error) => {
setInstance({});
console.error(`Error fetching instance ${url}${pk}:`, error);
return null;
});
},
refetchOnMount: false,
refetchOnWindowFocus: false
});
const refreshInstance = useCallback(
function () {
instanceQuery.refetch();
},
[instanceQuery]
);
return { instance, refreshInstance, instanceQuery };
}

View File

@ -26,6 +26,7 @@ import { AttachmentTable } from '../../components/tables/AttachmentTable';
import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable'; import { BuildOrderTable } from '../../components/tables/build/BuildOrderTable';
import { StockItemTable } from '../../components/tables/stock/StockItemTable'; import { StockItemTable } from '../../components/tables/stock/StockItemTable';
import { NotesEditor } from '../../components/widgets/MarkdownEditor'; import { NotesEditor } from '../../components/widgets/MarkdownEditor';
import { useInstance } from '../../hooks/UseInstance';
/** /**
* Detail page for a single Build Order * Detail page for a single Build Order
@ -33,30 +34,12 @@ import { NotesEditor } from '../../components/widgets/MarkdownEditor';
export default function BuildDetail() { export default function BuildDetail() {
const { id } = useParams(); const { id } = useParams();
// Build data const {
const [build, setBuild] = useState<any>({}); instance: build,
refreshInstance,
useEffect(() => { instanceQuery
setBuild({}); } = useInstance('/build/', id, {
}, [id]); part_detail: true
// Query hook for fetching build data
const buildQuery = useQuery(['build', id ?? -1], async () => {
let url = `/build/${id}/`;
return api
.get(url, {
params: {
part_detail: true
}
})
.then((response) => {
setBuild(response.data);
})
.catch((error) => {
console.error(error);
setBuild({});
});
}); });
const buildPanels: PanelType[] = useMemo(() => { const buildPanels: PanelType[] = useMemo(() => {
@ -162,7 +145,7 @@ export default function BuildDetail() {
]} ]}
actions={[<PlaceholderPill key="1" />]} actions={[<PlaceholderPill key="1" />]}
/> />
<LoadingOverlay visible={buildQuery.isFetching} /> <LoadingOverlay visible={instanceQuery.isFetching} />
<PanelGroup panels={buildPanels} /> <PanelGroup panels={buildPanels} />
</Stack> </Stack>
</> </>

View File

@ -15,6 +15,7 @@ import { PageDetail } from '../../components/nav/PageDetail';
import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; import { PanelGroup, PanelType } from '../../components/nav/PanelGroup';
import { PartCategoryTable } from '../../components/tables/part/PartCategoryTable'; import { PartCategoryTable } from '../../components/tables/part/PartCategoryTable';
import { PartListTable } from '../../components/tables/part/PartTable'; import { PartListTable } from '../../components/tables/part/PartTable';
import { useInstance } from '../../hooks/UseInstance';
/** /**
* Detail view for a single PartCategory instance. * Detail view for a single PartCategory instance.
@ -24,27 +25,10 @@ import { PartListTable } from '../../components/tables/part/PartTable';
export default function CategoryDetail({}: {}) { export default function CategoryDetail({}: {}) {
const { id } = useParams(); const { id } = useParams();
const [category, setCategory] = useState<any>({}); const { instance: category, refreshInstance } = useInstance(
'/part/category/',
useEffect(() => { id
setCategory({}); );
}, [id]);
const categoryQuery = useQuery({
enabled: id != null && id != undefined,
queryKey: ['category', id],
queryFn: async () => {
return api
.get(`/part/category/${id}/`)
.then((response) => {
setCategory(response.data);
return response.data;
})
.catch((error) => {
console.error('Error fetching category data:', error);
});
}
});
const categoryPanels: PanelType[] = useMemo( const categoryPanels: PanelType[] = useMemo(
() => [ () => [
@ -90,7 +74,7 @@ export default function CategoryDetail({}: {}) {
title={t`Part Category`} title={t`Part Category`}
detail={<Text>{category.name ?? 'Top level'}</Text>} detail={<Text>{category.name ?? 'Top level'}</Text>}
breadcrumbs={ breadcrumbs={
id category.pk
? [ ? [
{ name: t`Parts`, url: '/part' }, { name: t`Parts`, url: '/part' },
{ name: '...', url: '' }, { name: '...', url: '' },

View File

@ -1,13 +1,5 @@
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import { Alert, Button, LoadingOverlay, Stack, Text } from '@mantine/core';
Alert,
Button,
Group,
LoadingOverlay,
Space,
Stack,
Text
} from '@mantine/core';
import { import {
IconBuilding, IconBuilding,
IconCurrencyDollar, IconCurrencyDollar,
@ -41,6 +33,7 @@ import {
NotesEditor NotesEditor
} from '../../components/widgets/MarkdownEditor'; } from '../../components/widgets/MarkdownEditor';
import { editPart } from '../../functions/forms/PartForms'; import { editPart } from '../../functions/forms/PartForms';
import { useInstance } from '../../hooks/UseInstance';
/** /**
* Detail view for a single Part instance * Detail view for a single Part instance
@ -48,12 +41,11 @@ import { editPart } from '../../functions/forms/PartForms';
export default function PartDetail() { export default function PartDetail() {
const { id } = useParams(); const { id } = useParams();
// Part data const {
const [part, setPart] = useState<any>({}); instance: part,
refreshInstance,
useEffect(() => { instanceQuery
setPart({}); } = useInstance('/part/', id);
}, [id]);
// Part data panels (recalculate when part data changes) // Part data panels (recalculate when part data changes)
const partPanels: PanelType[] = useMemo(() => { const partPanels: PanelType[] = useMemo(() => {
@ -153,22 +145,6 @@ export default function PartDetail() {
]; ];
}, [part]); }, [part]);
// Query hook for fetching part data
const partQuery = useQuery(['part', id], async () => {
let url = `/part/${id}/`;
return api
.get(url)
.then((response) => {
setPart(response.data);
return response.data;
})
.catch((error) => {
setPart({});
return null;
});
});
function partAttachmentsTab(): React.ReactNode { function partAttachmentsTab(): React.ReactNode {
return ( return (
<AttachmentTable <AttachmentTable
@ -226,9 +202,7 @@ export default function PartDetail() {
part.pk && part.pk &&
editPart({ editPart({
part_id: part.pk, part_id: part.pk,
callback: () => { callback: refreshInstance
partQuery.refetch();
}
}) })
} }
> >
@ -236,7 +210,7 @@ export default function PartDetail() {
</Button> </Button>
]} ]}
/> />
<LoadingOverlay visible={partQuery.isFetching} /> <LoadingOverlay visible={instanceQuery.isFetching} />
<PanelGroup panels={partPanels} /> <PanelGroup panels={partPanels} />
</Stack> </Stack>
</> </>