mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-19 02:22:11 +01:00
Refactor to fix circular imports (#4700)
# Description of Changes Refactors code to avoid circular imports everywhere and adds linting for circular imports to ensure it doesn't happen again. Most changes are around the tool registry, making it a provider, and splitting into tool types to make it easier for things like Automate to only have access to tools excluding itself.
This commit is contained in:
@@ -25,7 +25,7 @@ interface AutomationCreationProps {
|
||||
existingAutomation?: AutomationConfig;
|
||||
onBack: () => void;
|
||||
onComplete: (automation: AutomationConfig) => void;
|
||||
toolRegistry: ToolRegistry;
|
||||
toolRegistry: Partial<ToolRegistry>;
|
||||
}
|
||||
|
||||
export default function AutomationCreation({ mode, existingAutomation, onBack, onComplete, toolRegistry }: AutomationCreationProps) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import { Tooltip } from '../../shared/Tooltip';
|
||||
import { ToolIcon } from '../../shared/ToolIcon';
|
||||
import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
||||
import { ToolRegistry } from '../../../data/toolsTaxonomy';
|
||||
import { ToolId } from 'src/types/toolId';
|
||||
|
||||
interface AutomationEntryProps {
|
||||
@@ -32,7 +32,7 @@ interface AutomationEntryProps {
|
||||
/** Copy handler (for suggested automations) */
|
||||
onCopy?: () => void;
|
||||
/** Tool registry to resolve operation names */
|
||||
toolRegistry?: Record<ToolId, ToolRegistryEntry>;
|
||||
toolRegistry?: Partial<ToolRegistry>;
|
||||
}
|
||||
|
||||
export default function AutomationEntry({
|
||||
@@ -56,8 +56,9 @@ export default function AutomationEntry({
|
||||
|
||||
// Helper function to resolve tool display names
|
||||
const getToolDisplayName = (operation: string): string => {
|
||||
if (toolRegistry?.[operation as ToolId]?.name) {
|
||||
return toolRegistry[operation as ToolId].name;
|
||||
const entry = toolRegistry?.[operation as ToolId];
|
||||
if (entry?.name) {
|
||||
return entry.name;
|
||||
}
|
||||
// Fallback to translation or operation key
|
||||
return t(`${operation}.title`, operation);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Button, Text, Stack, Group, Card, Progress } from "@mantine/core";
|
||||
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import { useFileSelection } from "../../../contexts/FileContext";
|
||||
import { useFlatToolRegistry } from "../../../data/useTranslatedToolRegistry";
|
||||
import { useToolRegistry } from "../../../contexts/ToolRegistryContext";
|
||||
import { AutomationConfig, ExecutionStep } from "../../../types/automation";
|
||||
import { AUTOMATION_CONSTANTS, EXECUTION_STATUS } from "../../../constants/automation";
|
||||
import { useResourceCleanup } from "../../../utils/resourceManager";
|
||||
@@ -18,7 +18,8 @@ interface AutomationRunProps {
|
||||
export default function AutomationRun({ automation, onComplete, automateOperation }: AutomationRunProps) {
|
||||
const { t } = useTranslation();
|
||||
const { selectedFiles } = useFileSelection();
|
||||
const toolRegistry = useFlatToolRegistry();
|
||||
const { regularTools } = useToolRegistry();
|
||||
const toolRegistry = regularTools;
|
||||
const cleanup = useResourceCleanup();
|
||||
|
||||
// Progress tracking state
|
||||
|
||||
@@ -6,8 +6,7 @@ import AutomationEntry from "./AutomationEntry";
|
||||
import { useSuggestedAutomations } from "../../../hooks/tools/automate/useSuggestedAutomations";
|
||||
import { AutomationConfig, SuggestedAutomation } from "../../../types/automation";
|
||||
import { iconMap } from './iconMap';
|
||||
import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
|
||||
import { ToolId } from '../../../types/toolId';
|
||||
import { ToolRegistry } from '../../../data/toolsTaxonomy';
|
||||
|
||||
interface AutomationSelectionProps {
|
||||
savedAutomations: AutomationConfig[];
|
||||
@@ -16,7 +15,7 @@ interface AutomationSelectionProps {
|
||||
onEdit: (automation: AutomationConfig) => void;
|
||||
onDelete: (automation: AutomationConfig) => void;
|
||||
onCopyFromSuggested: (automation: SuggestedAutomation) => void;
|
||||
toolRegistry: Record<ToolId, ToolRegistryEntry>;
|
||||
toolRegistry: Partial<ToolRegistry>;
|
||||
}
|
||||
|
||||
export default function AutomationSelection({
|
||||
|
||||
@@ -15,6 +15,7 @@ import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import { ToolRegistry } from '../../../data/toolsTaxonomy';
|
||||
import { ToolId } from '../../../types/toolId';
|
||||
import { getAvailableToExtensions } from '../../../utils/convertUtils';
|
||||
interface ToolConfigurationModalProps {
|
||||
opened: boolean;
|
||||
@@ -26,7 +27,7 @@ interface ToolConfigurationModalProps {
|
||||
};
|
||||
onSave: (parameters: any) => void;
|
||||
onCancel: () => void;
|
||||
toolRegistry: ToolRegistry;
|
||||
toolRegistry: Partial<ToolRegistry>;
|
||||
}
|
||||
|
||||
export default function ToolConfigurationModal({ opened, tool, onSave, onCancel, toolRegistry }: ToolConfigurationModalProps) {
|
||||
@@ -35,7 +36,7 @@ export default function ToolConfigurationModal({ opened, tool, onSave, onCancel,
|
||||
const [parameters, setParameters] = useState<any>({});
|
||||
|
||||
// Get tool info from registry
|
||||
const toolInfo = toolRegistry[tool.operation as keyof ToolRegistry];
|
||||
const toolInfo = toolRegistry[tool.operation as ToolId];
|
||||
const SettingsComponent = toolInfo?.automationSettings;
|
||||
|
||||
// Initialize parameters from tool (which should contain defaults from registry)
|
||||
|
||||
@@ -5,14 +5,14 @@ import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import AddCircleOutline from "@mui/icons-material/AddCircleOutline";
|
||||
import { AutomationTool } from "../../../types/automation";
|
||||
import { ToolRegistryEntry } from "../../../data/toolsTaxonomy";
|
||||
import { ToolRegistry } from "../../../data/toolsTaxonomy";
|
||||
import { ToolId } from "../../../types/toolId";
|
||||
import ToolSelector from "./ToolSelector";
|
||||
import AutomationEntry from "./AutomationEntry";
|
||||
|
||||
interface ToolListProps {
|
||||
tools: AutomationTool[];
|
||||
toolRegistry: Record<ToolId, ToolRegistryEntry>;
|
||||
toolRegistry: Partial<ToolRegistry>;
|
||||
onToolUpdate: (index: number, updates: Partial<AutomationTool>) => void;
|
||||
onToolRemove: (index: number) => void;
|
||||
onToolConfigure: (index: number) => void;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Stack, Text, ScrollArea } from '@mantine/core';
|
||||
import { ToolRegistryEntry, getToolSupportsAutomate } from '../../../data/toolsTaxonomy';
|
||||
import { ToolRegistryEntry, ToolRegistry, getToolSupportsAutomate } from '../../../data/toolsTaxonomy';
|
||||
import { useToolSections } from '../../../hooks/useToolSections';
|
||||
import { renderToolButtons } from '../shared/renderToolButtons';
|
||||
import ToolSearch from '../toolPicker/ToolSearch';
|
||||
@@ -11,7 +11,7 @@ import { ToolId } from '../../../types/toolId';
|
||||
interface ToolSelectorProps {
|
||||
onSelect: (toolKey: string) => void;
|
||||
excludeTools?: string[];
|
||||
toolRegistry: Record<ToolId, ToolRegistryEntry>; // Pass registry as prop to break circular dependency
|
||||
toolRegistry: Partial<ToolRegistry>; // Pass registry as prop to break circular dependency
|
||||
selectedValue?: string; // For showing current selection when editing existing tool
|
||||
placeholder?: string; // Custom placeholder text
|
||||
}
|
||||
@@ -54,7 +54,7 @@ export default function ToolSelector({
|
||||
|
||||
// Create filtered tool registry for ToolSearch
|
||||
const filteredToolRegistry = useMemo(() => {
|
||||
const registry: Record<ToolId, ToolRegistryEntry> = {} as Record<ToolId, ToolRegistryEntry>;
|
||||
const registry: Partial<ToolRegistry> = {};
|
||||
baseFilteredTools.forEach(([key, tool]) => {
|
||||
registry[key as ToolId] = tool;
|
||||
});
|
||||
@@ -142,10 +142,10 @@ export default function ToolSelector({
|
||||
};
|
||||
|
||||
// Get display value for selected tool
|
||||
const selectedTool = selectedValue ? toolRegistry[selectedValue as ToolId] : undefined;
|
||||
|
||||
const getDisplayValue = () => {
|
||||
if (selectedValue && toolRegistry[selectedValue as ToolId]) {
|
||||
return toolRegistry[selectedValue as ToolId].name;
|
||||
}
|
||||
if (selectedTool) return selectedTool.name;
|
||||
return placeholder || t('automate.creation.tools.add', 'Add a tool...');
|
||||
};
|
||||
|
||||
@@ -153,12 +153,18 @@ export default function ToolSelector({
|
||||
<div ref={containerRef} className='rounded-xl'>
|
||||
{/* Always show the target - either selected tool or search input */}
|
||||
|
||||
{selectedValue && toolRegistry[selectedValue as ToolId] && !opened ? (
|
||||
{selectedTool && !opened ? (
|
||||
// Show selected tool in AutomationEntry style when tool is selected and dropdown closed
|
||||
<div onClick={handleSearchFocus} style={{ cursor: 'pointer',
|
||||
borderRadius: "var(--mantine-radius-lg)" }}>
|
||||
<ToolButton id={'tool' as ToolId} tool={toolRegistry[selectedValue as ToolId]} isSelected={false}
|
||||
onSelect={()=>{}} rounded={true} disableNavigation={true}></ToolButton>
|
||||
<ToolButton
|
||||
id={'tool' as ToolId}
|
||||
tool={selectedTool}
|
||||
isSelected={false}
|
||||
onSelect={()=>{}}
|
||||
rounded={true}
|
||||
disableNavigation={true}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
// Show search input when no tool selected OR when dropdown is opened
|
||||
|
||||
@@ -3,13 +3,7 @@ import { useHistoryCapability } from '@embedpdf/plugin-history/react';
|
||||
import { useAnnotationCapability } from '@embedpdf/plugin-annotation/react';
|
||||
import { useSignature } from '../../contexts/SignatureContext';
|
||||
import { uuidV4 } from '@embedpdf/models';
|
||||
|
||||
export interface HistoryAPI {
|
||||
undo: () => void;
|
||||
redo: () => void;
|
||||
canUndo: () => boolean;
|
||||
canRedo: () => boolean;
|
||||
}
|
||||
import type { HistoryAPI } from './viewerTypes';
|
||||
|
||||
export const HistoryAPIBridge = forwardRef<HistoryAPI>(function HistoryAPIBridge(_, ref) {
|
||||
const { provides: historyApi } = useHistoryCapability();
|
||||
@@ -42,7 +36,7 @@ export const HistoryAPIBridge = forwardRef<HistoryAPI>(function HistoryAPIBridge
|
||||
const currentStoredData = getImageData(annotation.id);
|
||||
// Check if the annotation lacks image data but we have it stored
|
||||
if (currentStoredData && (!annotation.imageSrc || annotation.imageSrc !== currentStoredData)) {
|
||||
|
||||
|
||||
// Generate new ID to avoid React key conflicts
|
||||
const newId = uuidV4();
|
||||
|
||||
@@ -113,4 +107,4 @@ export const HistoryAPIBridge = forwardRef<HistoryAPI>(function HistoryAPIBridge
|
||||
return null; // This is a bridge component with no UI
|
||||
});
|
||||
|
||||
HistoryAPIBridge.displayName = 'HistoryAPIBridge';
|
||||
HistoryAPIBridge.displayName = 'HistoryAPIBridge';
|
||||
|
||||
@@ -34,8 +34,9 @@ import { SpreadAPIBridge } from './SpreadAPIBridge';
|
||||
import { SearchAPIBridge } from './SearchAPIBridge';
|
||||
import { ThumbnailAPIBridge } from './ThumbnailAPIBridge';
|
||||
import { RotateAPIBridge } from './RotateAPIBridge';
|
||||
import { SignatureAPIBridge, SignatureAPI } from './SignatureAPIBridge';
|
||||
import { HistoryAPIBridge, HistoryAPI } from './HistoryAPIBridge';
|
||||
import { SignatureAPIBridge } from './SignatureAPIBridge';
|
||||
import { HistoryAPIBridge } from './HistoryAPIBridge';
|
||||
import type { SignatureAPI, HistoryAPI } from './viewerTypes';
|
||||
import { ExportAPIBridge } from './ExportAPIBridge';
|
||||
|
||||
interface LocalEmbedPDFProps {
|
||||
|
||||
@@ -2,17 +2,7 @@ import { useImperativeHandle, forwardRef, useEffect } from 'react';
|
||||
import { useAnnotationCapability } from '@embedpdf/plugin-annotation/react';
|
||||
import { PdfAnnotationSubtype, uuidV4 } from '@embedpdf/models';
|
||||
import { useSignature } from '../../contexts/SignatureContext';
|
||||
|
||||
export interface SignatureAPI {
|
||||
addImageSignature: (signatureData: string, x: number, y: number, width: number, height: number, pageIndex: number) => void;
|
||||
activateDrawMode: () => void;
|
||||
activateSignaturePlacementMode: () => void;
|
||||
activateDeleteMode: () => void;
|
||||
deleteAnnotation: (annotationId: string, pageIndex: number) => void;
|
||||
updateDrawSettings: (color: string, size: number) => void;
|
||||
deactivateTools: () => void;
|
||||
getPageAnnotations: (pageIndex: number) => Promise<any[]>;
|
||||
}
|
||||
import type { SignatureAPI } from './viewerTypes';
|
||||
|
||||
export const SignatureAPIBridge = forwardRef<SignatureAPI>(function SignatureAPIBridge(_, ref) {
|
||||
const { provides: annotationApi } = useAnnotationCapability();
|
||||
@@ -246,4 +236,4 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI>(function SignatureAPI
|
||||
return null; // This is a bridge component with no UI
|
||||
});
|
||||
|
||||
SignatureAPIBridge.displayName = 'SignatureAPIBridge';
|
||||
SignatureAPIBridge.displayName = 'SignatureAPIBridge';
|
||||
|
||||
24
frontend/src/components/viewer/viewerTypes.ts
Normal file
24
frontend/src/components/viewer/viewerTypes.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export interface SignatureAPI {
|
||||
addImageSignature: (
|
||||
signatureData: string,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
pageIndex: number
|
||||
) => void;
|
||||
activateDrawMode: () => void;
|
||||
activateSignaturePlacementMode: () => void;
|
||||
activateDeleteMode: () => void;
|
||||
deleteAnnotation: (annotationId: string, pageIndex: number) => void;
|
||||
updateDrawSettings: (color: string, size: number) => void;
|
||||
deactivateTools: () => void;
|
||||
getPageAnnotations: (pageIndex: number) => Promise<any[]>;
|
||||
}
|
||||
|
||||
export interface HistoryAPI {
|
||||
undo: () => void;
|
||||
redo: () => void;
|
||||
canUndo: () => boolean;
|
||||
canRedo: () => boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user