diff --git a/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx b/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx index 23301657..47cf7c95 100644 --- a/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx +++ b/frontend/lib/registry/components/v2-timeline-scheduler/TimelineSchedulerComponent.tsx @@ -85,11 +85,31 @@ export function TimelineSchedulerComponent({ const cellWidthConfig = config.cellWidth || defaultTimelineSchedulerConfig.cellWidth!; const cellWidth = cellWidthConfig[zoomLevel] || 60; + // 리소스가 없으면 스케줄의 resourceId로 자동 생성 + const effectiveResources = useMemo(() => { + if (resources.length > 0) { + return resources; + } + + // 스케줄에서 고유한 resourceId 추출하여 자동 리소스 생성 + const uniqueResourceIds = new Set(); + schedules.forEach((schedule) => { + if (schedule.resourceId) { + uniqueResourceIds.add(schedule.resourceId); + } + }); + + return Array.from(uniqueResourceIds).map((id) => ({ + id, + name: id, // resourceId를 이름으로 사용 + })); + }, [resources, schedules]); + // 리소스별 스케줄 그룹화 const schedulesByResource = useMemo(() => { const grouped = new Map(); - resources.forEach((resource) => { + effectiveResources.forEach((resource) => { grouped.set(resource.id, []); }); @@ -99,7 +119,7 @@ export function TimelineSchedulerComponent({ list.push(schedule); } else { // 리소스가 없는 스케줄은 첫 번째 리소스에 할당 - const firstResource = resources[0]; + const firstResource = effectiveResources[0]; if (firstResource) { const firstList = grouped.get(firstResource.id); if (firstList) { @@ -110,7 +130,7 @@ export function TimelineSchedulerComponent({ }); return grouped; - }, [schedules, resources]); + }, [schedules, effectiveResources]); // 줌 레벨 변경 const handleZoomIn = useCallback(() => { @@ -132,12 +152,12 @@ export function TimelineSchedulerComponent({ // 스케줄 클릭 핸들러 const handleScheduleClick = useCallback( (schedule: ScheduleItem) => { - const resource = resources.find((r) => r.id === schedule.resourceId); + const resource = effectiveResources.find((r) => r.id === schedule.resourceId); if (resource && onScheduleClick) { onScheduleClick({ schedule, resource }); } }, - [resources, onScheduleClick] + [effectiveResources, onScheduleClick] ); // 빈 셀 클릭 핸들러 @@ -195,13 +215,13 @@ export function TimelineSchedulerComponent({ // 추가 버튼 클릭 const handleAddClick = useCallback(() => { - if (onAddSchedule && resources.length > 0) { + if (onAddSchedule && effectiveResources.length > 0) { onAddSchedule( - resources[0].id, + effectiveResources[0].id, new Date().toISOString().split("T")[0] ); } - }, [onAddSchedule, resources]); + }, [onAddSchedule, effectiveResources]); // 디자인 모드 플레이스홀더 if (isDesignMode) { @@ -250,8 +270,8 @@ export function TimelineSchedulerComponent({ ); } - // 리소스 없음 - if (resources.length === 0) { + // 리소스 없음 (스케줄도 없는 경우에만 표시) + if (effectiveResources.length === 0) { return (
-

리소스가 없습니다

-

리소스 테이블을 설정하세요

+

스케줄 데이터가 없습니다

+

스케줄 테이블에 데이터를 추가하세요

); @@ -385,7 +405,7 @@ export function TimelineSchedulerComponent({ {/* 리소스 행들 */}
- {resources.map((resource) => ( + {effectiveResources.map((resource) => (