Compare commits

...
3 changed files with 73 additions and 16 deletions
@@ -87,6 +87,7 @@ export function createToolFlow<TParams = unknown>(config: ToolFlowConfig<TParams
{config.steps.map((stepConfig) =>
steps.create(stepConfig.title, {
isVisible: stepConfig.isVisible,
isCollapsed: stepConfig.isCollapsed,
onCollapsedClick: stepConfig.onCollapsedClick,
tooltip: stepConfig.tooltip
}, stepConfig.content)
@@ -47,6 +47,10 @@ export function useBaseTool<TParams, TParamsHook extends BaseParametersHook<TPar
const { selectedFiles } = useFileSelection();
const previousFileCount = useRef(selectedFiles.length);
// Prevent reset immediately after operation completes (when consumeFiles auto-selects outputs)
const skipNextSelectionResetRef = useRef(false);
const previousSelectionRef = useRef<string>('');
// Tool-specific hooks
const params = useParams();
const operation = useOperation();
@@ -54,19 +58,45 @@ export function useBaseTool<TParams, TParamsHook extends BaseParametersHook<TPar
// Endpoint validation using parameters hook
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(params.getEndpointName());
// Standard computed state - defined early so it's available in useEffects
const hasFiles = selectedFiles.length >= minFiles;
const hasResults = operation.files.length > 0 || operation.downloadUrl !== null;
const settingsCollapsed = !hasFiles || hasResults;
// Reset results when parameters change
useEffect(() => {
operation.resetResults();
onPreviewFile?.(null);
}, [params.parameters]);
// Reset results when selected files change
// When operation completes, flag the next selection change to skip reset
// (consumeFiles auto-selects outputs immediately after processing)
useEffect(() => {
if (selectedFiles.length > 0) {
operation.resetResults();
onPreviewFile?.(null);
if (hasResults) {
skipNextSelectionResetRef.current = true;
}
}, [selectedFiles.length]);
}, [hasResults]);
// Reset results when user manually changes file selection
useEffect(() => {
if (selectedFiles.length === 0) return;
const currentSelection = selectedFiles.map(f => f.fileId).sort().join(',');
if (currentSelection === previousSelectionRef.current) return; // No change
// Skip reset if this is the auto-selection after operation completed
if (skipNextSelectionResetRef.current) {
skipNextSelectionResetRef.current = false;
previousSelectionRef.current = currentSelection;
return;
}
// User manually selected different files - reset results
previousSelectionRef.current = currentSelection;
operation.resetResults();
onPreviewFile?.(null);
}, [selectedFiles]);
// Reset parameters when transitioning from 0 files to at least 1 file
useEffect(() => {
@@ -101,6 +131,7 @@ export function useBaseTool<TParams, TParamsHook extends BaseParametersHook<TPar
}, [onPreviewFile, toolName]);
const handleSettingsReset = useCallback(() => {
skipNextSelectionResetRef.current = false;
operation.resetResults();
onPreviewFile?.(null);
}, [operation, onPreviewFile]);
@@ -110,11 +141,6 @@ export function useBaseTool<TParams, TParamsHook extends BaseParametersHook<TPar
onPreviewFile?.(null);
}, [operation, onPreviewFile]);
// Standard computed state
const hasFiles = selectedFiles.length >= minFiles;
const hasResults = operation.files.length > 0 || operation.downloadUrl !== null;
const settingsCollapsed = !hasFiles || hasResults;
return {
// File management
selectedFiles,
+36 -6
View File
@@ -23,6 +23,10 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(convertParams.getEndpointName());
// Prevent reset immediately after operation completes (when consumeFiles auto-selects outputs)
const skipNextSelectionResetRef = useRef(false);
const previousSelectionRef = useRef<string>('');
const scrollToBottom = () => {
if (scrollContainerRef.current) {
scrollContainerRef.current.scrollTo({
@@ -33,24 +37,49 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
};
const hasFiles = selectedFiles.length > 0;
const hasResults = convertOperation.downloadUrl !== null;
const hasResults = convertOperation.files.length > 0 || convertOperation.downloadUrl !== null;
const settingsCollapsed = hasResults;
// When operation completes, flag the next selection change to skip reset
useEffect(() => {
if (hasResults) {
skipNextSelectionResetRef.current = true;
}
}, [hasResults]);
// Reset results when user manually changes file selection
useEffect(() => {
const currentSelection = selectedFiles.map(f => f.fileId).sort().join(',');
if (currentSelection === previousSelectionRef.current) return; // No change
// Skip reset if this is the auto-selection after operation completed
// Don't analyze file types - would change parameters and trigger another reset
if (skipNextSelectionResetRef.current) {
skipNextSelectionResetRef.current = false;
previousSelectionRef.current = currentSelection;
return;
}
// User manually selected different files
if (selectedFiles.length > 0) {
previousSelectionRef.current = currentSelection;
convertParams.analyzeFileTypes(selectedFiles);
if (hasResults) {
convertOperation.resetResults();
onPreviewFile?.(null);
}
} else {
// Only reset when there are no active files at all
// If there are active files but no selected files, keep current format (user filtered by format)
previousSelectionRef.current = '';
if (activeFiles.length === 0) {
convertParams.resetParameters();
}
}
}, [selectedFiles, activeFiles, convertParams.analyzeFileTypes, convertParams.resetParameters]);
}, [selectedFiles]);
useEffect(() => {
// Only clear results if we're not currently processing and parameters changed
if (!convertOperation.isLoading) {
// Reset when user changes conversion parameters (but not during operation)
if (!convertOperation.isLoading && !skipNextSelectionResetRef.current) {
convertOperation.resetResults();
onPreviewFile?.(null);
}
@@ -87,6 +116,7 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
};
const handleSettingsReset = () => {
skipNextSelectionResetRef.current = false;
convertOperation.resetResults();
onPreviewFile?.(null);
};