히스토리 패널 작업 완료.
This commit is contained in:
@@ -8,7 +8,6 @@ import {
|
|||||||
} from "@univerjs/presets";
|
} from "@univerjs/presets";
|
||||||
import { UniverSheetsCorePreset } from "@univerjs/presets/preset-sheets-core";
|
import { UniverSheetsCorePreset } from "@univerjs/presets/preset-sheets-core";
|
||||||
import UniverPresetSheetsCoreEnUS from "@univerjs/presets/preset-sheets-core/locales/en-US";
|
import UniverPresetSheetsCoreEnUS from "@univerjs/presets/preset-sheets-core/locales/en-US";
|
||||||
import { UniverInstanceType } from "@univerjs/core";
|
|
||||||
|
|
||||||
// Presets CSS import
|
// Presets CSS import
|
||||||
import "@univerjs/presets/lib/styles/preset-sheets-core.css";
|
import "@univerjs/presets/lib/styles/preset-sheets-core.css";
|
||||||
@@ -327,7 +326,7 @@ const TestSheetViewer: React.FC = () => {
|
|||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const mountedRef = useRef<boolean>(false);
|
const mountedRef = useRef<boolean>(false);
|
||||||
|
|
||||||
const [isInitialized, setIsInitialized] = useState<boolean>(false);
|
const [, setIsInitialized] = useState<boolean>(false);
|
||||||
const [showUploadOverlay, setShowUploadOverlay] = useState(true);
|
const [showUploadOverlay, setShowUploadOverlay] = useState(true);
|
||||||
const [isDragOver, setIsDragOver] = useState(false);
|
const [isDragOver, setIsDragOver] = useState(false);
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
@@ -355,12 +354,73 @@ const TestSheetViewer: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHistoryReapply = (entry: HistoryEntry) => {
|
const handleHistoryReapply = useCallback(async (entry: HistoryEntry) => {
|
||||||
// 히스토리 항목 재적용 로직
|
console.log("🔄 히스토리 재적용 시작:", entry);
|
||||||
|
|
||||||
|
// 1. 프롬프트 입력창에 기존 프롬프트 설정
|
||||||
setPrompt(entry.prompt);
|
setPrompt(entry.prompt);
|
||||||
console.log("🔄 히스토리 재적용:", entry);
|
|
||||||
// TODO: 실제 액션 재실행 로직 구현
|
// 2. 확인 대화상자
|
||||||
};
|
const confirmReapply = window.confirm(
|
||||||
|
`다음 프롬프트를 다시 실행하시겠습니까?\n\n"${entry.prompt}"\n\n범위: ${entry.range} | 시트: ${entry.sheetName}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!confirmReapply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 재적용 히스토리 항목 생성
|
||||||
|
const reapplyHistoryId = addHistoryEntry(
|
||||||
|
`[재적용] ${entry.prompt}`,
|
||||||
|
entry.range,
|
||||||
|
entry.sheetName,
|
||||||
|
[],
|
||||||
|
"pending",
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 4. AI 프로세서 실행
|
||||||
|
const result = await aiProcessor.processPrompt(entry.prompt, true);
|
||||||
|
|
||||||
|
// 5. 결과에 따라 히스토리 업데이트
|
||||||
|
if (result.success) {
|
||||||
|
updateHistoryEntry(reapplyHistoryId, {
|
||||||
|
status: "success",
|
||||||
|
actions:
|
||||||
|
result.appliedCells?.map((cell) => ({
|
||||||
|
type: "formula" as const,
|
||||||
|
range: cell,
|
||||||
|
formula: `=재적용 수식`, // TODO: 실제 수식 정보 저장
|
||||||
|
})) || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 성공 시 팝업 제거 (히스토리 패널에서 확인 가능)
|
||||||
|
console.log(`✅ 재적용 성공: ${result.message}`);
|
||||||
|
} else {
|
||||||
|
updateHistoryEntry(reapplyHistoryId, {
|
||||||
|
status: "error",
|
||||||
|
error: result.message,
|
||||||
|
actions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 실패 알림
|
||||||
|
alert(`❌ 재적용 실패: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 6. 예외 처리
|
||||||
|
const errorMessage =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "알 수 없는 오류가 발생했습니다.";
|
||||||
|
updateHistoryEntry(reapplyHistoryId, {
|
||||||
|
status: "error",
|
||||||
|
error: errorMessage,
|
||||||
|
actions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
alert(`❌ 재적용 중 오류: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 새 히스토리 항목 추가 함수
|
// 새 히스토리 항목 추가 함수
|
||||||
const addHistoryEntry = (
|
const addHistoryEntry = (
|
||||||
@@ -383,8 +443,87 @@ const TestSheetViewer: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
setHistory((prev) => [newEntry, ...prev]); // 최신 항목을 맨 위에
|
setHistory((prev) => [newEntry, ...prev]); // 최신 항목을 맨 위에
|
||||||
|
return newEntry.id; // 히스토리 ID 반환하여 나중에 업데이트 가능
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 기존 히스토리 항목 업데이트 함수
|
||||||
|
const updateHistoryEntry = (
|
||||||
|
id: string,
|
||||||
|
updates: Partial<Omit<HistoryEntry, "id" | "timestamp">>,
|
||||||
|
) => {
|
||||||
|
setHistory((prev) =>
|
||||||
|
prev.map((entry) => (entry.id === id ? { ...entry, ...updates } : entry)),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// AI 프롬프트 실행 핸들러 (히스토리 연동)
|
||||||
|
const handlePromptExecute = useCallback(async () => {
|
||||||
|
if (!prompt.trim()) {
|
||||||
|
alert("프롬프트를 입력해주세요.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentRange = appStore.selectedRange
|
||||||
|
? rangeToAddress(appStore.selectedRange.range)
|
||||||
|
: "A1";
|
||||||
|
const currentSheetName = "Sheet1"; // TODO: 실제 시트명 가져오기
|
||||||
|
|
||||||
|
// 1. 히스토리에 pending 상태로 추가
|
||||||
|
const historyId = addHistoryEntry(
|
||||||
|
prompt.trim(),
|
||||||
|
currentRange,
|
||||||
|
currentSheetName,
|
||||||
|
[],
|
||||||
|
"pending",
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2. AI 프로세서 실행
|
||||||
|
const result = await aiProcessor.processPrompt(prompt.trim(), true);
|
||||||
|
|
||||||
|
// 3. 결과에 따라 히스토리 업데이트
|
||||||
|
if (result.success) {
|
||||||
|
updateHistoryEntry(historyId, {
|
||||||
|
status: "success",
|
||||||
|
actions:
|
||||||
|
result.appliedCells?.map((cell) => ({
|
||||||
|
type: "formula" as const,
|
||||||
|
range: cell,
|
||||||
|
formula: `=수식`, // TODO: 실제 수식 정보 저장
|
||||||
|
})) || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 성공 시 팝업 제거 (히스토리 패널에서 확인 가능)
|
||||||
|
console.log(`✅ ${result.message}`);
|
||||||
|
} else {
|
||||||
|
updateHistoryEntry(historyId, {
|
||||||
|
status: "error",
|
||||||
|
error: result.message,
|
||||||
|
actions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 실패 알림
|
||||||
|
alert(`❌ ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 4. 예외 처리
|
||||||
|
const errorMessage =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: "알 수 없는 오류가 발생했습니다.";
|
||||||
|
updateHistoryEntry(historyId, {
|
||||||
|
status: "error",
|
||||||
|
error: errorMessage,
|
||||||
|
actions: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
alert(`❌ 처리 중 오류: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 프롬프트 입력창 초기화
|
||||||
|
setPrompt("");
|
||||||
|
}, [prompt, appStore.selectedRange]);
|
||||||
|
|
||||||
// Univer 초기화 함수 (Presets 기반)
|
// Univer 초기화 함수 (Presets 기반)
|
||||||
const initializeUniver = useCallback(
|
const initializeUniver = useCallback(
|
||||||
async (workbookData?: any) => {
|
async (workbookData?: any) => {
|
||||||
@@ -769,8 +908,10 @@ const TestSheetViewer: React.FC = () => {
|
|||||||
<PromptInput
|
<PromptInput
|
||||||
value={prompt}
|
value={prompt}
|
||||||
onChange={(e) => setPrompt(e.target.value)}
|
onChange={(e) => setPrompt(e.target.value)}
|
||||||
|
onExecute={handlePromptExecute}
|
||||||
onHistoryToggle={handleHistoryToggle}
|
onHistoryToggle={handleHistoryToggle}
|
||||||
historyCount={history.length}
|
historyCount={history.length}
|
||||||
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 히스토리 패널 - 파일이 업로드된 후에만 표시 */}
|
{/* 히스토리 패널 - 파일이 업로드된 후에만 표시 */}
|
||||||
|
|||||||
@@ -24,18 +24,16 @@ const PromptInput: React.FC<PromptInputProps> = ({
|
|||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
onExecute,
|
onExecute,
|
||||||
disabled = true,
|
disabled: _disabled = true,
|
||||||
maxLength = 500,
|
maxLength = 500,
|
||||||
onHistoryToggle,
|
onHistoryToggle,
|
||||||
historyCount,
|
historyCount,
|
||||||
}) => {
|
}) => {
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
const [showCellInsertFeedback, setShowCellInsertFeedback] = useState(false);
|
const [, setShowCellInsertFeedback] = useState(false);
|
||||||
const [lastInsertedCell, setLastInsertedCell] = useState<string | null>(null);
|
const [, setLastInsertedCell] = useState<string | null>(null);
|
||||||
const [currentSelectedCell, setCurrentSelectedCell] = useState<string | null>(
|
const [, setCurrentSelectedCell] = useState<string | null>(null);
|
||||||
null,
|
const [, setProcessingMessage] = useState<string>("");
|
||||||
);
|
|
||||||
const [processingMessage, setProcessingMessage] = useState<string>("");
|
|
||||||
|
|
||||||
const cellAddressToInsert = useAppStore((state) => state.cellAddressToInsert);
|
const cellAddressToInsert = useAppStore((state) => state.cellAddressToInsert);
|
||||||
const setCellAddressToInsert = useAppStore(
|
const setCellAddressToInsert = useAppStore(
|
||||||
@@ -53,7 +51,7 @@ const PromptInput: React.FC<PromptInputProps> = ({
|
|||||||
}, [cellAddressToInsert]);
|
}, [cellAddressToInsert]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 전송하기 버튼 클릭 핸들러
|
* 전송하기 버튼 클릭 핸들러 - 상위 컴포넌트 onExecute 사용 또는 기본 로직
|
||||||
*/
|
*/
|
||||||
const handleExecute = async () => {
|
const handleExecute = async () => {
|
||||||
if (!value.trim()) {
|
if (!value.trim()) {
|
||||||
@@ -66,6 +64,14 @@ const PromptInput: React.FC<PromptInputProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 상위 컴포넌트에서 onExecute를 전달받은 경우 해당 함수 사용
|
||||||
|
if (onExecute) {
|
||||||
|
console.log("🚀 상위 컴포넌트 onExecute 함수 호출");
|
||||||
|
await onExecute();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 폴백: 기본 AI 프로세서 직접 호출
|
||||||
setProcessingMessage("AI가 요청을 처리하고 있습니다...");
|
setProcessingMessage("AI가 요청을 처리하고 있습니다...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "./card";
|
import { Card, CardContent, CardHeader } from "./card";
|
||||||
import { Button } from "./button";
|
import { Button } from "./button";
|
||||||
import type { HistoryPanelProps, HistoryEntry } from "../../types/ai";
|
import type { HistoryPanelProps, HistoryEntry } from "../../types/ai";
|
||||||
import { cn } from "../../lib/utils";
|
import { cn } from "../../lib/utils";
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export default defineConfig({
|
|||||||
"@univerjs/sheets-formula-ui",
|
"@univerjs/sheets-formula-ui",
|
||||||
"@univerjs/sheets-numfmt",
|
"@univerjs/sheets-numfmt",
|
||||||
"@univerjs/sheets-numfmt-ui",
|
"@univerjs/sheets-numfmt-ui",
|
||||||
"@univerjs/facade",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ export default defineConfig({
|
|||||||
"@univerjs/sheets-numfmt-ui",
|
"@univerjs/sheets-numfmt-ui",
|
||||||
],
|
],
|
||||||
"univer-docs": ["@univerjs/docs", "@univerjs/docs-ui"],
|
"univer-docs": ["@univerjs/docs", "@univerjs/docs-ui"],
|
||||||
"univer-ui": ["@univerjs/ui", "@univerjs/facade"],
|
"univer-ui": ["@univerjs/ui"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user