mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Circular dependencies
This commit is contained in:
parent
03df9a260b
commit
a85ab4a832
@ -4,6 +4,7 @@ import { FileContextProvider } from "./contexts/FileContext";
|
||||
import { FilesModalProvider } from "./contexts/FilesModalContext";
|
||||
import { FileSelectionProvider } from "./contexts/FileSelectionContext";
|
||||
import { ToolWorkflowProvider } from "./contexts/ToolWorkflowContext";
|
||||
import { ToolNavigationProvider } from "./contexts/ToolNavigationContext";
|
||||
import { SidebarProvider } from "./contexts/SidebarContext";
|
||||
import ErrorBoundary from "./components/shared/ErrorBoundary";
|
||||
import HomePage from "./pages/HomePage";
|
||||
@ -36,11 +37,13 @@ export default function App() {
|
||||
<FileContextProvider enableUrlSync={true} enablePersistence={true}>
|
||||
<FilesModalProvider>
|
||||
<FileSelectionProvider>
|
||||
<ToolWorkflowProvider>
|
||||
<SidebarProvider>
|
||||
<HomePage />
|
||||
</SidebarProvider>
|
||||
</ToolWorkflowProvider>
|
||||
<ToolNavigationProvider>
|
||||
<ToolWorkflowProvider>
|
||||
<SidebarProvider>
|
||||
<HomePage />
|
||||
</SidebarProvider>
|
||||
</ToolWorkflowProvider>
|
||||
</ToolNavigationProvider>
|
||||
</FileSelectionProvider>
|
||||
</FilesModalProvider>
|
||||
</FileContextProvider>
|
||||
|
@ -12,10 +12,9 @@ import {
|
||||
} from '@mantine/core';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry';
|
||||
import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
||||
import ToolConfigurationModal from './ToolConfigurationModal';
|
||||
import ToolSelector from './ToolSelector';
|
||||
|
||||
@ -24,6 +23,7 @@ interface AutomationCreationProps {
|
||||
existingAutomation?: any;
|
||||
onBack: () => void;
|
||||
onComplete: (automation: any) => void;
|
||||
toolRegistry: Record<string, ToolRegistryEntry>; // Pass registry as prop to break circular dependency
|
||||
}
|
||||
|
||||
interface AutomationTool {
|
||||
@ -34,9 +34,8 @@ interface AutomationTool {
|
||||
parameters?: any;
|
||||
}
|
||||
|
||||
export default function AutomationCreation({ mode, existingAutomation, onBack, onComplete }: AutomationCreationProps) {
|
||||
export default function AutomationCreation({ mode, existingAutomation, onBack, onComplete, toolRegistry }: AutomationCreationProps) {
|
||||
const { t } = useTranslation();
|
||||
const toolRegistry = useFlatToolRegistry();
|
||||
|
||||
const [automationName, setAutomationName] = useState('');
|
||||
const [selectedTools, setSelectedTools] = useState<AutomationTool[]>([]);
|
||||
@ -157,6 +156,7 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o
|
||||
<ToolSelector
|
||||
onSelect={addTool}
|
||||
excludeTools={['automate']}
|
||||
toolRegistry={toolRegistry}
|
||||
/>
|
||||
|
||||
{/* Selected Tools */}
|
||||
|
@ -14,8 +14,6 @@ import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import { useToolWorkflow } from '../../../contexts/ToolWorkflowContext';
|
||||
|
||||
interface ToolConfigurationModalProps {
|
||||
opened: boolean;
|
||||
tool: {
|
||||
@ -30,7 +28,6 @@ interface ToolConfigurationModalProps {
|
||||
|
||||
export default function ToolConfigurationModal({ opened, tool, onSave, onCancel }: ToolConfigurationModalProps) {
|
||||
const { t } = useTranslation();
|
||||
const { toolRegistry } = useToolWorkflow();
|
||||
|
||||
const [parameters, setParameters] = useState<any>({});
|
||||
const [isValid, setIsValid] = useState(true);
|
||||
|
@ -5,18 +5,17 @@ import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
||||
import { useToolSections } from '../../../hooks/useToolSections';
|
||||
import { renderToolButtons } from '../shared/renderToolButtons';
|
||||
import ToolSearch from '../toolPicker/ToolSearch';
|
||||
import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry';
|
||||
|
||||
interface ToolSelectorProps {
|
||||
onSelect: (toolKey: string) => void;
|
||||
excludeTools?: string[];
|
||||
toolRegistry: Record<string, ToolRegistryEntry>; // Pass registry as prop to break circular dependency
|
||||
}
|
||||
|
||||
export default function ToolSelector({ onSelect, excludeTools = [] }: ToolSelectorProps) {
|
||||
export default function ToolSelector({ onSelect, excludeTools = [], toolRegistry }: ToolSelectorProps) {
|
||||
const { t } = useTranslation();
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const toolRegistry = useFlatToolRegistry();
|
||||
|
||||
// Filter out excluded tools (like 'automate' itself)
|
||||
const baseFilteredTools = useMemo(() => {
|
||||
|
@ -2,11 +2,14 @@ import React from 'react';
|
||||
import { Stack, Text, Divider, Card, Group } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSuggestedTools } from '../../../hooks/useSuggestedTools';
|
||||
import { useToolNavigation } from '../../../contexts/ToolNavigationContext';
|
||||
|
||||
export interface SuggestedToolsSectionProps {}
|
||||
|
||||
export function SuggestedToolsSection(): React.ReactElement {
|
||||
const { t } = useTranslation();
|
||||
const suggestedTools = useSuggestedTools();
|
||||
const { handleToolSelect, selectedToolKey } = useToolNavigation();
|
||||
const suggestedTools = useSuggestedTools(selectedToolKey, handleToolSelect);
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
|
@ -1,4 +1,16 @@
|
||||
import { AddWatermarkParameters } from "../hooks/tools/addWatermark/useAddWatermarkParameters";
|
||||
export interface AddWatermarkParameters {
|
||||
watermarkType?: 'text' | 'image';
|
||||
watermarkText: string;
|
||||
watermarkImage?: File;
|
||||
fontSize: number; // Used for both text size and image size
|
||||
rotation: number;
|
||||
opacity: number;
|
||||
widthSpacer: number;
|
||||
heightSpacer: number;
|
||||
alphabet: string;
|
||||
customColor: string;
|
||||
convertPDFToImage: boolean;
|
||||
}
|
||||
|
||||
export interface AlphabetOption {
|
||||
value: string;
|
||||
|
85
frontend/src/contexts/ToolNavigationContext.tsx
Normal file
85
frontend/src/contexts/ToolNavigationContext.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* ToolNavigationContext - Handles tool selection and navigation without tool registry
|
||||
* This breaks the circular dependency by not importing the tool registry
|
||||
*/
|
||||
|
||||
import React, { createContext, useContext, useState, useCallback } from 'react';
|
||||
import { useFileContext } from './FileContext';
|
||||
|
||||
// Navigation state interface
|
||||
interface ToolNavigationState {
|
||||
selectedToolKey: string | null;
|
||||
}
|
||||
|
||||
// Context value interface
|
||||
interface ToolNavigationContextValue extends ToolNavigationState {
|
||||
// Navigation Actions
|
||||
selectTool: (toolKey: string) => void;
|
||||
clearToolSelection: () => void;
|
||||
handleToolSelect: (toolId: string) => void;
|
||||
}
|
||||
|
||||
const ToolNavigationContext = createContext<ToolNavigationContextValue | undefined>(undefined);
|
||||
|
||||
// Provider component
|
||||
interface ToolNavigationProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function ToolNavigationProvider({ children }: ToolNavigationProviderProps) {
|
||||
const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null);
|
||||
const { setCurrentView } = useFileContext();
|
||||
|
||||
const selectTool = useCallback((toolKey: string) => {
|
||||
setSelectedToolKey(toolKey);
|
||||
}, []);
|
||||
|
||||
const clearToolSelection = useCallback(() => {
|
||||
setSelectedToolKey(null);
|
||||
}, []);
|
||||
|
||||
const handleToolSelect = useCallback((toolId: string) => {
|
||||
// Handle special cases
|
||||
if (toolId === 'allTools') {
|
||||
clearToolSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
selectTool(toolId);
|
||||
setCurrentView('fileEditor');
|
||||
}, [selectTool, setCurrentView, clearToolSelection]);
|
||||
|
||||
const contextValue: ToolNavigationContextValue = {
|
||||
selectedToolKey,
|
||||
selectTool,
|
||||
clearToolSelection,
|
||||
handleToolSelect
|
||||
};
|
||||
|
||||
return (
|
||||
<ToolNavigationContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ToolNavigationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
// Custom hook to use the context
|
||||
export function useToolNavigation(): ToolNavigationContextValue {
|
||||
const context = useContext(ToolNavigationContext);
|
||||
if (!context) {
|
||||
// During development hot reload, temporarily return a safe fallback
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.warn('ToolNavigationContext temporarily unavailable during hot reload, using fallback');
|
||||
|
||||
return {
|
||||
selectedToolKey: null,
|
||||
selectTool: () => {},
|
||||
clearToolSelection: () => {},
|
||||
handleToolSelect: () => {}
|
||||
} as ToolNavigationContextValue;
|
||||
}
|
||||
|
||||
throw new Error('useToolNavigation must be used within a ToolNavigationProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
@ -7,6 +7,7 @@ import React, { createContext, useContext, useReducer, useCallback, useMemo } fr
|
||||
import { useToolManagement } from '../hooks/useToolManagement';
|
||||
import { PageEditorFunctions } from '../types/pageEditor';
|
||||
import { ToolRegistryEntry } from '../data/toolsTaxonomy';
|
||||
import { useFileContext } from './FileContext';
|
||||
|
||||
// State interface
|
||||
interface ToolWorkflowState {
|
||||
@ -71,7 +72,7 @@ interface ToolWorkflowContextValue extends ToolWorkflowState {
|
||||
selectedToolKey: string | null;
|
||||
selectedTool: ToolRegistryEntry | null;
|
||||
toolRegistry: any; // From useToolManagement
|
||||
|
||||
|
||||
// UI Actions
|
||||
setSidebarsVisible: (visible: boolean) => void;
|
||||
setLeftPanelView: (view: 'toolPicker' | 'toolContent') => void;
|
||||
@ -99,13 +100,14 @@ const ToolWorkflowContext = createContext<ToolWorkflowContextValue | undefined>(
|
||||
// Provider component
|
||||
interface ToolWorkflowProviderProps {
|
||||
children: React.ReactNode;
|
||||
/** Handler for view changes (passed from parent) */
|
||||
onViewChange?: (view: string) => void;
|
||||
}
|
||||
|
||||
export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowProviderProps) {
|
||||
export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
||||
const [state, dispatch] = useReducer(toolWorkflowReducer, initialState);
|
||||
|
||||
// File context for view changes
|
||||
const { setCurrentView } = useFileContext();
|
||||
|
||||
// Tool management hook
|
||||
const {
|
||||
selectedToolKey,
|
||||
@ -152,12 +154,12 @@ export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowPro
|
||||
}
|
||||
|
||||
selectTool(toolId);
|
||||
onViewChange?.('fileEditor');
|
||||
setCurrentView('fileEditor');
|
||||
setLeftPanelView('toolContent');
|
||||
setReaderMode(false);
|
||||
// Clear search so the tool content becomes visible immediately
|
||||
setSearchQuery('');
|
||||
}, [selectTool, onViewChange, setLeftPanelView, setReaderMode, setSearchQuery, clearToolSelection]);
|
||||
}, [selectTool, setCurrentView, setLeftPanelView, setReaderMode, setSearchQuery, clearToolSelection]);
|
||||
|
||||
const handleBackToTools = useCallback(() => {
|
||||
setLeftPanelView('toolPicker');
|
||||
@ -183,7 +185,7 @@ export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowPro
|
||||
);
|
||||
|
||||
// Simple context value with basic memoization
|
||||
const contextValue = useMemo((): ToolWorkflowContextValue => ({
|
||||
const contextValue : ToolWorkflowContextValue ={
|
||||
// State
|
||||
...state,
|
||||
selectedToolKey,
|
||||
@ -208,7 +210,7 @@ export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowPro
|
||||
// Computed
|
||||
filteredTools,
|
||||
isPanelVisible,
|
||||
}), [state, selectedToolKey, selectedTool, toolRegistry, filteredTools, isPanelVisible]);
|
||||
};
|
||||
|
||||
return (
|
||||
<ToolWorkflowContext.Provider value={contextValue}>
|
||||
@ -221,7 +223,41 @@ export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowPro
|
||||
export function useToolWorkflow(): ToolWorkflowContextValue {
|
||||
const context = useContext(ToolWorkflowContext);
|
||||
if (!context) {
|
||||
// During development hot reload, temporarily return a safe fallback
|
||||
if (false && process.env.NODE_ENV === 'development') {
|
||||
console.warn('ToolWorkflowContext temporarily unavailable during hot reload, using fallback');
|
||||
|
||||
// Return minimal safe fallback to prevent crashes
|
||||
return {
|
||||
state: {
|
||||
sidebarsVisible: true,
|
||||
leftPanelView: 'toolPicker',
|
||||
readerMode: false,
|
||||
previewFile: null,
|
||||
pageEditorFunctions: null,
|
||||
searchQuery: ''
|
||||
},
|
||||
selectedToolKey: null,
|
||||
selectedTool: null,
|
||||
toolRegistry: {},
|
||||
filteredTools: [],
|
||||
isPanelVisible: true,
|
||||
setSidebarsVisible: () => {},
|
||||
setLeftPanelView: () => {},
|
||||
setReaderMode: () => {},
|
||||
setPreviewFile: () => {},
|
||||
setPageEditorFunctions: () => {},
|
||||
setSearchQuery: () => {},
|
||||
selectTool: () => {},
|
||||
clearToolSelection: () => {},
|
||||
handleToolSelect: () => {},
|
||||
handleBackToTools: () => {},
|
||||
handleReaderToggle: () => {}
|
||||
} as ToolWorkflowContextValue;
|
||||
}
|
||||
|
||||
console.error('ToolWorkflowContext not found. Current stack:', new Error().stack);
|
||||
throw new Error('useToolWorkflow must be used within a ToolWorkflowProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import ChangePermissions from '../tools/ChangePermissions';
|
||||
import RemovePassword from '../tools/RemovePassword';
|
||||
import { SubcategoryId, ToolCategory, ToolRegistry } from './toolsTaxonomy';
|
||||
import AddWatermark from '../tools/AddWatermark';
|
||||
import Automate from '../tools/Automate';
|
||||
|
||||
// Hook to get the translated tool registry
|
||||
export function useFlatToolRegistry(): ToolRegistry {
|
||||
@ -336,7 +335,7 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
"automate": {
|
||||
icon: <span className="material-symbols-rounded">automation</span>,
|
||||
name: t("home.automate.title", "Automate"),
|
||||
component: Automate,
|
||||
component: React.lazy(() => import('../tools/Automate')),
|
||||
view: "format",
|
||||
description: t("home.automate.desc", "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."),
|
||||
category: ToolCategory.ADVANCED_TOOLS,
|
||||
|
@ -1,20 +1,5 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { defaultWatermarkParameters } from '../../../constants/addWatermarkConstants';
|
||||
|
||||
export interface AddWatermarkParameters {
|
||||
watermarkType?: 'text' | 'image';
|
||||
watermarkText: string;
|
||||
watermarkImage?: File;
|
||||
fontSize: number; // Used for both text size and image size
|
||||
rotation: number;
|
||||
opacity: number;
|
||||
widthSpacer: number;
|
||||
heightSpacer: number;
|
||||
alphabet: string;
|
||||
customColor: string;
|
||||
convertPDFToImage: boolean;
|
||||
}
|
||||
|
||||
import { defaultWatermarkParameters, AddWatermarkParameters } from '../../../constants/addWatermarkConstants';
|
||||
|
||||
export const useAddWatermarkParameters = () => {
|
||||
const [parameters, setParameters] = useState<AddWatermarkParameters>(defaultWatermarkParameters);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useToolWorkflow } from '../contexts/ToolWorkflowContext';
|
||||
|
||||
// Material UI Icons
|
||||
import CompressIcon from '@mui/icons-material/Compress';
|
||||
@ -43,9 +42,7 @@ const ALL_SUGGESTED_TOOLS: Omit<SuggestedTool, 'navigate'>[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export function useSuggestedTools(): SuggestedTool[] {
|
||||
const { handleToolSelect, selectedToolKey } = useToolWorkflow();
|
||||
|
||||
export function useSuggestedTools(selectedToolKey?: string | null, handleToolSelect?: (toolId: string) => void): SuggestedTool[] {
|
||||
return useMemo(() => {
|
||||
// Filter out the current tool
|
||||
const filteredTools = ALL_SUGGESTED_TOOLS.filter(tool => tool.name !== selectedToolKey);
|
||||
@ -53,7 +50,7 @@ export function useSuggestedTools(): SuggestedTool[] {
|
||||
// Add navigation function to each tool
|
||||
return filteredTools.map(tool => ({
|
||||
...tool,
|
||||
navigate: () => handleToolSelect(tool.name)
|
||||
navigate: handleToolSelect ? () => handleToolSelect(tool.name) : () => {}
|
||||
}));
|
||||
}, [selectedToolKey, handleToolSelect]);
|
||||
}
|
@ -10,6 +10,7 @@ import ToolSequence from "../components/tools/automate/ToolSequence";
|
||||
|
||||
import { useAutomateOperation } from "../hooks/tools/automate/useAutomateOperation";
|
||||
import { BaseToolProps } from "../types/tool";
|
||||
import { useFlatToolRegistry } from "../data/useTranslatedToolRegistry";
|
||||
|
||||
const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
@ -20,6 +21,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||
const [stepData, setStepData] = useState<any>({});
|
||||
|
||||
const automateOperation = useAutomateOperation();
|
||||
const toolRegistry = useFlatToolRegistry();
|
||||
|
||||
const handleStepChange = (data: any) => {
|
||||
setStepData(data);
|
||||
@ -51,6 +53,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||
existingAutomation={stepData.automation}
|
||||
onBack={() => handleStepChange({ step: 'selection' })}
|
||||
onComplete={(automation: any) => handleStepChange({ step: 'sequence', automation })}
|
||||
toolRegistry={toolRegistry}
|
||||
/>
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user