diff --git a/frontend/src/components/layout/Workbench.tsx b/frontend/src/components/layout/Workbench.tsx index 39c5166f7..fc41d2480 100644 --- a/frontend/src/components/layout/Workbench.tsx +++ b/frontend/src/components/layout/Workbench.tsx @@ -14,7 +14,6 @@ import PageEditorControls from '../pageEditor/PageEditorControls'; import Viewer from '../viewer/Viewer'; import ToolRenderer from '../tools/ToolRenderer'; import LandingPage from '../shared/LandingPage'; -import { ToolId } from '../../data/toolsTaxonomy'; // No props needed - component uses contexts directly export default function Workbench() { @@ -43,15 +42,15 @@ export default function Workbench() { const handlePreviewClose = () => { setPreviewFile(null); const previousMode = sessionStorage.getItem('previousMode'); - if (previousMode === ToolId.SPLIT_PDF) { + if (previousMode === 'split') { // Use context's handleToolSelect which coordinates tool selection and view changes - handleToolSelect(ToolId.SPLIT_PDF); + handleToolSelect('split'); sessionStorage.removeItem('previousMode'); - } else if (previousMode === ToolId.COMPRESS) { - handleToolSelect(ToolId.COMPRESS); + } else if (previousMode === 'compress') { + handleToolSelect('compress'); sessionStorage.removeItem('previousMode'); - } else if (previousMode === ToolId.CONVERT) { - handleToolSelect(ToolId.CONVERT); + } else if (previousMode === 'convert') { + handleToolSelect('convert'); sessionStorage.removeItem('previousMode'); } else { setCurrentView('fileEditor'); diff --git a/frontend/src/components/shared/QuickAccessBar.tsx b/frontend/src/components/shared/QuickAccessBar.tsx index 2ec161a00..80ef86c83 100644 --- a/frontend/src/components/shared/QuickAccessBar.tsx +++ b/frontend/src/components/shared/QuickAccessBar.tsx @@ -18,7 +18,6 @@ import { getNavButtonStyle, getActiveNavButton, } from './quickAccessBar/QuickAccessBar'; -import { ToolId } from "../../data/toolsTaxonomy"; const QuickAccessBar = forwardRef(({ }, ref) => { @@ -43,20 +42,20 @@ const QuickAccessBar = forwardRef(({ const buttonConfigs: ButtonConfig[] = [ { - id: ToolId.READ, + id: 'read', name: t("quickAccess.read", "Read"), icon: , size: 'lg', isRound: false, type: 'navigation', onClick: () => { - setActiveButton(ToolId.READ); + setActiveButton('read'); handleBackToTools(); handleReaderToggle(); } }, { - id: ToolId.SIGN, + id: 'sign', name: t("quickAccess.sign", "Sign"), icon: @@ -67,11 +66,11 @@ const QuickAccessBar = forwardRef(({ type: 'navigation', onClick: () => { setActiveButton('sign'); - handleToolSelect(ToolId.SIGN); + handleToolSelect('sign'); } }, { - id: ToolId.AUTOMATE, + id: 'automate', name: t("quickAccess.automate", "Automate"), icon: @@ -81,8 +80,8 @@ const QuickAccessBar = forwardRef(({ isRound: false, type: 'navigation', onClick: () => { - setActiveButton(ToolId.AUTOMATE); - handleToolSelect(ToolId.AUTOMATE); + setActiveButton('automate'); + handleToolSelect('automate'); } }, { diff --git a/frontend/src/components/tools/SearchResults.tsx b/frontend/src/components/tools/SearchResults.tsx index 63a746b49..6ecb64b7e 100644 --- a/frontend/src/components/tools/SearchResults.tsx +++ b/frontend/src/components/tools/SearchResults.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import { Box, Stack, Text } from '@mantine/core'; -import { getSubcategoryLabel, ToolId, ToolRegistryEntry } from '../../data/toolsTaxonomy'; +import { getSubcategoryLabel, ToolRegistryEntry } from '../../data/toolsTaxonomy'; import ToolButton from './toolPicker/ToolButton'; import { useTranslation } from 'react-i18next'; import { useToolSections } from '../../hooks/useToolSections'; @@ -8,8 +8,8 @@ import SubcategoryHeader from './shared/SubcategoryHeader'; import NoToolsFound from './shared/NoToolsFound'; interface SearchResultsProps { - filteredTools: [ToolId, ToolRegistryEntry][]; - onSelect: (id: ToolId) => void; + filteredTools: [string, ToolRegistryEntry][]; + onSelect: (id: string) => void; } const SearchResults: React.FC = ({ filteredTools, onSelect }) => { diff --git a/frontend/src/components/tools/ToolPicker.tsx b/frontend/src/components/tools/ToolPicker.tsx index 4d4e6200d..411ecdb7a 100644 --- a/frontend/src/components/tools/ToolPicker.tsx +++ b/frontend/src/components/tools/ToolPicker.tsx @@ -1,7 +1,7 @@ import React, { useMemo, useRef, useLayoutEffect, useState } from "react"; import { Box, Text, Stack } from "@mantine/core"; import { useTranslation } from "react-i18next"; -import { getSubcategoryLabel, ToolId, ToolRegistryEntry } from "../../data/toolsTaxonomy"; +import { getSubcategoryLabel, ToolRegistryEntry } from "../../data/toolsTaxonomy"; import ToolButton from "./toolPicker/ToolButton"; import "./toolPicker/ToolPicker.css"; import { SubcategoryGroup, useToolSections } from "../../hooks/useToolSections"; @@ -10,9 +10,9 @@ import NoToolsFound from "./shared/NoToolsFound"; import { TFunction } from "i18next"; interface ToolPickerProps { - selectedToolKey: ToolId | null; - onSelect: (id: ToolId) => void; - filteredTools: [ToolId, ToolRegistryEntry][]; + selectedToolKey: string | null; + onSelect: (id: string) => void; + filteredTools: [string, ToolRegistryEntry][]; isSearching?: boolean; } @@ -20,8 +20,8 @@ interface ToolPickerProps { const renderToolButtons = ( t: TFunction, subcategory: SubcategoryGroup, - selectedToolKey: ToolId | null, - onSelect: (id: ToolId) => void, + selectedToolKey: string | null, + onSelect: (id: string) => void, showSubcategoryHeader: boolean = true ) => ( @@ -29,7 +29,7 @@ const renderToolButtons = ( )} - {subcategory.tools.map(({ id, tool }) => ( + {subcategory.tools.map(({ id, tool }: { id: string; tool: any }) => ( void; + onSelect: (id: string) => void; } const ToolButton: React.FC = ({ id, tool, isSelected, onSelect }) => { - const handleClick = (id: ToolId) => { + const handleClick = (id: string) => { if (tool.link) { // Open external link in new tab window.open(tool.link, '_blank', 'noopener,noreferrer'); diff --git a/frontend/src/contexts/ToolWorkflowContext.tsx b/frontend/src/contexts/ToolWorkflowContext.tsx index 60023b911..1ee211312 100644 --- a/frontend/src/contexts/ToolWorkflowContext.tsx +++ b/frontend/src/contexts/ToolWorkflowContext.tsx @@ -6,7 +6,7 @@ import React, { createContext, useContext, useReducer, useCallback, useMemo } from 'react'; import { useToolManagement } from '../hooks/useToolManagement'; import { PageEditorFunctions } from '../types/pageEditor'; -import { ToolId, ToolRegistryEntry } from '../data/toolsTaxonomy'; +import { ToolRegistryEntry } from '../data/toolsTaxonomy'; import { useToolWorkflowUrlSync } from '../hooks/useUrlSync'; // State interface @@ -69,7 +69,7 @@ function toolWorkflowReducer(state: ToolWorkflowState, action: ToolWorkflowActio // Context value interface interface ToolWorkflowContextValue extends ToolWorkflowState { // Tool management (from hook) - selectedToolKey: ToolId | null; + selectedToolKey: string | null; selectedTool: ToolRegistryEntry | null; toolRegistry: any; // From useToolManagement @@ -82,16 +82,16 @@ interface ToolWorkflowContextValue extends ToolWorkflowState { setSearchQuery: (query: string) => void; // Tool Actions - selectTool: (toolId: ToolId) => void; + selectTool: (toolId: string) => void; clearToolSelection: () => void; // Workflow Actions (compound actions) - handleToolSelect: (toolId: ToolId) => void; + handleToolSelect: (toolId: string) => void; handleBackToTools: () => void; handleReaderToggle: () => void; // Computed values - filteredTools: [ToolId, ToolRegistryEntry][]; // Filtered by search + filteredTools: [string, ToolRegistryEntry][]; // Filtered by search isPanelVisible: boolean; } @@ -144,9 +144,9 @@ export function ToolWorkflowProvider({ children, onViewChange, enableUrlSync = t }, []); // Workflow actions (compound actions that coordinate multiple state changes) - const handleToolSelect = useCallback((toolId: ToolId) => { + const handleToolSelect = useCallback((toolId: string) => { // Special-case: if tool is a dedicated reader tool, enter reader mode and do not go to toolContent - if (toolId === ToolId.READ) { + if (toolId === 'read' || toolId === 'view-pdf') { setReaderMode(true); setLeftPanelView('toolPicker'); clearToolSelection(); @@ -175,7 +175,7 @@ export function ToolWorkflowProvider({ children, onViewChange, enableUrlSync = t // Filter tools based on search query const filteredTools = useMemo(() => { if (!toolRegistry) return []; - return (Object.entries(toolRegistry) as [ToolId, ToolRegistryEntry][]).filter(([_, { name }]) => + return Object.entries(toolRegistry).filter(([_, { name }]) => name.toLowerCase().includes(state.searchQuery.toLowerCase()) ); }, [toolRegistry, state.searchQuery]); diff --git a/frontend/src/data/toolsTaxonomy.ts b/frontend/src/data/toolsTaxonomy.ts index 90a29c6e6..2dff2b8e4 100644 --- a/frontend/src/data/toolsTaxonomy.ts +++ b/frontend/src/data/toolsTaxonomy.ts @@ -2,64 +2,6 @@ import { type TFunction } from 'i18next'; import React from 'react'; import { BaseToolProps } from '../types/tool'; -export enum ToolId { - CERT_SIGN = 'certSign', - SIGN = 'sign', - ADD_PASSWORD = 'addPassword', - WATERMARK = 'watermark', - ADD_STAMP = 'add-stamp', - SANITIZE = 'sanitize', - FLATTEN = 'flatten', - UNLOCK_PDF_FORMS = 'unlock-pdf-forms', - MANAGE_CERTIFICATES = 'manage-certificates', - CHANGE_PERMISSIONS = 'change-permissions', - GET_ALL_INFO_ON_PDF = 'get-all-info-on-pdf', - VALIDATE_PDF_SIGNATURE = 'validate-pdf-signature', - READ = 'read', - CHANGE_METADATA = 'change-metadata', - CROP_PDF = 'cropPdf', - ROTATE = 'rotate', - SPLIT_PDF = 'splitPdf', - REORGANIZE_PAGES = 'reorganize-pages', - ADJUST_PAGE_SIZE_SCALE = 'adjust-page-size-scale', - ADD_PAGE_NUMBERS = 'addPageNumbers', - MULTI_PAGE_LAYOUT = 'multi-page-layout', - SINGLE_LARGE_PAGE = 'single-large-page', - ADD_ATTACHMENTS = 'add-attachments', - EXTRACT_PAGES = 'extractPages', - EXTRACT_IMAGES = 'extract-images', - REMOVE_PAGES = 'removePages', - REMOVE_BLANK_PAGES = 'remove-blank-pages', - REMOVE_ANNOTATIONS = 'remove-annotations', - REMOVE_IMAGE = 'remove-image', - REMOVE_PASSWORD = 'remove-password', - REMOVE_CERTIFICATE_SIGN = 'remove-certificate-sign', - AUTOMATE = 'automate', - AUTO_RENAME_PDF_FILE = 'auto-rename-pdf-file', - AUTO_SPLIT_PAGES = 'auto-split-pages', - AUTO_SPLIT_BY_SIZE_COUNT = 'auto-split-by-size-count', - ADJUST_CONTRAST = 'adjustContrast', - REPAIR = 'repair', - DETECT_SPLIT_SCANNED_PHOTOS = 'detect-split-scanned-photos', - OVERLAY_PDFS = 'overlay-pdfs', - REPLACE_AND_INVERT_COLOR = 'replace-and-invert-color', - ADD_IMAGE = 'add-image', - EDIT_TABLE_OF_CONTENTS = 'edit-table-of-contents', - SCANNER_EFFECT = 'scanner-effect', - SHOW_JAVASCRIPT = 'show-javascript', - DEV_API = 'dev-api', - DEV_FOLDER_SCANNING = 'dev-folder-scanning', - DEV_SSO_GUIDE = 'dev-sso-guide', - DEV_AIRGAPPED = 'dev-airgapped', - COMPARE = 'compare', - COMPRESS = 'compress', - CONVERT = 'convert', - MERGE_PDFS = 'mergePdfs', - MULTI_TOOL = 'multi-tool', - OCR = 'ocr', - REDACT = 'redact' -}; - export enum SubcategoryId { SIGNING = 'signing', DOCUMENT_SECURITY = 'documentSecurity', @@ -95,7 +37,7 @@ export type ToolRegistryEntry = { type?: string; } -export type ToolRegistry = Record; +export type ToolRegistry = Record; export const SUBCATEGORY_ORDER: SubcategoryId[] = [ SubcategoryId.SIGNING, diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx index 011549569..0426a7bf6 100644 --- a/frontend/src/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/data/useTranslatedToolRegistry.tsx @@ -7,7 +7,7 @@ import Sanitize from '../tools/Sanitize'; import AddPassword from '../tools/AddPassword'; import ChangePermissions from '../tools/ChangePermissions'; import RemovePassword from '../tools/RemovePassword'; -import { SubcategoryId, ToolCategoryId, ToolId, ToolRegistry } from './toolsTaxonomy'; +import { SubcategoryId, ToolCategoryId, ToolRegistry } from './toolsTaxonomy'; import AddWatermark from '../tools/AddWatermark'; import Repair from '../tools/Repair'; import SingleLargePage from '../tools/SingleLargePage'; @@ -23,7 +23,7 @@ export function useFlatToolRegistry(): ToolRegistry { const allTools: ToolRegistry = { // Signing - [ToolId.CERT_SIGN]: { + "certSign": { icon: workspace_premium, name: t("home.certSign.title", "Sign with Certificate"), component: null, @@ -32,7 +32,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.SIGNING }, - [ToolId.SIGN]: { + "sign": { icon: signature, name: t("home.sign.title", "Sign"), component: null, @@ -45,7 +45,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Document Security - [ToolId.ADD_PASSWORD]: { + "addPassword": { icon: password, name: t("home.addPassword.title", "Add Password"), component: AddPassword, @@ -56,7 +56,7 @@ export function useFlatToolRegistry(): ToolRegistry { maxFiles: -1, endpoints: ["add-password"] }, - [ToolId.WATERMARK]: { + "watermark": { icon: branding_watermark, name: t("home.watermark.title", "Add Watermark"), component: AddWatermark, @@ -67,7 +67,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.DOCUMENT_SECURITY, endpoints: ["add-watermark"] }, - [ToolId.ADD_STAMP]: { + "add-stamp": { icon: approval, name: t("home.AddStampRequest.title", "Add Stamp to PDF"), component: null, @@ -76,7 +76,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.DOCUMENT_SECURITY }, - [ToolId.SANITIZE]: { + "sanitize": { icon: cleaning_services, name: t("home.sanitize.title", "Sanitize"), component: Sanitize, @@ -87,7 +87,7 @@ export function useFlatToolRegistry(): ToolRegistry { description: t("home.sanitize.desc", "Remove potentially harmful elements from PDF files"), endpoints: ["sanitize-pdf"] }, - [ToolId.FLATTEN]: { + "flatten": { icon: layers_clear, name: t("home.flatten.title", "Flatten"), component: null, @@ -96,7 +96,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.DOCUMENT_SECURITY }, - [ToolId.UNLOCK_PDF_FORMS]: { + "unlock-pdf-forms": { icon: preview_off, name: t("home.unlockPDFForms.title", "Unlock PDF Forms"), component: UnlockPdfForms, @@ -107,7 +107,7 @@ export function useFlatToolRegistry(): ToolRegistry { maxFiles: -1, endpoints: ["unlock-pdf-forms"] }, - [ToolId.MANAGE_CERTIFICATES]: { + "manage-certificates": { icon: license, name: t("home.manageCertificates.title", "Manage Certificates"), component: null, @@ -116,7 +116,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.DOCUMENT_SECURITY }, - [ToolId.CHANGE_PERMISSIONS]: { + "change-permissions": { icon: lock, name: t("home.changePermissions.title", "Change Permissions"), component: ChangePermissions, @@ -129,7 +129,7 @@ export function useFlatToolRegistry(): ToolRegistry { }, // Verification - [ToolId.GET_ALL_INFO_ON_PDF]: { + "get-all-info-on-pdf": { icon: fact_check, name: t("home.getPdfInfo.title", "Get ALL Info on PDF"), component: null, @@ -138,7 +138,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.VERIFICATION }, - [ToolId.VALIDATE_PDF_SIGNATURE]: { + "validate-pdf-signature": { icon: verified, name: t("home.validateSignature.title", "Validate PDF Signature"), component: null, @@ -151,7 +151,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Document Review - [ToolId.READ]: { + "read": { icon: article, name: t("home.read.title", "Read"), component: null, @@ -160,7 +160,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.DOCUMENT_REVIEW }, - [ToolId.CHANGE_METADATA]: { + "change-metadata": { icon: assignment, name: t("home.changeMetadata.title", "Change Metadata"), component: null, @@ -171,7 +171,7 @@ export function useFlatToolRegistry(): ToolRegistry { }, // Page Formatting - [ToolId.CROP_PDF]: { + "cropPdf": { icon: crop, name: t("home.crop.title", "Crop PDF"), component: null, @@ -180,7 +180,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.ROTATE]: { + "rotate": { icon: rotate_right, name: t("home.rotate.title", "Rotate"), component: null, @@ -189,7 +189,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.SPLIT_PDF]: { + "splitPdf": { icon: content_cut, name: t("home.split.title", "Split"), component: SplitPdfPanel, @@ -198,7 +198,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.REORGANIZE_PAGES]: { + "reorganize-pages": { icon: move_down, name: t("home.reorganizePages.title", "Reorganize Pages"), component: null, @@ -207,7 +207,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.ADJUST_PAGE_SIZE_SCALE]: { + "adjust-page-size-scale": { icon: crop_free, name: t("home.scalePages.title", "Adjust page size/scale"), component: null, @@ -216,7 +216,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.ADD_PAGE_NUMBERS]: { + "addPageNumbers": { icon: 123, name: t("home.addPageNumbers.title", "Add Page Numbers"), component: null, @@ -225,7 +225,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.MULTI_PAGE_LAYOUT]: { + "multi-page-layout": { icon: dashboard, name: t("home.pageLayout.title", "Multi-Page Layout"), component: null, @@ -234,7 +234,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.PAGE_FORMATTING }, - [ToolId.SINGLE_LARGE_PAGE]: { + "single-large-page": { icon: looks_one, name: t("home.pdfToSinglePage.title", "PDF to Single Large Page"), component: SingleLargePage, @@ -245,7 +245,7 @@ export function useFlatToolRegistry(): ToolRegistry { maxFiles: -1, endpoints: ["pdf-to-single-page"] }, - [ToolId.ADD_ATTACHMENTS]: { + "add-attachments": { icon: attachment, name: t("home.attachments.title", "Add Attachments"), component: null, @@ -258,7 +258,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Extraction - [ToolId.EXTRACT_PAGES]: { + "extractPages": { icon: upload, name: t("home.extractPages.title", "Extract Pages"), component: null, @@ -267,7 +267,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.EXTRACTION }, - [ToolId.EXTRACT_IMAGES]: { + "extract-images": { icon: filter, name: t("home.extractImages.title", "Extract Images"), component: null, @@ -280,7 +280,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Removal - [ToolId.REMOVE_PAGES]: { + "removePages": { icon: delete, name: t("home.removePages.title", "Remove Pages"), component: null, @@ -289,7 +289,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.REMOVAL }, - [ToolId.REMOVE_BLANK_PAGES]: { + "remove-blank-pages": { icon: scan_delete, name: t("home.removeBlanks.title", "Remove Blank Pages"), component: null, @@ -298,7 +298,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.REMOVAL }, - [ToolId.REMOVE_ANNOTATIONS]: { + "remove-annotations": { icon: thread_unread, name: t("home.removeAnnotations.title", "Remove Annotations"), component: null, @@ -307,7 +307,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.REMOVAL }, - [ToolId.REMOVE_IMAGE]: { + "remove-image": { icon: remove_selection, name: t("home.removeImagePdf.title", "Remove Image"), component: null, @@ -316,7 +316,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.REMOVAL }, - [ToolId.REMOVE_PASSWORD]: { + "remove-password": { icon: lock_open_right, name: t("home.removePassword.title", "Remove Password"), component: RemovePassword, @@ -328,7 +328,7 @@ export function useFlatToolRegistry(): ToolRegistry { maxFiles: -1, }, - [ToolId.REMOVE_CERTIFICATE_SIGN]: { + "remove-certificate-sign": { icon: remove_moderator, name: t("home.removeCertSign.title", "Remove Certificate Sign"), component: RemoveCertificateSign, @@ -343,7 +343,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Automation - [ToolId.AUTOMATE]: { + "automate": { icon: automation, name: t("home.automate.title", "Automate"), component: null, @@ -352,7 +352,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.AUTOMATION }, - [ToolId.AUTO_RENAME_PDF_FILE]: { + "auto-rename-pdf-file": { icon: match_word, name: t("home.auto-rename.title", "Auto Rename PDF File"), component: null, @@ -361,7 +361,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.AUTOMATION }, - [ToolId.AUTO_SPLIT_PAGES]: { + "auto-split-pages": { icon: split_scene_right, name: t("home.autoSplitPDF.title", "Auto Split Pages"), component: null, @@ -370,7 +370,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.AUTOMATION }, - [ToolId.AUTO_SPLIT_BY_SIZE_COUNT]: { + "auto-split-by-size-count": { icon: content_cut, name: t("home.autoSizeSplitPDF.title", "Auto Split by Size/Count"), component: null, @@ -383,7 +383,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Advanced Formatting - [ToolId.ADJUST_CONTRAST]: { + "adjustContrast": { icon: palette, name: t("home.adjustContrast.title", "Adjust Colors/Contrast"), component: null, @@ -392,7 +392,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.REPAIR]: { + "repair": { icon: build, name: t("home.repair.title", "Repair"), component: Repair, @@ -403,7 +403,7 @@ export function useFlatToolRegistry(): ToolRegistry { maxFiles: -1, endpoints: ["repair"] }, - [ToolId.DETECT_SPLIT_SCANNED_PHOTOS]: { + "detect-split-scanned-photos": { icon: scanner, name: t("home.ScannerImageSplit.title", "Detect & Split Scanned Photos"), component: null, @@ -412,7 +412,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.OVERLAY_PDFS]: { + "overlay-pdfs": { icon: layers, name: t("home.overlay-pdfs.title", "Overlay PDFs"), component: null, @@ -421,7 +421,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.REPLACE_AND_INVERT_COLOR]: { + "replace-and-invert-color": { icon: format_color_fill, name: t("home.replaceColorPdf.title", "Replace & Invert Color"), component: null, @@ -430,7 +430,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.ADD_IMAGE]: { + "add-image": { icon: image, name: t("home.addImage.title", "Add Image"), component: null, @@ -439,7 +439,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.EDIT_TABLE_OF_CONTENTS]: { + "edit-table-of-contents": { icon: bookmark_add, name: t("home.editTableOfContents.title", "Edit Table of Contents"), component: null, @@ -448,7 +448,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.ADVANCED_FORMATTING }, - [ToolId.SCANNER_EFFECT]: { + "scanner-effect": { icon: scanner, name: t("home.fakeScan.title", "Scanner Effect"), component: null, @@ -461,7 +461,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Developer Tools - [ToolId.SHOW_JAVASCRIPT]: { + "show-javascript": { icon: javascript, name: t("home.showJS.title", "Show JavaScript"), component: null, @@ -470,7 +470,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.ADVANCED_TOOLS, subcategoryId: SubcategoryId.DEVELOPER_TOOLS }, - [ToolId.DEV_API]: { + "dev-api": { icon: open_in_new, name: t("home.devApi.title", "API"), component: null, @@ -480,7 +480,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.DEVELOPER_TOOLS, link: "https://stirlingpdf.io/swagger-ui/5.21.0/index.html" }, - [ToolId.DEV_FOLDER_SCANNING]: { + "dev-folder-scanning": { icon: open_in_new, name: t("home.devFolderScanning.title", "Automated Folder Scanning"), component: null, @@ -490,7 +490,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.DEVELOPER_TOOLS, link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Folder%20Scanning/" }, - [ToolId.DEV_SSO_GUIDE]: { + "dev-sso-guide": { icon: open_in_new, name: t("home.devSsoGuide.title", "SSO Guide"), component: null, @@ -500,7 +500,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.DEVELOPER_TOOLS, link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Single%20Sign-On%20Configuration", }, - [ToolId.DEV_AIRGAPPED]: { + "dev-airgapped": { icon: open_in_new, name: t("home.devAirgapped.title", "Air-gapped Setup"), component: null, @@ -513,7 +513,7 @@ export function useFlatToolRegistry(): ToolRegistry { // Recommended Tools - [ToolId.COMPARE]: { + "compare": { icon: compare, name: t("home.compare.title", "Compare"), component: null, @@ -522,7 +522,7 @@ export function useFlatToolRegistry(): ToolRegistry { categoryId: ToolCategoryId.RECOMMENDED_TOOLS, subcategoryId: SubcategoryId.GENERAL }, - [ToolId.COMPRESS]: { + "compress": { icon: zoom_in_map, name: t("home.compress.title", "Compress"), component: CompressPdfPanel, @@ -532,7 +532,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.GENERAL, maxFiles: -1 }, - [ToolId.CONVERT]: { + "convert": { icon: sync_alt, name: t("home.convert.title", "Convert"), component: ConvertPanel, @@ -576,7 +576,7 @@ export function useFlatToolRegistry(): ToolRegistry { "dbf", "fods", "vsd", "vor", "vor3", "vor4", "uop", "pct", "ps", "pdf" ] }, - [ToolId.MERGE_PDFS]: { + "mergePdfs": { icon: library_add, name: t("home.merge.title", "Merge"), component: null, @@ -586,7 +586,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.GENERAL, maxFiles: -1 }, - [ToolId.MULTI_TOOL]: { + "multi-tool": { icon: dashboard_customize, name: t("home.multiTool.title", "Multi-Tool"), component: null, @@ -596,7 +596,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.GENERAL, maxFiles: -1 }, - [ToolId.OCR]: { + "ocr": { icon: quick_reference_all, name: t("home.ocr.title", "OCR"), component: OCRPanel, @@ -606,7 +606,7 @@ export function useFlatToolRegistry(): ToolRegistry { subcategoryId: SubcategoryId.GENERAL, maxFiles: -1 }, - [ToolId.REDACT]: { + "redact": { icon: visibility_off, name: t("home.redact.title", "Redact"), component: null, @@ -620,7 +620,7 @@ export function useFlatToolRegistry(): ToolRegistry { if (showPlaceholderTools) { return allTools; } else { - const filteredTools = (Object.keys(allTools) as ToolId[]) + const filteredTools = Object.keys(allTools) .filter(key => allTools[key].component !== null || allTools[key].link) .reduce((obj, key) => { obj[key] = allTools[key]; diff --git a/frontend/src/hooks/useSuggestedTools.ts b/frontend/src/hooks/useSuggestedTools.ts index 8b8809a7d..effbe2397 100644 --- a/frontend/src/hooks/useSuggestedTools.ts +++ b/frontend/src/hooks/useSuggestedTools.ts @@ -7,10 +7,9 @@ import SwapHorizIcon from '@mui/icons-material/SwapHoriz'; import CleaningServicesIcon from '@mui/icons-material/CleaningServices'; import CropIcon from '@mui/icons-material/Crop'; import TextFieldsIcon from '@mui/icons-material/TextFields'; -import { ToolId } from '../data/toolsTaxonomy'; export interface SuggestedTool { - id: ToolId; + id: string /* FIX ME: Should be ToolId */; title: string; icon: React.ComponentType; navigate: () => void; @@ -18,27 +17,27 @@ export interface SuggestedTool { const ALL_SUGGESTED_TOOLS: Omit[] = [ { - id: ToolId.COMPRESS, + id: 'compress', title: 'Compress', icon: CompressIcon }, { - id: ToolId.CONVERT, + id: 'convert', title: 'Convert', icon: SwapHorizIcon }, { - id: ToolId.SANITIZE, + id: 'sanitize', title: 'Sanitize', icon: CleaningServicesIcon }, { - id: ToolId.SPLIT_PDF, + id: 'split', title: 'Split', icon: CropIcon }, { - id: ToolId.OCR, + id: 'ocr', title: 'OCR', icon: TextFieldsIcon } diff --git a/frontend/src/hooks/useToolManagement.tsx b/frontend/src/hooks/useToolManagement.tsx index 5c3359792..a4c481fcc 100644 --- a/frontend/src/hooks/useToolManagement.tsx +++ b/frontend/src/hooks/useToolManagement.tsx @@ -1,15 +1,15 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useFlatToolRegistry } from "../data/useTranslatedToolRegistry"; -import { getAllEndpoints, ToolId, type ToolRegistryEntry } from "../data/toolsTaxonomy"; +import { getAllEndpoints, type ToolRegistryEntry } from "../data/toolsTaxonomy"; import { useMultipleEndpointsEnabled } from "./useEndpointConfig"; interface ToolManagementResult { - selectedToolKey: ToolId | null; + selectedToolKey: string | null; selectedTool: ToolRegistryEntry | null; toolSelectedFileIds: string[]; toolRegistry: Record; - selectTool: (toolKey: ToolId) => void; + selectTool: (toolKey: string) => void; clearToolSelection: () => void; setToolSelectedFileIds: (fileIds: string[]) => void; } @@ -17,7 +17,7 @@ interface ToolManagementResult { export const useToolManagement = (): ToolManagementResult => { const { t } = useTranslation(); - const [selectedToolKey, setSelectedToolKey] = useState(null); + const [selectedToolKey, setSelectedToolKey] = useState(null); const [toolSelectedFileIds, setToolSelectedFileIds] = useState([]); // Build endpoints list from registry entries with fallback to legacy mapping @@ -35,7 +35,7 @@ export const useToolManagement = (): ToolManagementResult => { const allEndpoints = useMemo(() => getAllEndpoints(baseRegistry), [baseRegistry]); const { endpointStatus, loading: endpointsLoading } = useMultipleEndpointsEnabled(allEndpoints); - const isToolAvailable = useCallback((toolKey: ToolId): boolean => { + const isToolAvailable = useCallback((toolKey: string): boolean => { if (endpointsLoading) return true; const endpoints = baseRegistry[toolKey]?.endpoints || []; return endpoints.length === 0 || endpoints.some((endpoint: string) => endpointStatus[endpoint] === true); @@ -43,7 +43,7 @@ export const useToolManagement = (): ToolManagementResult => { const toolRegistry: Record = useMemo(() => { const availableToolRegistry: Record = {}; - (Object.keys(baseRegistry) as ToolId[]).forEach(toolKey => { + Object.keys(baseRegistry).forEach(toolKey => { if (isToolAvailable(toolKey)) { const baseTool = baseRegistry[toolKey as keyof typeof baseRegistry]; availableToolRegistry[toolKey] = { @@ -58,7 +58,7 @@ export const useToolManagement = (): ToolManagementResult => { useEffect(() => { if (!endpointsLoading && selectedToolKey && !toolRegistry[selectedToolKey]) { - const firstAvailableTool = (Object.keys(toolRegistry) as ToolId[])[0]; + const firstAvailableTool = Object.keys(toolRegistry)[0]; if (firstAvailableTool) { setSelectedToolKey(firstAvailableTool); } else { @@ -67,7 +67,7 @@ export const useToolManagement = (): ToolManagementResult => { } }, [endpointsLoading, selectedToolKey, toolRegistry]); - const selectTool = useCallback((toolKey: ToolId) => { + const selectTool = useCallback((toolKey: string) => { setSelectedToolKey(toolKey); }, []); diff --git a/frontend/src/hooks/useToolSections.ts b/frontend/src/hooks/useToolSections.ts index b3d862799..41762a8e1 100644 --- a/frontend/src/hooks/useToolSections.ts +++ b/frontend/src/hooks/useToolSections.ts @@ -1,10 +1,10 @@ import { useMemo } from 'react'; -import { SUBCATEGORY_ORDER, SubcategoryId, ToolCategoryId, ToolId, ToolRegistryEntry } from '../data/toolsTaxonomy'; +import { SUBCATEGORY_ORDER, SubcategoryId, ToolCategoryId, ToolRegistryEntry } from '../data/toolsTaxonomy'; import { useTranslation } from 'react-i18next'; type SubcategoryIdMap = { - [subcategoryId in SubcategoryId]: Array<{ id: ToolId; tool: ToolRegistryEntry }>; + [subcategoryId in SubcategoryId]: Array<{ id: string /* FIX ME: Should be ToolId */; tool: ToolRegistryEntry }>; } type GroupedTools = { @@ -14,7 +14,7 @@ type GroupedTools = { export interface SubcategoryGroup { subcategoryId: SubcategoryId; tools: { - id: ToolId; + id: string /* FIX ME: Should be ToolId */; tool: ToolRegistryEntry; }[]; }; @@ -27,7 +27,7 @@ export interface ToolSection { subcategories: SubcategoryGroup[]; }; -export function useToolSections(filteredTools: [ToolId, ToolRegistryEntry][]) { +export function useToolSections(filteredTools: [string /* FIX ME: Should be ToolId */, ToolRegistryEntry][]) { const { t } = useTranslation(); const groupedTools = useMemo(() => { @@ -91,9 +91,9 @@ export function useToolSections(filteredTools: [ToolId, ToolRegistryEntry][]) { const searchGroups: SubcategoryGroup[] = useMemo(() => { const subMap = {} as SubcategoryIdMap; - const seen = new Set(); + const seen = new Set(); filteredTools.forEach(([id, tool]) => { - const toolId = id as ToolId; + const toolId = id as string /* FIX ME: Should be ToolId */; if (seen.has(toolId)) return; seen.add(toolId); const sub = tool.subcategoryId;