merge headache

This commit is contained in:
Connor Yoh 2025-08-21 19:12:12 +01:00
parent 14f6cf76e2
commit b2822c1d43
8 changed files with 96 additions and 88 deletions

View File

@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
import { Button, Text, Stack, Group, Card, Progress } from "@mantine/core"; import { Button, Text, Stack, Group, Card, Progress } from "@mantine/core";
import PlayArrowIcon from "@mui/icons-material/PlayArrow"; import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import CheckIcon from "@mui/icons-material/Check"; import CheckIcon from "@mui/icons-material/Check";
import { useFileSelection } from "../../../contexts/FileSelectionContext"; import { useFileSelection } from "../../../contexts/FileContext";
import { useFlatToolRegistry } from "../../../data/useTranslatedToolRegistry"; import { useFlatToolRegistry } from "../../../data/useTranslatedToolRegistry";
interface AutomationRunProps { interface AutomationRunProps {

View File

@ -1,15 +1,22 @@
import React from 'react'; import React, { useCallback } from 'react';
import { Stack, Text, Divider, Card, Group } from '@mantine/core'; import { Stack, Text, Divider, Card, Group } from '@mantine/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSuggestedTools } from '../../../hooks/useSuggestedTools'; import { useSuggestedTools } from '../../../hooks/useSuggestedTools';
import { useToolNavigation } from '../../../contexts/ToolNavigationContext'; import { useNavigationActions, useNavigationState, type ModeType } from '../../../contexts/NavigationContext';
export interface SuggestedToolsSectionProps {} export interface SuggestedToolsSectionProps {}
export function SuggestedToolsSection(): React.ReactElement { export function SuggestedToolsSection(): React.ReactElement {
const { t } = useTranslation(); const { t } = useTranslation();
const { handleToolSelect, selectedToolKey } = useToolNavigation(); const { actions } = useNavigationActions();
const suggestedTools = useSuggestedTools(selectedToolKey, handleToolSelect); const { currentMode } = useNavigationState();
// Create handleToolSelect function that navigates to the tool
const handleToolSelect = useCallback((toolId: string) => {
actions.setMode(toolId as ModeType);
}, [actions]);
const suggestedTools = useSuggestedTools(currentMode, handleToolSelect);
return ( return (
<Stack gap="md"> <Stack gap="md">

View File

@ -1,85 +1,85 @@
/** // /**
* ToolNavigationContext - Handles tool selection and navigation without tool registry // * ToolNavigationContext - Handles tool selection and navigation without tool registry
* This breaks the circular dependency by not importing the tool registry // * This breaks the circular dependency by not importing the tool registry
*/ // */
import React, { createContext, useContext, useState, useCallback } from 'react'; // import React, { createContext, useContext, useState, useCallback } from 'react';
import { useFileContext } from './FileContext'; // import { useFileContext } from './FileContext';
// Navigation state interface // // Navigation state interface
interface ToolNavigationState { // interface ToolNavigationState {
selectedToolKey: string | null; // selectedToolKey: string | null;
} // }
// Context value interface // // Context value interface
interface ToolNavigationContextValue extends ToolNavigationState { // interface ToolNavigationContextValue extends ToolNavigationState {
// Navigation Actions // // Navigation Actions
selectTool: (toolKey: string) => void; // selectTool: (toolKey: string) => void;
clearToolSelection: () => void; // clearToolSelection: () => void;
handleToolSelect: (toolId: string) => void; // handleToolSelect: (toolId: string) => void;
} // }
const ToolNavigationContext = createContext<ToolNavigationContextValue | undefined>(undefined); // const ToolNavigationContext = createContext<ToolNavigationContextValue | undefined>(undefined);
// Provider component // // Provider component
interface ToolNavigationProviderProps { // interface ToolNavigationProviderProps {
children: React.ReactNode; // children: React.ReactNode;
} // }
export function ToolNavigationProvider({ children }: ToolNavigationProviderProps) { // export function ToolNavigationProvider({ children }: ToolNavigationProviderProps) {
const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null); // const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null);
const { setCurrentView } = useFileContext(); // const { setCurrentView } = useFileContext();
const selectTool = useCallback((toolKey: string) => { // const selectTool = useCallback((toolKey: string) => {
setSelectedToolKey(toolKey); // setSelectedToolKey(toolKey);
}, []); // }, []);
const clearToolSelection = useCallback(() => { // const clearToolSelection = useCallback(() => {
setSelectedToolKey(null); // setSelectedToolKey(null);
}, []); // }, []);
const handleToolSelect = useCallback((toolId: string) => { // const handleToolSelect = useCallback((toolId: string) => {
// Handle special cases // // Handle special cases
if (toolId === 'allTools') { // if (toolId === 'allTools') {
clearToolSelection(); // clearToolSelection();
return; // return;
} // }
selectTool(toolId); // selectTool(toolId);
setCurrentView('fileEditor'); // setCurrentView('fileEditor');
}, [selectTool, setCurrentView, clearToolSelection]); // }, [selectTool, setCurrentView, clearToolSelection]);
const contextValue: ToolNavigationContextValue = { // const contextValue: ToolNavigationContextValue = {
selectedToolKey, // selectedToolKey,
selectTool, // selectTool,
clearToolSelection, // clearToolSelection,
handleToolSelect // handleToolSelect
}; // };
return ( // return (
<ToolNavigationContext.Provider value={contextValue}> // <ToolNavigationContext.Provider value={contextValue}>
{children} // {children}
</ToolNavigationContext.Provider> // </ToolNavigationContext.Provider>
); // );
} // }
// Custom hook to use the context // // Custom hook to use the context
export function useToolNavigation(): ToolNavigationContextValue { // export function useToolNavigation(): ToolNavigationContextValue {
const context = useContext(ToolNavigationContext); // const context = useContext(ToolNavigationContext);
if (!context) { // if (!context) {
// During development hot reload, temporarily return a safe fallback // // During development hot reload, temporarily return a safe fallback
if (process.env.NODE_ENV === 'development') { // if (process.env.NODE_ENV === 'development') {
console.warn('ToolNavigationContext temporarily unavailable during hot reload, using fallback'); // console.warn('ToolNavigationContext temporarily unavailable during hot reload, using fallback');
return { // return {
selectedToolKey: null, // selectedToolKey: null,
selectTool: () => {}, // selectTool: () => {},
clearToolSelection: () => {}, // clearToolSelection: () => {},
handleToolSelect: () => {} // handleToolSelect: () => {}
} as ToolNavigationContextValue; // } as ToolNavigationContextValue;
} // }
throw new Error('useToolNavigation must be used within a ToolNavigationProvider'); // throw new Error('useToolNavigation must be used within a ToolNavigationProvider');
} // }
return context; // return context;
} // }

View File

@ -26,7 +26,7 @@ import { ToolOperationConfig, ToolOperationHook, useToolOperation } from '../sha
describe('useAddPasswordOperation', () => { describe('useAddPasswordOperation', () => {
const mockUseToolOperation = vi.mocked(useToolOperation); const mockUseToolOperation = vi.mocked(useToolOperation);
const getToolConfig = (): ToolOperationConfig<AddPasswordFullParameters> => mockUseToolOperation.mock.calls[0][0]; const getToolConfig = (): ToolOperationConfig<AddPasswordFullParameters> => mockUseToolOperation.mock.calls[0][0] as ToolOperationConfig<AddPasswordFullParameters>;
const mockToolOperationReturn: ToolOperationHook<unknown> = { const mockToolOperationReturn: ToolOperationHook<unknown> = {
files: [], files: [],

View File

@ -25,7 +25,7 @@ import { ToolOperationConfig, ToolOperationHook, useToolOperation } from '../sha
describe('useChangePermissionsOperation', () => { describe('useChangePermissionsOperation', () => {
const mockUseToolOperation = vi.mocked(useToolOperation); const mockUseToolOperation = vi.mocked(useToolOperation);
const getToolConfig = (): ToolOperationConfig<ChangePermissionsParameters> => mockUseToolOperation.mock.calls[0][0]; const getToolConfig = (): ToolOperationConfig<ChangePermissionsParameters> => mockUseToolOperation.mock.calls[0][0] as ToolOperationConfig<ChangePermissionsParameters>;
const mockToolOperationReturn: ToolOperationHook<unknown> = { const mockToolOperationReturn: ToolOperationHook<unknown> = {
files: [], files: [],

View File

@ -52,8 +52,8 @@ export const buildOCRFormData = (parameters: OCRParameters, file: File): FormDat
return formData; return formData;
}; };
// Static response handler for OCR - can be used by automation executor // Static response handler for OCR - can be used by automation executor
export const ocrResponseHandler = async (blob: Blob, originalFiles: File[], extractZipFiles: (blob: Blob) => Promise<{ success: boolean; extractedFiles: File[]; errors: string[] }>): Promise<File[]> => { export const ocrResponseHandler = async (blob: Blob, originalFiles: File[], extractZipFiles: (blob: Blob) => Promise<File[]>): Promise<File[]> => {
const headBuf = await blob.slice(0, 8).arrayBuffer(); const headBuf = await blob.slice(0, 8).arrayBuffer();
const head = new TextDecoder().decode(new Uint8Array(headBuf)); const head = new TextDecoder().decode(new Uint8Array(headBuf));
@ -61,8 +61,8 @@ export const ocrResponseHandler = async (blob: Blob, originalFiles: File[], extr
if (head.startsWith('PK')) { if (head.startsWith('PK')) {
const base = stripExt(originalFiles[0].name); const base = stripExt(originalFiles[0].name);
try { try {
const result = await extractZipFiles(blob); const extractedFiles = await extractZipFiles(blob);
if (result.success && result.extractedFiles.length > 0) return result.extractedFiles; if (extractedFiles.length > 0) return extractedFiles;
} catch { /* ignore and try local extractor */ } } catch { /* ignore and try local extractor */ }
try { try {
const local = await extractZipFile(blob); // local fallback const local = await extractZipFile(blob); // local fallback
@ -108,7 +108,9 @@ export const useOCROperation = () => {
// OCR-specific parsing: ZIP (sidecar) vs PDF vs HTML error // OCR-specific parsing: ZIP (sidecar) vs PDF vs HTML error
const responseHandler = useCallback(async (blob: Blob, originalFiles: File[]): Promise<File[]> => { const responseHandler = useCallback(async (blob: Blob, originalFiles: File[]): Promise<File[]> => {
return ocrResponseHandler(blob, originalFiles, extractZipFiles); // extractZipFiles from useToolResources already returns File[] directly
const simpleExtractZipFiles = extractZipFiles;
return ocrResponseHandler(blob, originalFiles, simpleExtractZipFiles);
}, [extractZipFiles]); }, [extractZipFiles]);
const ocrConfig: ToolOperationConfig<OCRParameters> = { const ocrConfig: ToolOperationConfig<OCRParameters> = {

View File

@ -25,7 +25,7 @@ import { ToolOperationConfig, ToolOperationHook, useToolOperation } from '../sha
describe('useRemovePasswordOperation', () => { describe('useRemovePasswordOperation', () => {
const mockUseToolOperation = vi.mocked(useToolOperation); const mockUseToolOperation = vi.mocked(useToolOperation);
const getToolConfig = (): ToolOperationConfig<RemovePasswordParameters> => mockUseToolOperation.mock.calls[0][0]; const getToolConfig = (): ToolOperationConfig<RemovePasswordParameters> => mockUseToolOperation.mock.calls[0][0] as ToolOperationConfig<RemovePasswordParameters>;
const mockToolOperationReturn: ToolOperationHook<unknown> = { const mockToolOperationReturn: ToolOperationHook<unknown> = {
files: [], files: [],

View File

@ -1,7 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useFileContext } from "../contexts/FileContext"; import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext"; import { useFileSelection } from "../contexts/FileContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow"; import { createToolFlow } from "../components/tools/shared/createToolFlow";
import { createFilesToolStep } from "../components/tools/shared/FilesToolStep"; import { createFilesToolStep } from "../components/tools/shared/FilesToolStep";
@ -16,8 +16,7 @@ import { useSavedAutomations } from "../hooks/tools/automate/useSavedAutomations
const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { setCurrentMode } = useFileContext(); const { selectedFiles } = useFileSelection();
const { selectedFiles } = useToolFileSelection();
const [currentStep, setCurrentStep] = useState<'selection' | 'creation' | 'run'>('selection'); const [currentStep, setCurrentStep] = useState<'selection' | 'creation' | 'run'>('selection');
const [stepData, setStepData] = useState<any>({}); const [stepData, setStepData] = useState<any>({});