Merge branch 'fe/develop' of https://lab.ssafy.com/s11-s-project/S11P21S002 into fe/fix/error-api

This commit is contained in:
정현조 2024-10-04 16:45:36 +09:00
commit ff4ec00d01
9 changed files with 127 additions and 45 deletions

View File

@ -11,5 +11,5 @@ export async function saveImageLabels(
}
export async function runAutoLabel(projectId: number, modelId = 1) {
return api.post(`/projects/${projectId}/auto`, { modelId }).then(({ data }) => data);
return api.post(`/projects/${projectId}/auto`, { modelId }, { timeout: 0 }).then(({ data }) => data);
}

View File

@ -1,4 +1,5 @@
import { Label } from '@/types';
import rectSort from '@/utils/rectSort';
import Konva from 'konva';
import { useEffect, useRef } from 'react';
import { Line, Transformer } from 'react-konva';
@ -39,8 +40,9 @@ export default function LabelRect({
[info.coordinates[0][0] * scale.x + rect.x, info.coordinates[0][1] * scale.y + rect.y],
[info.coordinates[1][0] * scale.x + rect.x, info.coordinates[1][1] * scale.y + rect.y],
];
const sortedPoints = rectSort(points as [[number, number], [number, number]]);
setLabel(points);
setLabel(sortedPoints);
rectRef.current?.setPosition({ x: 0, y: 0 });
rectRef.current?.scale({ x: 1, y: 1 });
};

View File

@ -19,6 +19,7 @@ import { useQueryClient } from '@tanstack/react-query';
import useSaveImageLabelsQuery from '@/queries/projects/useSaveImageLabelsQuery';
import { useToast } from '@/hooks/use-toast';
import CommentLabel from './CommentLabel';
import rectSort from '@/utils/rectSort';
export default function ImageCanvas() {
const { project, folderId, categories } = useProjectStore();
@ -188,11 +189,11 @@ export default function ImageCanvas() {
const endDrawRect = () => {
if (drawState !== 'rect' || rectPoints.length === 0) return;
if (rectPoints[0][0] === rectPoints[1][0] && rectPoints[0][1] === rectPoints[1][1]) {
setRectPoints([]);
if (rectPoints[0][0] === rectPoints[1][0] && rectPoints[0][1] === rectPoints[1][1]) {
return;
}
setRectPoints([]);
const sortedPoints = rectSort(rectPoints as [[number, number], [number, number]]);
const color = Math.floor(Math.random() * 0xffffff)
.toString(16)
@ -203,7 +204,7 @@ export default function ImageCanvas() {
categoryId: categories[0]!.id,
type: 'rectangle',
color: `#${color}`,
coordinates: rectPoints,
coordinates: sortedPoints,
});
setDrawState('pointer');
setSelectedLabelId(id);

View File

@ -27,7 +27,7 @@ export default function ImageUploadPresignedModal({ projectId, folderId }: { pro
</button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader title={fileCount > 0 ? `파일 업로드 (${fileCount}) PreSigned` : '파일 업로드 PreSigned'} />
<DialogHeader title={fileCount > 0 ? `파일 업로드 PreSigned (${fileCount})` : '파일 업로드 PreSigned'} />
<ImageUploadPresingedForm
onClose={handleClose}
onFileCount={handleFileCount}

View File

@ -169,9 +169,19 @@ export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: Proje
<div className="mb-1 flex w-full flex-col gap-2">
<div className="body-strong"></div>
<Tabs defaultValue="manual">
<TabsList className="mb-4">
<TabsTrigger value="manual"> </TabsTrigger>
<TabsTrigger value="file"> </TabsTrigger>
<TabsList className="mb-4 rounded-none border-transparent bg-transparent shadow-none">
<TabsTrigger
value="manual"
className="rounded-none border-b-2 border-transparent bg-transparent shadow-none data-[state=active]:border-blue-500 data-[state=active]:shadow-none"
>
</TabsTrigger>
<TabsTrigger
value="file"
className="rounded-none border-b-2 border-transparent bg-transparent shadow-none data-[state=active]:border-blue-500 data-[state=active]:shadow-none"
>
</TabsTrigger>
</TabsList>
<TabsContent value="manual">
<div className="mt-2 flex gap-2">
@ -192,7 +202,7 @@ export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: Proje
<TabsContent value="file">
<div
className={cn(
'mt-2 flex w-full items-center justify-center rounded-lg border-2 border-dashed p-5 text-center transition-colors',
'mt-2 flex h-40 w-full items-center justify-center rounded-lg border-2 border-dashed p-5 text-center transition-colors',
isDragging ? 'border-blue-500 bg-blue-100' : 'border-gray-300 bg-gray-100'
)}
onDragOver={handleDragOver}
@ -200,9 +210,15 @@ export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: Proje
onDrop={(event) => handleDrop(event, field.onChange)}
onClick={() => fileInputRef.current?.click()}
>
{isDragging ? (
<p className="text-primary"> </p>
) : (
<p className="text-gray-500">
.
<br />
.
</p>
)}
<input
type="file"
ref={fileInputRef}

View File

@ -30,7 +30,6 @@ export default function WorkspaceBrowseLayout() {
};
const workspaces = workspacesResponse?.workspaceResponses ?? [];
console.log(workspaces);
return (
<>

View File

@ -12,7 +12,7 @@ import ImageUploadFileForm from '../ImageUploadFileModal/ImageUploadFileForm';
import ImageUploadFolderFileForm from '../ImageUploadFolderFileModal/ImageUploadFolderFileForm';
import ImageUploadFolderForm from '../ImageUploadFolderModal/ImageUploadFolderForm';
import ImageUploadZipForm from '../ImageUploadZipModal/ImageUploadZipForm';
import ImageUploadPresignedForm from '../ImageUploadPresignedModal/ImageUploadPresignedForm.tsx'
import ImageUploadPresignedForm from '../ImageUploadPresignedModal/ImageUploadPresignedForm.tsx';
export default function WorkspaceDropdownMenu({
projectId,
@ -25,9 +25,10 @@ export default function WorkspaceDropdownMenu({
}) {
const [isOpenUploadFile, setIsOpenUploadFile] = React.useState<boolean>(false);
const [fileCount, setFileCount] = React.useState<number>(0);
const [isOpenUploadPresigned, setIsOpenUploadPresigned] = React.useState<boolean>(false);
const [presignedCount, setPresignedCount] = React.useState<number>(0);
const [isOpenUploadFolderFile, setIsOpenUploadFolderFile] = React.useState<boolean>(false);
const [isOpenUploadFolder, setIsOpenUploadFolder] = React.useState<boolean>(false);
const [isOpenUploadPresigned, setIsOpenUploadPresigned] = React.useState<boolean>(false);
const [isOpenUploadZip, setIsOpenUploadZip] = React.useState<boolean>(false);
const handleOpenUploadFile = () => setIsOpenUploadFile(true);
@ -36,6 +37,20 @@ export default function WorkspaceDropdownMenu({
setIsOpenUploadFile(false);
};
const handleFileCount = (fileCount: number) => {
setFileCount(fileCount);
};
const handleOpenUploadPresigned = () => setIsOpenUploadPresigned(true);
const handleCloseUploadPresigned = () => {
setIsOpenUploadPresigned(false);
};
const handlePresignedCount = (fileCount: number) => {
setPresignedCount(fileCount);
};
const handleOpenUploadFolderFile = () => setIsOpenUploadFolderFile(true);
const handleCloseUploadFolderFile = () => {
@ -48,22 +63,12 @@ export default function WorkspaceDropdownMenu({
setIsOpenUploadFolder(false);
};
const handleOpenUploadPresigned = () => setIsOpenUploadPresigned(true);
const handleCloseUploadPresigned = () => {
setIsOpenUploadPresigned(false);
};
const handleOpenUploadZip = () => setIsOpenUploadZip(true);
const handleCloseUploadZip = () => {
setIsOpenUploadZip(false);
};
const handleFileCount = (fileCount: number) => {
setFileCount(fileCount);
};
return (
<>
<DropdownMenu>
@ -83,9 +88,9 @@ export default function WorkspaceDropdownMenu({
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleOpenUploadFile}> </DropdownMenuItem>
<DropdownMenuItem onClick={handleOpenUploadPresigned}> (PresignedUrl )</DropdownMenuItem>
<DropdownMenuItem onClick={handleOpenUploadFolderFile}> ( API )</DropdownMenuItem>
<DropdownMenuItem onClick={handleOpenUploadFolder}> ( )</DropdownMenuItem>
<DropdownMenuItem onClick={handleOpenUploadPresigned}> (PresignedUrl )</DropdownMenuItem>
<DropdownMenuItem onClick={handleOpenUploadZip}> </DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@ -107,6 +112,25 @@ export default function WorkspaceDropdownMenu({
</DialogContent>
</Dialog>
<Dialog
open={isOpenUploadPresigned}
onOpenChange={setIsOpenUploadPresigned}
>
<DialogTrigger asChild></DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader
title={presignedCount > 0 ? `파일 업로드 PreSigned (${presignedCount})` : '파일 업로드 PreSigned'}
/>
<ImageUploadPresignedForm
onClose={handleCloseUploadPresigned}
onRefetch={onRefetch}
onFileCount={handlePresignedCount}
projectId={projectId}
folderId={folderId}
/>
</DialogContent>
</Dialog>
<Dialog
open={isOpenUploadFolderFile}
onOpenChange={setIsOpenUploadFolderFile}
@ -139,23 +163,6 @@ export default function WorkspaceDropdownMenu({
</DialogContent>
</Dialog>
<Dialog
open={isOpenUploadPresigned}
onOpenChange={setIsOpenUploadPresigned}
>
<DialogTrigger asChild></DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader title='파일 업로드' />
<ImageUploadPresignedForm
onClose={handleCloseUploadPresigned}
onRefetch={onRefetch}
onFileCount={handleFileCount}
projectId={projectId}
folderId={folderId}
/>
</DialogContent>
</Dialog>
<Dialog
open={isOpenUploadZip}
onOpenChange={setIsOpenUploadZip}

View File

@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import rectSort from './rectSort';
describe('rectSort', () => {
it('should sort coordinates when first point is top-left and second point is bottom-right', () => {
const result = rectSort([
[1, 2],
[3, 4],
]);
expect(result).toEqual([
[1, 2],
[3, 4],
]);
});
it('should sort coordinates when first point is bottom-right and second point is top-left', () => {
const result = rectSort([
[3, 4],
[1, 2],
]);
expect(result).toEqual([
[1, 2],
[3, 4],
]);
});
it('should sort coordinates when first point is bottom-left and second point is top-right', () => {
const result = rectSort([
[1, 4],
[3, 2],
]);
expect(result).toEqual([
[1, 2],
[3, 4],
]);
});
it('should sort coordinates when first point is top-right and second point is bottom-left', () => {
const result = rectSort([
[3, 2],
[1, 4],
]);
expect(result).toEqual([
[1, 2],
[3, 4],
]);
});
});

View File

@ -0,0 +1,9 @@
export default function rectSort([[x1, y1], [x2, y2]]: [[number, number], [number, number]]): [
[number, number],
[number, number],
] {
return [
[Math.min(x1, x2), Math.min(y1, y2)],
[Math.max(x1, x2), Math.max(y1, y2)],
];
}