Fix: 프로젝트 변경 시 캔버스 초기화

This commit is contained in:
jhynsoo 2024-09-25 13:33:54 +09:00
parent 27c5dbc2b8
commit cde724cad9
9 changed files with 55 additions and 66 deletions

View File

@ -10,9 +10,10 @@ import CanvasControlBar from '../CanvasControlBar';
import { Label } from '@/types';
import useLabelJson from '@/hooks/useLabelJson';
import { saveImageLabels } from '@/api/lablingApi';
import useProjectStore from '@/stores/useProjectStore';
export default function ImageCanvas() {
const project = useCanvasStore((state) => state.project)!;
const project = useProjectStore((state) => state.project)!;
const { id: imageId, imagePath, dataPath } = useCanvasStore((state) => state.image)!;
const { data: labelData, refetch } = useLabelJson(dataPath, project);
const { shapes } = labelData || [];

View File

@ -45,7 +45,10 @@ export default function WorkspaceDropdownMenu({
<>
<DropdownMenu>
<DropdownMenuTrigger>
<Menu size={20} />
<Menu
size={16}
className="stroke-gray-900"
/>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuItem

View File

@ -1,46 +1,29 @@
import LabelButton from './LabelButton';
import { Button } from '../ui/button';
import { Play } from 'lucide-react';
import useCanvasStore from '@/stores/useCanvasStore';
export default function WorkspaceLabelBar() {
const labels = useCanvasStore((state) => state.labels);
const { labels, image } = useCanvasStore();
const selectedLabelId = useCanvasStore((state) => state.selectedLabelId);
const setSelectedLabelId = useCanvasStore((state) => state.setSelectedLabelId);
const handleAutoLabeling = () => {
console.log('Auto labeling');
};
return (
<div className="flex h-full w-[280px] flex-col justify-between gap-2 border-l border-gray-300 bg-gray-50 p-3">
<div className="flex h-full w-[200px] flex-col justify-between gap-2 border-l border-gray-300 bg-gray-50 p-3">
<div className="flex flex-col gap-2.5">
<header className="subheading flex w-full items-center gap-2">
<h1 className="w-full overflow-hidden text-ellipsis whitespace-nowrap"> </h1>
</header>
<div className="flex flex-col gap-1">
{labels.map((label) => (
<LabelButton
key={label.id}
{...label}
selected={selectedLabelId === label.id}
setSelectedLabelId={setSelectedLabelId}
/>
))}
{image &&
labels.map((label) => (
<LabelButton
key={label.id}
{...label}
selected={selectedLabelId === label.id}
setSelectedLabelId={setSelectedLabelId}
/>
))}
</div>
</div>
<div className="flex p-2.5">
<Button
variant="outlinePrimary"
className="w-full"
onClick={handleAutoLabeling}
>
<Play
size={16}
className="mr-1"
/>
<span> </span>
</Button>
</div>
</div>
);
}

View File

@ -7,9 +7,10 @@ import useCanvasStore from '@/stores/useCanvasStore';
import { Button } from '../ui/button';
import { useEffect } from 'react';
import WorkspaceDropdownMenu from '../WorkspaceDropdownMenu';
import useProjectStore from '@/stores/useProjectStore';
export default function ProjectStructure({ project }: { project: Project }) {
const setProject = useCanvasStore((state) => state.setProject);
const setProject = useProjectStore((state) => state.setProject);
const image = useCanvasStore((state) => state.image);
const { data: folderData, refetch } = useFolderQuery(project.id.toString(), 0);
@ -22,7 +23,7 @@ export default function ProjectStructure({ project }: { project: Project }) {
<div className="flex h-full flex-col overflow-hidden px-1 pb-2">
<header className="flex w-full items-center gap-2 rounded p-1">
<div className="flex w-full min-w-0 items-center gap-1 pr-1">
<h2 className="caption overflow-hidden text-ellipsis whitespace-nowrap">{project.type}</h2>
<h2 className="caption overflow-hidden text-ellipsis whitespace-nowrap text-gray-500">{project.type}</h2>
</div>
<WorkspaceDropdownMenu
projectId={project.id}

View File

@ -5,24 +5,31 @@ import { Project } from '@/types';
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '../ui/select';
import useCanvasStore from '@/stores/useCanvasStore';
import { webPath } from '@/router';
import { Suspense } from 'react';
import { Suspense, useEffect } from 'react';
export default function WorkspaceSidebar({ workspaceName, projects }: { workspaceName: string; projects: Project[] }) {
const { projectId: selectedProjectId } = useParams<{ projectId: string }>();
const { setImage } = useCanvasStore();
const { projectId: selectedProjectId, workspaceId } = useParams<{ projectId: string; workspaceId: string }>();
const selectedProject = projects.find((project) => project.id.toString() === selectedProjectId) || null;
const setSidebarSize = useCanvasStore((state) => state.setSidebarSize);
const navigate = useNavigate();
const { workspaceId } = useParams<{ workspaceId: string }>();
const handleSelectProject = (projectId: string) => {
setImage(null);
navigate(`${webPath.workspace()}/${workspaceId}/${projectId}`);
};
useEffect(() => {
if (!selectedProject) {
setImage(null);
}
}, [selectedProject, setImage]);
return (
<>
<ResizablePanel
minSize={10}
maxSize={35}
defaultSize={20}
defaultSize={15}
className="flex h-full flex-col gap-2 bg-gray-50 p-3"
onResize={(size) => setSidebarSize(size)}
>

View File

@ -1,16 +1,16 @@
import { ImageResponse, Label, Project } from '@/types';
import { ImageResponse, Label } from '@/types';
import { create } from 'zustand';
interface CanvasState {
project: Project | null;
// project: Project | null;
sidebarSize: number;
image: ImageResponse | null;
labels: Label[];
drawState: 'pen' | 'rect' | 'pointer';
selectedLabelId: number | null;
setProject: (project: Project | null) => void;
// setProject: (project: Project | null) => void;
setSidebarSize: (width: number) => void;
setImage: (image: ImageResponse) => void;
setImage: (image: ImageResponse | null) => void;
setLabels: (labels: Label[]) => void;
addLabel: (label: Label) => void;
removeLabel: (labelId: number) => void;
@ -20,13 +20,13 @@ interface CanvasState {
}
const useCanvasStore = create<CanvasState>()((set) => ({
project: null,
// project: null,
sidebarSize: 20,
image: null,
labels: [],
drawState: 'pointer',
selectedLabelId: null,
setProject: (project) => set({ project }),
// setProject: (project) => set({ project }),
setSidebarSize: (width) => set({ sidebarSize: width }),
setImage: (image) => set({ image }),
addLabel: (label: Label) => set((state) => ({ labels: [...state.labels, label] })),

View File

@ -1,22 +0,0 @@
import { create } from 'zustand';
import { FolderResponse } from '@/types';
interface FolderState {
folder: FolderResponse | null;
loading: boolean;
error: string | null;
setFolder: (folder: FolderResponse | null) => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
}
const useFolderStore = create<FolderState>((set) => ({
folder: null,
loading: false,
error: null,
setFolder: (folder) => set({ folder }),
setLoading: (loading) => set({ loading }),
setError: (error) => set({ error }),
}));
export default useFolderStore;

View File

@ -0,0 +1,14 @@
import { create } from 'zustand';
import { Project } from '@/types';
interface ProjectState {
project: Project | null;
setProject: (project: Project | null) => void;
}
const useProjectStore = create<ProjectState>((set) => ({
project: null,
setProject: (project) => set({ project }),
}));
export default useProjectStore;

View File

@ -68,12 +68,14 @@ export interface FolderResponse {
children: ChildFolder[];
}
export type ImageStatus = 'PENDING' | 'IN_PROGRESS' | 'SAVE' | 'REVIEW_REQUEST' | 'COMPLETED';
export interface ImageResponse {
id: number;
imageTitle: string;
imagePath: string;
dataPath: string;
status: 'PENDING' | 'IN_PROGRESS' | 'SAVE' | 'REVIEW_REQUEST' | 'COMPLETED';
status: ImageStatus;
}
// 이미지 이동 및 상태변경 요청 DTO
@ -82,7 +84,7 @@ export interface ImageMoveRequest {
}
export interface ImageStatusChangeRequest {
labelStatus: 'PENDING' | 'IN_PROGRESS' | 'SAVE' | 'REVIEW_REQUEST' | 'COMPLETED';
labelStatus: ImageStatus;
}
// 멤버 관련 DTO