Merge branch 'fe/develop' of https://lab.ssafy.com/s11-s-project/S11P21S002 into fe/refactor/reviews

This commit is contained in:
정현조 2024-09-26 20:55:53 +09:00
commit 5f9d41fd09
6 changed files with 85 additions and 28 deletions

View File

@ -9,14 +9,15 @@ import LabelPolygon from './LabelPolygon';
import CanvasControlBar from '../CanvasControlBar';
import { Label } from '@/types';
import useLabelJson from '@/hooks/useLabelJson';
import { saveImageLabels } from '@/api/lablingApi';
import useProjectStore from '@/stores/useProjectStore';
import { LABEL_CATEGORY } from '@/constants';
import { useQueryClient } from '@tanstack/react-query';
import useSaveImageLabelsQuery from '@/queries/projects/useSaveImageLabelsQuery';
export default function ImageCanvas() {
const project = useProjectStore((state) => state.project)!;
const { project, folderId } = useProjectStore();
const { id: imageId, imagePath, dataPath } = useCanvasStore((state) => state.image)!;
const { data: labelData } = useLabelJson(dataPath, project);
const { data: labelData } = useLabelJson(dataPath, project!);
const { labels, drawState, setDrawState, addLabel, setLabels, selectedLabelId, setSelectedLabelId, sidebarSize } =
useCanvasStore();
const { shapes } = labelData || [];
@ -28,6 +29,8 @@ export default function ImageCanvas() {
const [image] = useImage(imagePath);
const [rectPoints, setRectPoints] = useState<[number, number][]>([]);
const [polygonPoints, setPolygonPoints] = useState<[number, number][]>([]);
const saveImageLabelsMutation = useSaveImageLabelsQuery();
const queryClient = useQueryClient();
useEffect(() => {
setLabels(
@ -65,13 +68,17 @@ export default function ImageCanvas() {
imageHeight: image!.height,
});
saveImageLabels(project.id, imageId, { data: json })
.catch(() => {
alert('레이블 데이터 저장 실패');
})
.then(() => {
alert('레이블링 성공!');
});
saveImageLabelsMutation.mutate(
{ projectId: project!.id, imageId: imageId, data: { data: json } },
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['folder', project!.id.toString(), folderId] });
},
onError: () => {
alert('레이블 데이터 저장 실패');
},
}
);
};
const startDrawRect = () => {
const { x, y } = stageRef.current!.getRelativePointerPosition()!;
@ -346,7 +353,7 @@ export default function ImageCanvas() {
</Stage>
<CanvasControlBar
saveJson={saveJson}
projectType={project.type}
projectType={project!.type}
/>
</div>
) : (

View File

@ -56,6 +56,7 @@ export default function ProjectDirectoryItem({
key={`${projectId}-${item.imageTitle}`}
item={item}
depth={depth + 1}
folderId={folderData.id}
selected={image?.id === item.id}
/>
))}

View File

@ -1,31 +1,35 @@
import { cn } from '@/lib/utils';
import { ImageResponse } from '@/types';
import { Check, Image, Minus } from 'lucide-react';
import { ArrowDownToLine, Check, Image, Loader, Minus, Send } from 'lucide-react';
import useCanvasStore from '@/stores/useCanvasStore';
import useProjectStore from '@/stores/useProjectStore';
export default function ProjectFileItem({
className = '',
item,
folderId = 0,
depth = 0,
selected,
}: {
className?: string;
item: ImageResponse;
folderId?: number;
depth?: number;
selected: boolean;
}) {
const paddingLeft = depth * 12;
// const changeImage = useCanvasStore((state) => state.changeImage);
const setImage = useCanvasStore((state) => state.setImage);
const setFolderId = useProjectStore((state) => state.setFolderId);
const handleClick = () => {
setImage(item);
setFolderId(folderId);
};
return (
<button
className={cn(
`flex w-full gap-2 rounded-md py-0.5 pr-1 ${selected ? 'bg-gray-200' : 'hover:bg-gray-100'}`,
`flex w-full items-center gap-2 rounded-md py-0.5 pr-1 ${selected ? 'bg-gray-200' : 'hover:bg-gray-100'}`,
className
)}
style={{
@ -40,15 +44,30 @@ export default function ProjectFileItem({
/>
</div>
<span className="grow overflow-hidden text-ellipsis whitespace-nowrap text-left">{item.imageTitle}</span>
{item.status === 'COMPLETED' ? (
<Check
size={16}
className="shrink-0 stroke-green-500"
{item.status === 'PENDING' ? (
<Minus
size={12}
className="shrink-0 stroke-gray-400"
/>
) : item.status === 'IN_PROGRESS' ? (
<Loader
size={12}
className="shrink-0 stroke-yellow-500"
/>
) : item.status === 'SAVE' ? (
<ArrowDownToLine
size={12}
className="shrink-0 stroke-gray-400"
/>
) : item.status === 'REVIEW_REQUEST' ? (
<Send
size={12}
className="shrink-0 stroke-blue-400"
/>
) : (
<Minus
size={16}
className="shrink-0 stroke-gray-400"
<Check
size={12}
className="shrink-0 stroke-green-500"
/>
)}
</button>

View File

@ -1,5 +1,5 @@
import { Project } from '@/types';
import { Play } from 'lucide-react';
import { LoaderCircle, Play } from 'lucide-react';
import ProjectFileItem from './ProjectFileItem';
import ProjectDirectoryItem from './ProjectDirectoryItem';
import useFolderQuery from '@/queries/folders/useFolderQuery';
@ -62,11 +62,17 @@ export default function ProjectStructure({ project }: { project: Project }) {
<Button
variant="outlinePrimary"
className="w-full"
disabled={requestAutoLabel.isPending}
onClick={() => {
requestAutoLabel.mutate(
{ projectId: project.id },
{
onSuccess: refetch,
onSuccess: () => {
refetch;
setTimeout(() => {
alert('레이블링 성공!');
}, 100);
},
onError: () => {
alert('자동 레이블링을 요청하는 중 오류가 발생했습니다.');
},
@ -74,11 +80,22 @@ export default function ProjectStructure({ project }: { project: Project }) {
);
}}
>
<Play
size={16}
className="mr-1"
/>
<span> </span>
{requestAutoLabel.isPending ? (
<>
<LoaderCircle
size={16}
className="animate-spin"
/>
</>
) : (
<>
<Play
size={16}
className="mr-1"
/>
<span> </span>
</>
)}
</Button>
</div>
</div>

View File

@ -0,0 +1,9 @@
import { saveImageLabels } from '@/api/lablingApi';
import { useMutation } from '@tanstack/react-query';
export default function useSaveImageLabelsQuery() {
return useMutation({
mutationFn: ({ projectId, imageId, data }: { projectId: number; imageId: number; data: { data: string } }) =>
saveImageLabels(projectId, imageId, data),
});
}

View File

@ -4,11 +4,15 @@ import { Project } from '@/types';
interface ProjectState {
project: Project | null;
setProject: (project: Project | null) => void;
folderId: number;
setFolderId: (folderId: number) => void;
}
const useProjectStore = create<ProjectState>((set) => ({
project: null,
setProject: (project) => set({ project }),
folderId: 0,
setFolderId: (folderId) => set({ folderId }),
}));
export default useProjectStore;