mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
PartThumbTable updates (#9094)
- Change columns based on viewport width - Use debounced value - Enable pagination - Fix pagination on backend API
This commit is contained in:
parent
a3ffc01d88
commit
480536a023
@ -522,7 +522,10 @@ class PartThumbs(ListAPI):
|
||||
|
||||
data = serializer.data
|
||||
|
||||
return Response(data)
|
||||
if page is not None:
|
||||
return self.get_paginated_response(data)
|
||||
else:
|
||||
return Response(data)
|
||||
|
||||
filter_backends = [InvenTreeSearchFilter]
|
||||
|
||||
|
@ -305,7 +305,7 @@ function ImageActionButtons({
|
||||
|
||||
modals.open({
|
||||
title: <StylishText size='xl'>{t`Select Image`}</StylishText>,
|
||||
size: 'xxl',
|
||||
size: '80%',
|
||||
children: <PartThumbTable pk={pk} setImage={setImage} />
|
||||
});
|
||||
}}
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
Button,
|
||||
Divider,
|
||||
Group,
|
||||
Pagination,
|
||||
Paper,
|
||||
SimpleGrid,
|
||||
Skeleton,
|
||||
@ -11,12 +12,13 @@ import {
|
||||
Text,
|
||||
TextInput
|
||||
} from '@mantine/core';
|
||||
import { useHover } from '@mantine/hooks';
|
||||
import { useDebouncedValue, useHover } from '@mantine/hooks';
|
||||
import { modals } from '@mantine/modals';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type React from 'react';
|
||||
import { Suspense, useEffect, useState } from 'react';
|
||||
import { Suspense, useState } from 'react';
|
||||
|
||||
import { IconX } from '@tabler/icons-react';
|
||||
import { api } from '../../App';
|
||||
import { Thumbnail } from '../../components/images/Thumbnail';
|
||||
import { ApiEndpoints } from '../../enums/ApiEndpoints';
|
||||
@ -27,9 +29,6 @@ import { apiUrl } from '../../states/ApiState';
|
||||
*/
|
||||
export type ThumbTableProps = {
|
||||
pk: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
search?: string;
|
||||
setImage: (image: string) => void;
|
||||
};
|
||||
|
||||
@ -122,37 +121,42 @@ async function setNewImage(
|
||||
/**
|
||||
* Renders a "table" of thumbnails
|
||||
*/
|
||||
export function PartThumbTable({
|
||||
limit = 24,
|
||||
offset = 0,
|
||||
search = '',
|
||||
pk,
|
||||
setImage
|
||||
}: Readonly<ThumbTableProps>) {
|
||||
export function PartThumbTable({ pk, setImage }: Readonly<ThumbTableProps>) {
|
||||
const limit = 24;
|
||||
|
||||
const [thumbImage, setThumbImage] = useState<string | null>(null);
|
||||
const [filterInput, setFilterInput] = useState<string>('');
|
||||
const [filterQuery, setFilterQuery] = useState<string>(search);
|
||||
|
||||
const [page, setPage] = useState<number>(1);
|
||||
const [totalPages, setTotalPages] = useState<number>(1);
|
||||
|
||||
// Keep search filters from updating while user is typing
|
||||
useEffect(() => {
|
||||
const timeoutId = setTimeout(() => setFilterQuery(filterInput), 500);
|
||||
return () => clearTimeout(timeoutId);
|
||||
}, [filterInput]);
|
||||
const [searchText] = useDebouncedValue(filterInput, 500);
|
||||
|
||||
// Fetch thumbnails from API
|
||||
const thumbQuery = useQuery({
|
||||
queryKey: [
|
||||
ApiEndpoints.part_thumbs_list,
|
||||
{ limit: limit, offset: offset, search: filterQuery }
|
||||
],
|
||||
queryKey: [ApiEndpoints.part_thumbs_list, page, searchText],
|
||||
queryFn: async () => {
|
||||
return api.get(apiUrl(ApiEndpoints.part_thumbs_list), {
|
||||
params: {
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
search: filterQuery
|
||||
}
|
||||
});
|
||||
const offset = Math.max(0, page - 1) * limit;
|
||||
|
||||
return api
|
||||
.get(apiUrl(ApiEndpoints.part_thumbs_list), {
|
||||
params: {
|
||||
offset: offset,
|
||||
limit: limit,
|
||||
search: searchText
|
||||
}
|
||||
})
|
||||
.then((response) => {
|
||||
const records = response?.data?.count ?? 1;
|
||||
setTotalPages(Math.ceil(records / limit));
|
||||
return response.data?.results ?? response.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
setTotalPages(1);
|
||||
setPage(1);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -161,18 +165,20 @@ export function PartThumbTable({
|
||||
<Suspense>
|
||||
<Divider />
|
||||
<Paper p='sm'>
|
||||
<SimpleGrid cols={8}>
|
||||
<SimpleGrid
|
||||
cols={{ base: 2, '450px': 3, '600px': 4, '900px': 6 }}
|
||||
type='container'
|
||||
spacing='xs'
|
||||
>
|
||||
{!thumbQuery.isFetching
|
||||
? thumbQuery.data?.data.map(
|
||||
(data: ImageElement, index: number) => (
|
||||
<PartThumbComponent
|
||||
element={data}
|
||||
key={index}
|
||||
selected={thumbImage}
|
||||
selectImage={setThumbImage}
|
||||
/>
|
||||
)
|
||||
)
|
||||
? thumbQuery?.data.map((data: ImageElement, index: number) => (
|
||||
<PartThumbComponent
|
||||
element={data}
|
||||
key={index}
|
||||
selected={thumbImage}
|
||||
selectImage={setThumbImage}
|
||||
/>
|
||||
))
|
||||
: [...Array(limit)].map((elem, idx) => (
|
||||
<Skeleton
|
||||
height={150}
|
||||
@ -188,13 +194,28 @@ export function PartThumbTable({
|
||||
|
||||
<Divider />
|
||||
<Paper p='sm'>
|
||||
<Group justify='space-between'>
|
||||
<TextInput
|
||||
placeholder={t`Search...`}
|
||||
onChange={(event) => {
|
||||
setFilterInput(event.currentTarget.value);
|
||||
}}
|
||||
/>
|
||||
<Group justify='space-between' gap='xs'>
|
||||
<Group justify='left' gap='xs'>
|
||||
<TextInput
|
||||
placeholder={t`Search...`}
|
||||
value={filterInput}
|
||||
onChange={(event) => {
|
||||
setFilterInput(event.currentTarget.value);
|
||||
}}
|
||||
rightSection={
|
||||
<IconX
|
||||
size='1rem'
|
||||
color='red'
|
||||
onClick={() => setFilterInput('')}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Pagination
|
||||
total={totalPages}
|
||||
value={page}
|
||||
onChange={(value) => setPage(value)}
|
||||
/>
|
||||
</Group>
|
||||
<Button
|
||||
disabled={!thumbImage}
|
||||
onClick={() => setNewImage(thumbImage, pk, setImage)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user