Revert change to add ToolId

This commit is contained in:
James Brunton 2025-08-22 12:20:34 +01:00
parent c2feebc6a5
commit f1757f8b31
11 changed files with 113 additions and 174 deletions

View File

@ -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');

View File

@ -18,7 +18,6 @@ import {
getNavButtonStyle,
getActiveNavButton,
} from './quickAccessBar/QuickAccessBar';
import { ToolId } from "../../data/toolsTaxonomy";
const QuickAccessBar = forwardRef<HTMLDivElement>(({
}, ref) => {
@ -43,20 +42,20 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
const buttonConfigs: ButtonConfig[] = [
{
id: ToolId.READ,
id: 'read',
name: t("quickAccess.read", "Read"),
icon: <MenuBookIcon sx={{ fontSize: "1.5rem" }} />,
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:
<span className="material-symbols-rounded font-size-20">
@ -67,11 +66,11 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
type: 'navigation',
onClick: () => {
setActiveButton('sign');
handleToolSelect(ToolId.SIGN);
handleToolSelect('sign');
}
},
{
id: ToolId.AUTOMATE,
id: 'automate',
name: t("quickAccess.automate", "Automate"),
icon:
<span className="material-symbols-rounded font-size-20">
@ -81,8 +80,8 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
isRound: false,
type: 'navigation',
onClick: () => {
setActiveButton(ToolId.AUTOMATE);
handleToolSelect(ToolId.AUTOMATE);
setActiveButton('automate');
handleToolSelect('automate');
}
},
{

View File

@ -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<SearchResultsProps> = ({ filteredTools, onSelect }) => {

View File

@ -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
) => (
<Box key={subcategory.subcategoryId} w="100%">
@ -29,7 +29,7 @@ const renderToolButtons = (
<SubcategoryHeader label={getSubcategoryLabel(t, subcategory.subcategoryId)} />
)}
<Stack gap="xs">
{subcategory.tools.map(({ id, tool }) => (
{subcategory.tools.map(({ id, tool }: { id: string; tool: any }) => (
<ToolButton
key={id}
id={id}

View File

@ -1,18 +1,18 @@
import React from "react";
import { Button } from "@mantine/core";
import { Tooltip } from "../../shared/Tooltip";
import { ToolId, ToolRegistryEntry } from "../../../data/toolsTaxonomy";
import { ToolRegistryEntry } from "../../../data/toolsTaxonomy";
import FitText from "../../shared/FitText";
interface ToolButtonProps {
id: ToolId;
id: string;
tool: ToolRegistryEntry;
isSelected: boolean;
onSelect: (id: ToolId) => void;
onSelect: (id: string) => void;
}
const ToolButton: React.FC<ToolButtonProps> = ({ 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');

View File

@ -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]);

View File

@ -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<ToolId, ToolRegistryEntry>;
export type ToolRegistry = Record<string /* FIX ME: Should be ToolId */, ToolRegistryEntry>;
export const SUBCATEGORY_ORDER: SubcategoryId[] = [
SubcategoryId.SIGNING,

View File

@ -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: <span className="material-symbols-rounded">workspace_premium</span>,
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: <span className="material-symbols-rounded">signature</span>,
name: t("home.sign.title", "Sign"),
component: null,
@ -45,7 +45,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Document Security
[ToolId.ADD_PASSWORD]: {
"addPassword": {
icon: <span className="material-symbols-rounded">password</span>,
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: <span className="material-symbols-rounded">branding_watermark</span>,
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: <span className="material-symbols-rounded">approval</span>,
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: <span className="material-symbols-rounded">cleaning_services</span>,
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: <span className="material-symbols-rounded">layers_clear</span>,
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: <span className="material-symbols-rounded">preview_off</span>,
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: <span className="material-symbols-rounded">license</span>,
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: <span className="material-symbols-rounded">lock</span>,
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: <span className="material-symbols-rounded">fact_check</span>,
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: <span className="material-symbols-rounded">verified</span>,
name: t("home.validateSignature.title", "Validate PDF Signature"),
component: null,
@ -151,7 +151,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Document Review
[ToolId.READ]: {
"read": {
icon: <span className="material-symbols-rounded">article</span>,
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: <span className="material-symbols-rounded">assignment</span>,
name: t("home.changeMetadata.title", "Change Metadata"),
component: null,
@ -171,7 +171,7 @@ export function useFlatToolRegistry(): ToolRegistry {
},
// Page Formatting
[ToolId.CROP_PDF]: {
"cropPdf": {
icon: <span className="material-symbols-rounded">crop</span>,
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: <span className="material-symbols-rounded">rotate_right</span>,
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: <span className="material-symbols-rounded">content_cut</span>,
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: <span className="material-symbols-rounded">move_down</span>,
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: <span className="material-symbols-rounded">crop_free</span>,
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: <span className="material-symbols-rounded">123</span>,
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: <span className="material-symbols-rounded">dashboard</span>,
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: <span className="material-symbols-rounded">looks_one</span>,
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: <span className="material-symbols-rounded">attachment</span>,
name: t("home.attachments.title", "Add Attachments"),
component: null,
@ -258,7 +258,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Extraction
[ToolId.EXTRACT_PAGES]: {
"extractPages": {
icon: <span className="material-symbols-rounded">upload</span>,
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: <span className="material-symbols-rounded">filter</span>,
name: t("home.extractImages.title", "Extract Images"),
component: null,
@ -280,7 +280,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Removal
[ToolId.REMOVE_PAGES]: {
"removePages": {
icon: <span className="material-symbols-rounded">delete</span>,
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: <span className="material-symbols-rounded">scan_delete</span>,
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: <span className="material-symbols-rounded">thread_unread</span>,
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: <span className="material-symbols-rounded">remove_selection</span>,
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: <span className="material-symbols-rounded">lock_open_right</span>,
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: <span className="material-symbols-rounded">remove_moderator</span>,
name: t("home.removeCertSign.title", "Remove Certificate Sign"),
component: RemoveCertificateSign,
@ -343,7 +343,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Automation
[ToolId.AUTOMATE]: {
"automate": {
icon: <span className="material-symbols-rounded">automation</span>,
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: <span className="material-symbols-rounded">match_word</span>,
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: <span className="material-symbols-rounded">split_scene_right</span>,
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: <span className="material-symbols-rounded">content_cut</span>,
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: <span className="material-symbols-rounded">palette</span>,
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: <span className="material-symbols-rounded">build</span>,
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: <span className="material-symbols-rounded">scanner</span>,
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: <span className="material-symbols-rounded">layers</span>,
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: <span className="material-symbols-rounded">format_color_fill</span>,
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: <span className="material-symbols-rounded">image</span>,
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: <span className="material-symbols-rounded">bookmark_add</span>,
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: <span className="material-symbols-rounded">scanner</span>,
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: <span className="material-symbols-rounded">javascript</span>,
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: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
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: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
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: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
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: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
name: t("home.devAirgapped.title", "Air-gapped Setup"),
component: null,
@ -513,7 +513,7 @@ export function useFlatToolRegistry(): ToolRegistry {
// Recommended Tools
[ToolId.COMPARE]: {
"compare": {
icon: <span className="material-symbols-rounded">compare</span>,
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: <span className="material-symbols-rounded">zoom_in_map</span>,
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: <span className="material-symbols-rounded">sync_alt</span>,
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: <span className="material-symbols-rounded">library_add</span>,
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: <span className="material-symbols-rounded">dashboard_customize</span>,
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: <span className="material-symbols-rounded">quick_reference_all</span>,
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: <span className="material-symbols-rounded">visibility_off</span>,
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];

View File

@ -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<any>;
navigate: () => void;
@ -18,27 +17,27 @@ export interface SuggestedTool {
const ALL_SUGGESTED_TOOLS: Omit<SuggestedTool, 'navigate'>[] = [
{
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
}

View File

@ -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<string, ToolRegistryEntry>;
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<ToolId | null>(null);
const [selectedToolKey, setSelectedToolKey] = useState<string /* FIX ME: Should be ToolId */ | null>(null);
const [toolSelectedFileIds, setToolSelectedFileIds] = useState<string[]>([]);
// 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<string, ToolRegistryEntry> = useMemo(() => {
const availableToolRegistry: Record<string, ToolRegistryEntry> = {};
(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);
}, []);

View File

@ -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<ToolId>();
const seen = new Set<string /* FIX ME: Should be ToolId */>();
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;