Merge branch 'fe/develop' of https://lab.ssafy.com/s11-s-project/S11P21S002 into fe/refactor/admin-model
This commit is contained in:
commit
aace66275f
@ -6,9 +6,9 @@ export async function reissueToken() {
|
||||
}
|
||||
|
||||
export async function getProfile() {
|
||||
return api
|
||||
.get<MemberResponse>('/auth/profile', {
|
||||
withCredentials: true,
|
||||
})
|
||||
.then(({ data }) => data);
|
||||
return api.get<MemberResponse>('/auth/profile').then(({ data }) => data);
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
return api.post('/auth/logout').then(({ data }) => data);
|
||||
}
|
||||
|
@ -27,9 +27,8 @@ api.interceptors.response.use(
|
||||
return api
|
||||
.post<RefreshTokenResponse>(REFRESH_URL)
|
||||
.then(({ data }) => {
|
||||
console.log(data);
|
||||
const { accessToken } = data;
|
||||
useAuthStore.getState().setLoggedIn(true, accessToken);
|
||||
useAuthStore.getState().setToken(accessToken);
|
||||
if (error.config) {
|
||||
return api(error.config);
|
||||
}
|
||||
|
@ -10,14 +10,6 @@ export async function saveImageLabels(
|
||||
return api.post(`/projects/${projectId}/images/${imageId}/label`, data).then(({ data }) => data);
|
||||
}
|
||||
|
||||
export async function runAutoLabel(projectId: number, memberId: number) {
|
||||
return api
|
||||
.post(
|
||||
`/projects/${projectId}/label/auto`,
|
||||
{},
|
||||
{
|
||||
params: { memberId },
|
||||
}
|
||||
)
|
||||
.then(({ data }) => data);
|
||||
export async function runAutoLabel(projectId: number, modelId = 1) {
|
||||
return api.post(`/projects/${projectId}/auto`, { modelId }).then(({ data }) => data);
|
||||
}
|
||||
|
@ -6,4 +6,9 @@ export default {
|
||||
component: CanvasControlBar,
|
||||
};
|
||||
|
||||
export const Default = () => <CanvasControlBar saveJson={() => {}} />;
|
||||
export const Default = () => (
|
||||
<CanvasControlBar
|
||||
saveJson={() => {}}
|
||||
projectType="segmentation"
|
||||
/>
|
||||
);
|
||||
|
@ -2,16 +2,22 @@ import useCanvasStore from '@/stores/useCanvasStore';
|
||||
import { LucideIcon, MousePointer2, PenTool, Save, Square } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export default function CanvasControlBar({ saveJson }: { saveJson: () => void }) {
|
||||
export default function CanvasControlBar({
|
||||
saveJson,
|
||||
projectType,
|
||||
}: {
|
||||
saveJson: () => void;
|
||||
projectType: 'classification' | 'detection' | 'segmentation';
|
||||
}) {
|
||||
const drawState = useCanvasStore((state) => state.drawState);
|
||||
const setDrawState = useCanvasStore((state) => state.setDrawState);
|
||||
const buttonBaseClassName = 'rounded-lg p-2 transition-colors ';
|
||||
const buttonClassName = 'hover:bg-gray-100';
|
||||
const activeButtonClassName = 'bg-primary stroke-white';
|
||||
|
||||
const controls: { [key: string]: LucideIcon } = {
|
||||
pointer: MousePointer2,
|
||||
rect: Square,
|
||||
pen: PenTool,
|
||||
...(projectType === 'segmentation' ? { pen: PenTool } : { rect: Square }),
|
||||
};
|
||||
|
||||
return (
|
||||
@ -31,7 +37,7 @@ export default function CanvasControlBar({ saveJson }: { saveJson: () => void })
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="h-5 w-0.5 rounded bg-gray-400" />
|
||||
<button
|
||||
className={cn(buttonClassName, buttonBaseClassName)}
|
||||
onClick={saveJson}
|
||||
|
@ -20,7 +20,7 @@ export default function ImageCanvas() {
|
||||
const selectedLabelId = useCanvasStore((state) => state.selectedLabelId);
|
||||
const setSelectedLabelId = useCanvasStore((state) => state.setSelectedLabelId);
|
||||
const sidebarSize = useCanvasStore((state) => state.sidebarSize);
|
||||
const stageWidth = window.innerWidth * ((100 - sidebarSize) / 100) - 280;
|
||||
const stageWidth = window.innerWidth * ((100 - sidebarSize) / 100) - 200;
|
||||
const stageHeight = window.innerHeight - 64;
|
||||
const stageRef = useRef<Konva.Stage>(null);
|
||||
const dragLayerRef = useRef<Konva.Layer>(null);
|
||||
@ -345,7 +345,10 @@ export default function ImageCanvas() {
|
||||
|
||||
<Layer ref={dragLayerRef} />
|
||||
</Stage>
|
||||
<CanvasControlBar saveJson={saveJson} />
|
||||
<CanvasControlBar
|
||||
saveJson={saveJson}
|
||||
projectType={project.type}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div></div>
|
||||
|
@ -8,15 +8,15 @@ import useWorkspaceListQuery from '@/queries/workspaces/useWorkspaceListQuery';
|
||||
import useCreateWorkspaceQuery from '@/queries/workspaces/useCreateWorkspaceQuery';
|
||||
|
||||
export default function WorkspaceBrowseLayout() {
|
||||
const { profile, isLoggedIn } = useAuthStore();
|
||||
const { profile } = useAuthStore();
|
||||
const memberId = profile?.id ?? 0;
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoggedIn || memberId == 0) {
|
||||
if (memberId == 0) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [isLoggedIn, memberId, navigate]);
|
||||
}, [memberId, navigate]);
|
||||
|
||||
const { data: workspacesResponse } = useWorkspaceListQuery(memberId ?? 0);
|
||||
const createWorkspace = useCreateWorkspaceQuery();
|
||||
|
@ -7,12 +7,14 @@ import useCanvasStore from '@/stores/useCanvasStore';
|
||||
import { Button } from '../ui/button';
|
||||
import { useEffect } from 'react';
|
||||
import WorkspaceDropdownMenu from '../WorkspaceDropdownMenu';
|
||||
import useAutoLabelQuery from '@/queries/projects/useAutoLabelQuery';
|
||||
import useProjectStore from '@/stores/useProjectStore';
|
||||
|
||||
export default function ProjectStructure({ project }: { project: Project }) {
|
||||
const setProject = useProjectStore((state) => state.setProject);
|
||||
const image = useCanvasStore((state) => state.image);
|
||||
const { data: folderData, refetch } = useFolderQuery(project.id.toString(), 0);
|
||||
const requestAutoLabel = useAutoLabelQuery();
|
||||
|
||||
useEffect(() => {
|
||||
setProject(project);
|
||||
@ -60,7 +62,17 @@ export default function ProjectStructure({ project }: { project: Project }) {
|
||||
<Button
|
||||
variant="outlinePrimary"
|
||||
className="w-full"
|
||||
onClick={() => console.log('autolabel')}
|
||||
onClick={() => {
|
||||
requestAutoLabel.mutate(
|
||||
{ projectId: project.id },
|
||||
{
|
||||
onSuccess: refetch,
|
||||
onError: () => {
|
||||
alert('자동 레이블링을 요청하는 중 오류가 발생했습니다.');
|
||||
},
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Play
|
||||
size={16}
|
||||
|
@ -4,11 +4,11 @@ import useProfileQuery from '@/queries/auth/useProfileQuery';
|
||||
export default function useHandleOAuthCallback() {
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
const accessToken = queryParams.get('accessToken');
|
||||
const setLoggedIn = useAuthStore((state) => state.setLoggedIn);
|
||||
const setToken = useAuthStore((state) => state.setToken);
|
||||
const setProfile = useAuthStore((state) => state.setProfile);
|
||||
|
||||
if (accessToken) {
|
||||
setLoggedIn(true, accessToken);
|
||||
setToken(accessToken);
|
||||
}
|
||||
|
||||
const { data: profile } = useProfileQuery();
|
||||
|
@ -1,25 +1,12 @@
|
||||
import { useRef } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import GoogleLogo from '@/assets/icons/web_neutral_rd_ctn@1x.png';
|
||||
import useAuthStore from '@/stores/useAuthStore';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { getProfile } from '@/api/authApi';
|
||||
|
||||
const BASE_URL = import.meta.env.VITE_API_URL;
|
||||
|
||||
export default function Home() {
|
||||
const { isLoggedIn, accessToken, setLoggedIn, profile, setProfile } = useAuthStore();
|
||||
const hasFetchedProfile = useRef(false);
|
||||
|
||||
if (!isLoggedIn && !profile && !hasFetchedProfile.current && accessToken) {
|
||||
setLoggedIn(true, accessToken);
|
||||
getProfile().then((data) => {
|
||||
setProfile(data);
|
||||
hasFetchedProfile.current = true;
|
||||
});
|
||||
}
|
||||
const handleGoogleSignIn = () => {
|
||||
window.location.href = `${BASE_URL}/login/oauth2/authorization/google`;
|
||||
};
|
||||
const { accessToken } = useAuthStore();
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center bg-gray-50 p-8">
|
||||
@ -42,9 +29,10 @@ export default function Home() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{!isLoggedIn ? (
|
||||
<button
|
||||
onClick={handleGoogleSignIn}
|
||||
{!accessToken ? (
|
||||
<Link
|
||||
to={`${BASE_URL}/login/oauth2/authorization/google`}
|
||||
replace
|
||||
className="mb-4 transition hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-300 active:opacity-80"
|
||||
>
|
||||
<img
|
||||
@ -52,7 +40,7 @@ export default function Home() {
|
||||
alt="Sign in with Google"
|
||||
className="h-auto w-full"
|
||||
/>
|
||||
</button> // 404 에러 방지
|
||||
</Link> // 404 에러 방지
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
|
@ -4,12 +4,12 @@ import { reissueToken } from '@/api/authApi';
|
||||
|
||||
export default function useReissueTokenQuery() {
|
||||
const queryClient = useQueryClient();
|
||||
const { setLoggedIn } = useAuthStore();
|
||||
const { setToken } = useAuthStore();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: reissueToken,
|
||||
onSuccess: (data) => {
|
||||
setLoggedIn(true, data.accessToken);
|
||||
setToken(data.accessToken);
|
||||
queryClient.invalidateQueries({ queryKey: ['profile'] });
|
||||
},
|
||||
});
|
||||
|
9
frontend/src/queries/projects/useAutoLabelQuery.ts
Normal file
9
frontend/src/queries/projects/useAutoLabelQuery.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { runAutoLabel } from '@/api/lablingApi';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
export default function useAutoLabelQuery() {
|
||||
return useMutation({
|
||||
mutationFn: ({ projectId, modelId = 1 }: { projectId: number; modelId?: number }) =>
|
||||
runAutoLabel(projectId, modelId),
|
||||
});
|
||||
}
|
@ -45,7 +45,6 @@ const router = createBrowserRouter([
|
||||
],
|
||||
},
|
||||
{
|
||||
// FIXME: index에서 오류나지 않게 수정
|
||||
path: webPath.browse(),
|
||||
element: (
|
||||
<Suspense fallback={<PageLayout />}>
|
||||
@ -64,7 +63,6 @@ const router = createBrowserRouter([
|
||||
],
|
||||
},
|
||||
{
|
||||
// FIXME: index에서 오류나지 않게 수정
|
||||
path: `${webPath.workspace()}/:workspaceId`,
|
||||
element: (
|
||||
<Suspense fallback={<div></div>}>
|
||||
|
@ -3,10 +3,9 @@ import { persist } from 'zustand/middleware';
|
||||
import { MemberResponse } from '@/types';
|
||||
|
||||
interface AuthState {
|
||||
isLoggedIn: boolean;
|
||||
accessToken: string;
|
||||
profile: MemberResponse | null;
|
||||
setLoggedIn: (status: boolean, token: string) => void;
|
||||
setToken: (token: string) => void;
|
||||
setProfile: (profile: MemberResponse) => void;
|
||||
clearAuth: () => void;
|
||||
}
|
||||
@ -14,12 +13,11 @@ interface AuthState {
|
||||
const useAuthStore = create<AuthState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
isLoggedIn: false,
|
||||
accessToken: '',
|
||||
profile: null,
|
||||
setLoggedIn: (status: boolean, token: string) => set({ isLoggedIn: status, accessToken: token }),
|
||||
setToken: (token: string) => set({ accessToken: token }),
|
||||
setProfile: (profile: MemberResponse) => set({ profile }),
|
||||
clearAuth: () => set({ isLoggedIn: false, accessToken: '', profile: null }),
|
||||
clearAuth: () => set({ accessToken: '', profile: null }),
|
||||
}),
|
||||
{
|
||||
name: 'auth-storage',
|
||||
|
Loading…
Reference in New Issue
Block a user