Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
line-height: 0px;
padding: var(--spectrum-global-dimension-size-125);
border-radius: var(--spectrum-global-dimension-size-50);
background-color: var(--spectrum-gray-100);

&:empty {
display: none;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Image } from '@geti-inspect/icons';
import { Flex } from '@geti/ui';
import { clsx } from 'clsx';

import styles from './dataset-item-placeholder.module.scss';

export const DatasetItemPlaceholder = () => {
return (
<Flex justifyContent={'center'} alignItems={'center'} UNSAFE_className={clsx(styles.datasetItemPlaceholder)}>
<Image />
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.datasetItemPlaceholder {
width: 100%;
height: 100%;
aspect-ratio: auto;
border: 1px dashed var(--spectrum-global-color-gray-700);
background-color: var(--spectrum-global-color-gray-200);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MediaItem } from '../types';

const PLACEHOLDER_FILENAME = 'placeholder';

export const isPlaceholderItem = (name: string): boolean => {
return name.includes(PLACEHOLDER_FILENAME);
};

export const getPlaceholderItem = (index: number): MediaItem => {
return {
id: `${PLACEHOLDER_FILENAME}-${index}`,
filename: PLACEHOLDER_FILENAME,
project_id: '',
size: 0,
is_anomalous: false,
width: 0,
height: 0,
};
};

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import { DialogContainer, Flex, Grid, Heading, minmax, repeat } from '@geti/ui';
import { DialogContainer, Flex, Heading, Selection, Size, View } from '@geti/ui';
import { isNil } from 'lodash-es';
import isEmpty from 'lodash-es/isEmpty';
import { useQueryState } from 'nuqs';
import { MediaThumbnail } from 'src/components/media-thumbnail/media-thumbnail.component';
import { GridMediaItem } from 'src/components/virtualizer-grid-layout/grid-media-item/grid-media-item.component';
import { VirtualizerGridLayout } from 'src/components/virtualizer-grid-layout/virtualizer-grid-layout.component';

import { DatasetItemPlaceholder } from './dataset-item/dataset-item-placeholder.component';
import { DatasetItem } from './dataset-item/dataset-item.component';
import { getThumbnailUrl } from '../utils';
import { DatasetItemPlaceholder } from './dataset-item-placeholder/dataset-item-placeholder.component';
import { getPlaceholderItem, isPlaceholderItem } from './dataset-item-placeholder/util';
import { DeleteMediaItem } from './delete-dataset-item/delete-dataset-item.component';
import { useGetMediaItems } from './hooks/use-get-media-items.hook';
import { MediaPreview } from './media-preview/media-preview.component';
import { InferenceOpacityProvider } from './media-preview/providers/inference-opacity-provider.component';
import { MediaItem } from './types';
import { REQUIRED_NUMBER_OF_NORMAL_IMAGES_TO_TRIGGER_TRAINING } from './utils';

interface DatasetItemProps {
mediaItems: MediaItem[];
}
const layoutOptions = {
maxColumns: 4,
minSpace: new Size(8, 8),
minItemSize: new Size(120, 120),
preserveAspectRatio: true,
};

export const DatasetList = ({ mediaItems }: DatasetItemProps) => {
export const DatasetList = () => {
const { mediaItems, isFetchingNextPage, fetchNextPage } = useGetMediaItems();
const [selectedMediaItemId, setSelectedMediaItem] = useQueryState('selectedMediaItem');
//TODO: revisit implementation when dataset loading is paginated
const selectedMediaItem = mediaItems.find((item) => item.id === selectedMediaItemId);
Expand All @@ -22,34 +33,55 @@ export const DatasetList = ({ mediaItems }: DatasetItemProps) => {
...mediaItems,
...Array.from({
length: Math.max(0, REQUIRED_NUMBER_OF_NORMAL_IMAGES_TO_TRIGGER_TRAINING - mediaItems.length),
}).map(() => undefined),
}).map((_, index): MediaItem => getPlaceholderItem(index)),
];

const handleSelectionChange = (newKeys: Selection) => {
const updatedSelectedKeys = new Set(newKeys);
const firstKey = updatedSelectedKeys.values().next().value;
const itemId = String(firstKey);

if (!isNil(firstKey) && !isPlaceholderItem(itemId)) {
setSelectedMediaItem(itemId);
}
};

return (
<Flex gap='size-200' direction={'column'} height={'100%'}>
<Heading>Normal images</Heading>

<Grid
flex={1}
gap={'size-100'}
rows={['max-content', '1fr']}
alignContent={'start'}
columns={repeat('auto-fill', minmax('size-1600', '1fr'))}
>
{mediaItemsToRender.map((mediaItem, index) =>
isEmpty(mediaItem) ? (
<DatasetItemPlaceholder key={index} />
) : (
<DatasetItem
key={mediaItem.id}
mediaItem={mediaItem}
isSelected={selectedMediaItem?.id === mediaItem.id}
onClick={() => setSelectedMediaItem(mediaItem?.id ?? null)}
onDeleted={() => selectedMediaItem?.id === mediaItem.id && setSelectedMediaItem(null)}
/>
)
)}
</Grid>
<View width={'100%'} height={'100%'}>
<VirtualizerGridLayout
items={mediaItemsToRender}
ariaLabel='sidebar-items'
selectionMode='single'
layoutOptions={layoutOptions}
isLoadingMore={isFetchingNextPage}
onLoadMore={fetchNextPage}
onSelectionChange={handleSelectionChange}
contentItem={(mediaItem) =>
mediaItem.filename === 'placeholder' ? (
<DatasetItemPlaceholder />
) : (
<GridMediaItem
contentElement={() => (
<MediaThumbnail
alt={mediaItem.filename}
url={getThumbnailUrl(mediaItem)}
onClick={() => setSelectedMediaItem(mediaItem.id ?? null)}
/>
)}
topRightElement={() => (
<DeleteMediaItem
itemsIds={[String(mediaItem.id)]}
onDeleted={() => setSelectedMediaItem(null)}
/>
)}
/>
)
}
/>
</View>

<DialogContainer onDismiss={() => setSelectedMediaItem(null)}>
{!isEmpty(selectedMediaItem) && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
import { Suspense } from 'react';

import { $api } from '@geti-inspect/api';
import { useProjectIdentifier } from '@geti-inspect/hooks';
import { Flex, Heading, Loading, View } from '@geti/ui';

import { TrainModelButton } from '../train-model/train-model-button.component';
import { DatasetList } from './dataset-list.component';
import { UploadImages } from './upload-images.component';

const useMediaItems = () => {
const { projectId } = useProjectIdentifier();

const { data } = $api.useSuspenseQuery('get', '/api/projects/{project_id}/images', {
params: { path: { project_id: projectId } },
});

return {
mediaItems: data.media,
};
};

export const Dataset = () => {
const { mediaItems } = useMediaItems();
return (
<Flex direction={'column'} height={'100%'}>
<Heading margin={0}>
Expand All @@ -36,7 +21,7 @@ export const Dataset = () => {
<Suspense fallback={<Loading mode={'inline'} />}>
<View flex={1} padding={'size-300'}>
<Flex direction={'column'} height={'100%'} gap={'size-300'}>
<DatasetList mediaItems={mediaItems} />
<DatasetList />
</Flex>
</View>
</Suspense>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { $api } from '@geti-inspect/api';
import { useProjectIdentifier } from '@geti-inspect/hooks';

const mediaItemsLimit = 20;

export const useGetMediaItems = () => {
const { projectId } = useProjectIdentifier();

const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = $api.useInfiniteQuery(
'get',
'/api/projects/{project_id}/images',
{
params: {
query: { offset: 0, limit: mediaItemsLimit },
path: { project_id: projectId },
},
},
{
pageParamName: 'offset',
getNextPageParam: ({
pagination,
}: {
pagination: { offset: number; limit: number; count: number; total: number };
}) => {
const total = pagination.offset + pagination.count;

if (total >= pagination.total) {
return undefined;
}

return pagination.offset + mediaItemsLimit;
},
}
);

const mediaItems = data?.pages.flatMap((page) => page.media) ?? [];

return { mediaItems, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage };
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Selection, Size, View } from '@geti/ui';
import { MediaThumbnail } from 'src/components/media-thumbnail/media-thumbnail.component';
import { GridMediaItem } from 'src/components/virtualizer-grid-layout/grid-media-item/grid-media-item.component';
import { VirtualizerGridLayout } from 'src/components/virtualizer-grid-layout/virtualizer-grid-layout.component';
import { getThumbnailUrl } from 'src/features/inspect/utils';

import { GridMediaItem } from '../../../../..//components/virtualizer-grid-layout/grid-media-item/grid-media-item.component';
import { MediaThumbnail } from '../../../../../components/media-thumbnail/media-thumbnail.component';
import { VirtualizerGridLayout } from '../../../../../components/virtualizer-grid-layout/virtualizer-grid-layout.component';
import { MediaItem } from '../../types';

interface SidebarItemsProps {
Expand All @@ -19,9 +20,6 @@ const layoutOptions = {
preserveAspectRatio: true,
};

const getThumbnailUrl = (mediaItem: MediaItem) =>
`/api/projects/${mediaItem.project_id}/images/${mediaItem.id}/thumbnail`;

export const SidebarItems = ({ mediaItems, selectedMediaItem, onSelectedMediaItem }: SidebarItemsProps) => {
const selectedIndex = mediaItems.findIndex((item) => item.id === selectedMediaItem.id);

Expand Down
Loading
Loading