Refactor tooltips, context, and update dependencies

Refactored tooltip and context usage for improved flexibility and error handling. Updated dependency versions for posthog-js and react-router-dom. Improved i18n usage in tool step components, restructured FileContext for better persistence management, and enhanced hooks for parameter handling. Minor code cleanups and optimizations throughout.
This commit is contained in:
Ludy87 2025-09-24 19:44:30 +02:00
parent 885d0d4404
commit c6cf5bccf0
No known key found for this signature in database
GPG Key ID: 92696155E0220F94
12 changed files with 125 additions and 92 deletions

View File

@ -49,11 +49,11 @@
"license-report": "^6.8.0", "license-report": "^6.8.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"pdfjs-dist": "^5.4.149", "pdfjs-dist": "^5.4.149",
"posthog-js": "^1.268.3", "posthog-js": "^1.268.4",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-i18next": "^15.7.3", "react-i18next": "^15.7.3",
"react-router-dom": "^7.9.1", "react-router-dom": "^7.9.2",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",
"web-vitals": "^5.1.0" "web-vitals": "^5.1.0"
}, },
@ -2460,9 +2460,9 @@
} }
}, },
"node_modules/@posthog/core": { "node_modules/@posthog/core": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.2.1.tgz",
"integrity": "sha512-JuVWgEiOeEfjNtxKg3Kxvt/YWbZCilZUnezUCSAUPQoKxM0VAzMYklh6u/+wxwWybSQ9NaStcNhkxnSU4OxqWA==", "integrity": "sha512-zNw96BipqM5/Tf161Q8/K5zpwGY3ezfb2wz+Yc3fIT5OQHW8eEzkQldPgtFKMUkqImc73ukEa2IdUpS6vEGH7w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@rolldown/pluginutils": { "node_modules/@rolldown/pluginutils": {
@ -5481,9 +5481,9 @@
} }
}, },
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.1.0", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.1.tgz",
"integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==", "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -10042,12 +10042,12 @@
} }
}, },
"node_modules/posthog-js": { "node_modules/posthog-js": {
"version": "1.268.3", "version": "1.268.4",
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.268.3.tgz", "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.268.4.tgz",
"integrity": "sha512-1F5MA9YPNKHkCodPi9VOv83dSDRf7xQpeOIjP0ww9isE+hlK7ogqoC/ZgO3bks4Du5yYazr4Tu7tlZDbkDCXfg==", "integrity": "sha512-kbE8SeH4Hi6uETEzO4EVANULz1ncw+PXC/SMfDdByf4Qt0a/AKoxjlGCZwHuZuflQmBfTwwQcjHeQxnmIxti1A==",
"license": "SEE LICENSE IN LICENSE", "license": "SEE LICENSE IN LICENSE",
"dependencies": { "dependencies": {
"@posthog/core": "1.2.0", "@posthog/core": "1.2.1",
"core-js": "^3.38.1", "core-js": "^3.38.1",
"fflate": "^0.4.8", "fflate": "^0.4.8",
"preact": "^10.19.3", "preact": "^10.19.3",
@ -10465,9 +10465,9 @@
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "7.9.1", "version": "7.9.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.2.tgz",
"integrity": "sha512-pfAByjcTpX55mqSDGwGnY9vDCpxqBLASg0BMNAuMmpSGESo/TaOUG6BllhAtAkCGx8Rnohik/XtaqiYUJtgW2g==", "integrity": "sha512-i2TPp4dgaqrOqiRGLZmqh2WXmbdFknUyiCRmSKs0hf6fWXkTKg5h56b+9F22NbGRAMxjYfqQnpi63egzD2SuZA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cookie": "^1.0.1", "cookie": "^1.0.1",
@ -10487,12 +10487,12 @@
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "7.9.1", "version": "7.9.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.1.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.2.tgz",
"integrity": "sha512-U9WBQssBE9B1vmRjo9qTM7YRzfZ3lUxESIZnsf4VjR/lXYz9MHjvOxHzr/aUm4efpktbVOrF09rL/y4VHa8RMw==", "integrity": "sha512-pagqpVJnjZOfb+vIM23eTp7Sp/AAJjOgaowhP1f1TWOdk5/W8Uk8d/M/0wfleqx7SgjitjNPPsKeCZE1hTSp3w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"react-router": "7.9.1" "react-router": "7.9.2"
}, },
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=20.0.0"

View File

@ -45,11 +45,11 @@
"license-report": "^6.8.0", "license-report": "^6.8.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"pdfjs-dist": "^5.4.149", "pdfjs-dist": "^5.4.149",
"posthog-js": "^1.268.3", "posthog-js": "^1.268.4",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-i18next": "^15.7.3", "react-i18next": "^15.7.3",
"react-router-dom": "^7.9.1", "react-router-dom": "^7.9.2",
"tailwindcss": "^4.1.13", "tailwindcss": "^4.1.13",
"web-vitals": "^5.1.0" "web-vitals": "^5.1.0"
}, },
@ -97,7 +97,6 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"eslint-plugin-react": "^7.37.5",
"@eslint/js": "^9.36.0", "@eslint/js": "^9.36.0",
"@iconify-json/material-symbols": "^1.2.38", "@iconify-json/material-symbols": "^1.2.38",
"@iconify/utils": "^3.0.2", "@iconify/utils": "^3.0.2",
@ -114,6 +113,7 @@
"@vitejs/plugin-react-swc": "^4.1.0", "@vitejs/plugin-react-swc": "^4.1.0",
"@vitest/coverage-v8": "^3.2.4", "@vitest/coverage-v8": "^3.2.4",
"eslint": "^9.36.0", "eslint": "^9.36.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-hooks": "^5.2.0",
"globals": "^16.4.0", "globals": "^16.4.0",
"jsdom": "^27.0.0", "jsdom": "^27.0.0",

View File

@ -24,10 +24,10 @@ const ToolChain: React.FC<ToolChainProps> = ({
size = 'xs', size = 'xs',
color = 'var(--mantine-color-blue-7)' color = 'var(--mantine-color-blue-7)'
}) => { }) => {
if (!toolChain || toolChain.length === 0) return null;
const { t } = useTranslation(); const { t } = useTranslation();
if (!toolChain || toolChain.length === 0) return null;
const toolIds = toolChain.map(tool => tool.toolId); const toolIds = toolChain.map(tool => tool.toolId);
const getToolName = (toolId: ToolId) => { const getToolName = (toolId: ToolId) => {

View File

@ -5,7 +5,7 @@ import { addEventListenerWithCleanup } from '../../utils/genericUtils';
import { useTooltipPosition } from '../../hooks/useTooltipPosition'; import { useTooltipPosition } from '../../hooks/useTooltipPosition';
import { TooltipTip } from '../../types/tips'; import { TooltipTip } from '../../types/tips';
import { TooltipContent } from './tooltip/TooltipContent'; import { TooltipContent } from './tooltip/TooltipContent';
import { useSidebarContext } from '../../contexts/SidebarContext'; import { useOptionalSidebarContext } from '../../contexts/SidebarContext';
import styles from './tooltip/Tooltip.module.css'; import styles from './tooltip/Tooltip.module.css';
export interface TooltipProps { export interface TooltipProps {
@ -64,7 +64,14 @@ export const Tooltip: React.FC<TooltipProps> = ({
} }
}, []); }, []);
const sidebarContext = sidebarTooltip ? useSidebarContext() : null; const sidebarContext = useOptionalSidebarContext();
const effectiveSidebarContext = sidebarTooltip ? sidebarContext : undefined;
useEffect(() => {
if (sidebarTooltip && !sidebarContext) {
console.warn('Sidebar tooltip requested without SidebarProvider context.');
}
}, [sidebarTooltip, sidebarContext]);
const isControlled = controlledOpen !== undefined; const isControlled = controlledOpen !== undefined;
const open = isControlled ? !!controlledOpen : internalOpen; const open = isControlled ? !!controlledOpen : internalOpen;
@ -86,8 +93,8 @@ export const Tooltip: React.FC<TooltipProps> = ({
gap, gap,
triggerRef, triggerRef,
tooltipRef, tooltipRef,
sidebarRefs: sidebarContext?.sidebarRefs, sidebarRefs: effectiveSidebarContext?.sidebarRefs,
sidebarState: sidebarContext?.sidebarState, sidebarState: effectiveSidebarContext?.sidebarState,
}); });
// Close on outside click: pinned → close; not pinned → optionally close // Close on outside click: pinned → close; not pinned → optionally close

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import i18n from '../../../i18n';
import FileStatusIndicator from './FileStatusIndicator'; import FileStatusIndicator from './FileStatusIndicator';
import { StirlingFile } from '../../../types/fileContext'; import { StirlingFile } from '../../../types/fileContext';
@ -14,9 +14,9 @@ export function createFilesToolStep(
createStep: (title: string, props: any, children?: React.ReactNode) => React.ReactElement, createStep: (title: string, props: any, children?: React.ReactNode) => React.ReactElement,
props: FilesToolStepProps props: FilesToolStepProps
): React.ReactElement { ): React.ReactElement {
const { t } = useTranslation(); const title = i18n.t('files.title', { defaultValue: 'Files' });
return createStep(t("files.title", "Files"), { return createStep(title, {
isVisible: true, isVisible: true,
isCollapsed: props.isCollapsed, isCollapsed: props.isCollapsed,
onCollapsedClick: props.onCollapsedClick onCollapsedClick: props.onCollapsedClick

View File

@ -1,6 +1,7 @@
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { Button, Stack } from "@mantine/core"; import { Button, Stack } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import i18n from "../../../i18n";
import DownloadIcon from "@mui/icons-material/Download"; import DownloadIcon from "@mui/icons-material/Download";
import UndoIcon from "@mui/icons-material/Undo"; import UndoIcon from "@mui/icons-material/Undo";
import ErrorNotification from "./ErrorNotification"; import ErrorNotification from "./ErrorNotification";
@ -107,10 +108,10 @@ export function createReviewToolStep<TParams = unknown>(
createStep: (title: string, props: any, children?: React.ReactNode) => React.ReactElement, createStep: (title: string, props: any, children?: React.ReactNode) => React.ReactElement,
props: ReviewToolStepProps<TParams> props: ReviewToolStepProps<TParams>
): React.ReactElement { ): React.ReactElement {
const { t } = useTranslation(); const title = i18n.t("review", { defaultValue: "Review" });
return createStep( return createStep(
t("review", "Review"), title,
{ {
isVisible: props.isVisible, isVisible: props.isVisible,
isCollapsed: props.isCollapsed, isCollapsed: props.isCollapsed,

View File

@ -80,8 +80,6 @@ const ToolStep = ({
alwaysShowTooltip = false, alwaysShowTooltip = false,
tooltip tooltip
}: ToolStepProps) => { }: ToolStepProps) => {
if (!isVisible) return null;
const parent = useContext(ToolStepContext); const parent = useContext(ToolStepContext);
// Auto-detect if we should show numbers based on sibling count or force option // Auto-detect if we should show numbers based on sibling count or force option
@ -91,6 +89,8 @@ const ToolStep = ({
return parent ? parent.visibleStepCount >= 3 : false; // Auto-detect return parent ? parent.visibleStepCount >= 3 : false; // Auto-detect
}, [showNumber, parent]); }, [showNumber, parent]);
if (!isVisible) return null;
const stepNumber = _stepNumber; const stepNumber = _stepNumber;
return ( return (

View File

@ -1,11 +1,15 @@
import { useTranslation } from 'react-i18next'; import { useMemo } from 'react';
import { useTranslation, type TFunction } from 'react-i18next';
import { TooltipContent } from '../../types/tips'; import { TooltipContent } from '../../types/tips';
import { SPLIT_METHODS, type SplitMethod } from '../../constants/splitConstants'; import { SPLIT_METHODS, type SplitMethod } from '../../constants/splitConstants';
export const useSplitSettingsTips = (method: SplitMethod | ''): TooltipContent | null => { export const getSplitSettingsTips = (
const { t } = useTranslation(); t: TFunction,
method: SplitMethod | ''
if (!method) return null; ): TooltipContent | null => {
if (!method) {
return null;
}
const tooltipMap: Record<SplitMethod, TooltipContent> = { const tooltipMap: Record<SplitMethod, TooltipContent> = {
[SPLIT_METHODS.BY_PAGES]: { [SPLIT_METHODS.BY_PAGES]: {
@ -132,3 +136,9 @@ export const useSplitSettingsTips = (method: SplitMethod | ''): TooltipContent |
return tooltipMap[method]; return tooltipMap[method];
}; };
export const useSplitSettingsTips = (method: SplitMethod | ''): TooltipContent | null => {
const { t } = useTranslation();
return useMemo(() => getSplitSettingsTips(t, method), [t, method]);
};

View File

@ -1,7 +1,12 @@
import { useAppConfig } from '../hooks/useAppConfig'; import { useAppConfig, type AppConfig } from '../hooks/useAppConfig';
// Get base URL from app config with fallback // Get base URL from app config with fallback
export const getBaseUrl = (): string => { export const DEFAULT_BASE_URL = 'https://stirling.com';
export const getBaseUrlFromConfig = (config?: AppConfig | null): string =>
config?.baseUrl || DEFAULT_BASE_URL;
// Hook to access the base URL within React components
export const useBaseUrl = (): string => {
const { config } = useAppConfig(); const { config } = useAppConfig();
return config?.baseUrl || 'https://stirling.com'; return getBaseUrlFromConfig(config);
}; };

View File

@ -34,16 +34,19 @@ import { IndexedDBProvider, useIndexedDB } from './IndexedDBContext';
const DEBUG = process.env.NODE_ENV === 'development'; const DEBUG = process.env.NODE_ENV === 'development';
type IndexedDBApi = ReturnType<typeof useIndexedDB>;
// Inner provider component that has access to IndexedDB // Inner provider component that has access to IndexedDB
function FileContextInner({ function FileContextContent({
children, children,
enablePersistence = true enablePersistence = true,
}: FileContextProviderProps) { indexedDB
}: FileContextProviderProps & { indexedDB: IndexedDBApi | null }) {
const [state, dispatch] = useReducer(fileContextReducer, initialFileContextState); const [state, dispatch] = useReducer(fileContextReducer, initialFileContextState);
// IndexedDB context for persistence // IndexedDB context for persistence
const indexedDB = enablePersistence ? useIndexedDB() : null; const persistenceApi = enablePersistence ? indexedDB : null;
// File ref map - stores File objects outside React state // File ref map - stores File objects outside React state
const filesRef = useRef<Map<FileId, File>>(new Map()); const filesRef = useRef<Map<FileId, File>>(new Map());
@ -72,11 +75,11 @@ function FileContextInner({
dispatch({ type: 'SET_UNSAVED_CHANGES', payload: { hasChanges } }); dispatch({ type: 'SET_UNSAVED_CHANGES', payload: { hasChanges } });
}, []); }, []);
const selectFiles = (stirlingFiles: StirlingFile[]) => { const selectFiles = useCallback((stirlingFiles: StirlingFile[]) => {
const currentSelection = stateRef.current.ui.selectedFileIds; const currentSelection = stateRef.current.ui.selectedFileIds;
const newFileIds = stirlingFiles.map(stirlingFile => stirlingFile.fileId); const newFileIds = stirlingFiles.map(stirlingFile => stirlingFile.fileId);
dispatch({ type: 'SET_SELECTED_FILES', payload: { fileIds: [...currentSelection, ...newFileIds] } }); dispatch({ type: 'SET_SELECTED_FILES', payload: { fileIds: [...currentSelection, ...newFileIds] } });
} }, [dispatch]);
// File operations using unified addFiles helper with persistence // File operations using unified addFiles helper with persistence
const addRawFiles = useCallback(async (files: File[], options?: { insertAfterPageId?: string; selectFiles?: boolean }): Promise<StirlingFile[]> => { const addRawFiles = useCallback(async (files: File[], options?: { insertAfterPageId?: string; selectFiles?: boolean }): Promise<StirlingFile[]> => {
@ -88,7 +91,7 @@ function FileContextInner({
} }
return stirlingFiles; return stirlingFiles;
}, [enablePersistence]); }, [enablePersistence, lifecycleManager, selectFiles]);
const addStirlingFileStubsAction = useCallback(async (stirlingFileStubs: StirlingFileStub[], options?: { insertAfterPageId?: string; selectFiles?: boolean }): Promise<StirlingFile[]> => { const addStirlingFileStubsAction = useCallback(async (stirlingFileStubs: StirlingFileStub[], options?: { insertAfterPageId?: string; selectFiles?: boolean }): Promise<StirlingFile[]> => {
// StirlingFileStubs preserve all metadata - perfect for FileManager use case! // StirlingFileStubs preserve all metadata - perfect for FileManager use case!
@ -100,7 +103,7 @@ function FileContextInner({
} }
return result; return result;
}, []); }, [lifecycleManager, selectFiles]);
// Action creators // Action creators
@ -112,8 +115,8 @@ function FileContextInner({
}, []); }, []);
const undoConsumeFilesWrapper = useCallback(async (inputFiles: File[], inputStirlingFileStubs: StirlingFileStub[], outputFileIds: FileId[]): Promise<void> => { const undoConsumeFilesWrapper = useCallback(async (inputFiles: File[], inputStirlingFileStubs: StirlingFileStub[], outputFileIds: FileId[]): Promise<void> => {
return undoConsumeFiles(inputFiles, inputStirlingFileStubs, outputFileIds, filesRef, dispatch, indexedDB); return undoConsumeFiles(inputFiles, inputStirlingFileStubs, outputFileIds, filesRef, dispatch, persistenceApi);
}, [indexedDB]); }, [persistenceApi]);
// File pinning functions - use StirlingFile directly // File pinning functions - use StirlingFile directly
const pinFileWrapper = useCallback((file: StirlingFile) => { const pinFileWrapper = useCallback((file: StirlingFile) => {
@ -134,9 +137,9 @@ function FileContextInner({
lifecycleManager.removeFiles(fileIds, stateRef); lifecycleManager.removeFiles(fileIds, stateRef);
// Remove from IndexedDB if enabled // Remove from IndexedDB if enabled
if (indexedDB && enablePersistence && deleteFromStorage !== false) { if (persistenceApi && enablePersistence && deleteFromStorage !== false) {
try { try {
await indexedDB.deleteMultiple(fileIds); await persistenceApi.deleteMultiple(fileIds);
} catch (error) { } catch (error) {
console.error('Failed to delete files from IndexedDB:', error); console.error('Failed to delete files from IndexedDB:', error);
} }
@ -162,9 +165,9 @@ function FileContextInner({
dispatch({ type: 'RESET_CONTEXT' }); dispatch({ type: 'RESET_CONTEXT' });
// Then clear IndexedDB storage // Then clear IndexedDB storage
if (indexedDB && enablePersistence) { if (persistenceApi && enablePersistence) {
try { try {
await indexedDB.clearAll(); await persistenceApi.clearAll();
} catch (error) { } catch (error) {
console.error('Failed to clear IndexedDB:', error); console.error('Failed to clear IndexedDB:', error);
} }
@ -190,7 +193,7 @@ function FileContextInner({
undoConsumeFilesWrapper, undoConsumeFilesWrapper,
pinFileWrapper, pinFileWrapper,
unpinFileWrapper, unpinFileWrapper,
indexedDB, persistenceApi,
enablePersistence enablePersistence
]); ]);
@ -229,31 +232,38 @@ function FileContextInner({
); );
} }
function FileContextWithPersistence(props: FileContextProviderProps) {
const indexedDB = useIndexedDB();
return <FileContextContent {...props} indexedDB={indexedDB} />;
}
// Outer provider component that wraps with IndexedDBProvider // Outer provider component that wraps with IndexedDBProvider
export function FileContextProvider({ export function FileContextProvider({
children, children,
enableUrlSync = true, enableUrlSync = true,
enablePersistence = true enablePersistence = true,
...rest
}: FileContextProviderProps) { }: FileContextProviderProps) {
const sharedProps = {
children,
enableUrlSync,
enablePersistence,
...rest
};
if (enablePersistence) { if (enablePersistence) {
return ( return (
<IndexedDBProvider> <IndexedDBProvider>
<FileContextInner <FileContextWithPersistence {...sharedProps} />
enableUrlSync={enableUrlSync}
enablePersistence={enablePersistence}
>
{children}
</FileContextInner>
</IndexedDBProvider> </IndexedDBProvider>
); );
} else { } else {
return ( return (
<FileContextInner <FileContextContent
enableUrlSync={enableUrlSync} {...sharedProps}
enablePersistence={enablePersistence} indexedDB={null}
> />
{children}
</FileContextInner>
); );
} }
} }

View File

@ -15,8 +15,12 @@ export interface BaseParametersConfig<T> {
validateFn?: (params: T) => boolean; validateFn?: (params: T) => boolean;
} }
export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParametersHook<T> { export function useBaseParameters<T>({
const [parameters, setParameters] = useState<T>(config.defaultParameters); defaultParameters,
endpointName,
validateFn
}: BaseParametersConfig<T>): BaseParametersHook<T> {
const [parameters, setParameters] = useState<T>(defaultParameters);
const updateParameter = useCallback(<K extends keyof T>(parameter: K, value: T[K]) => { const updateParameter = useCallback(<K extends keyof T>(parameter: K, value: T[K]) => {
setParameters(prev => ({ setParameters(prev => ({
@ -26,24 +30,19 @@ export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParam
}, []); }, []);
const resetParameters = useCallback(() => { const resetParameters = useCallback(() => {
setParameters(config.defaultParameters); setParameters(defaultParameters);
}, [config.defaultParameters]); }, [defaultParameters]);
const validateParameters = useCallback(() => { const validateParameters = useCallback(() => {
return config.validateFn ? config.validateFn(parameters) : true; return validateFn ? validateFn(parameters) : true;
}, [parameters, config.validateFn]); }, [parameters, validateFn]);
const getEndpointName = useCallback(() => {
const endpointName = config.endpointName; if (typeof endpointName === "string") {
let getEndpointName: () => string;
if (typeof endpointName === "string") {
getEndpointName = useCallback(() => {
return endpointName; return endpointName;
}, []); } else {
} else {
getEndpointName = useCallback(() => {
return endpointName(parameters); return endpointName(parameters);
}, [parameters]); }
} }, [endpointName, parameters]);
return { return {
parameters, parameters,

View File

@ -1,3 +1,4 @@
import { useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { createToolFlow } from "../components/tools/shared/createToolFlow"; import { createToolFlow } from "../components/tools/shared/createToolFlow";
import CardSelector from "../components/shared/CardSelector"; import CardSelector from "../components/shared/CardSelector";
@ -6,7 +7,7 @@ import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation"; import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
import { useBaseTool } from "../hooks/tools/shared/useBaseTool"; import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
import { useSplitMethodTips } from "../components/tooltips/useSplitMethodTips"; import { useSplitMethodTips } from "../components/tooltips/useSplitMethodTips";
import { useSplitSettingsTips } from "../components/tooltips/useSplitSettingsTips"; import { useSplitSettingsTips, getSplitSettingsTips } from "../components/tooltips/useSplitSettingsTips";
import { BaseToolProps, ToolComponent } from "../types/tool"; import { BaseToolProps, ToolComponent } from "../types/tool";
import { type SplitMethod, METHOD_OPTIONS, type MethodOption } from "../constants/splitConstants"; import { type SplitMethod, METHOD_OPTIONS, type MethodOption } from "../constants/splitConstants";
@ -24,10 +25,10 @@ const Split = (props: BaseToolProps) => {
const settingsTips = useSplitSettingsTips(base.params.parameters.method); const settingsTips = useSplitSettingsTips(base.params.parameters.method);
// Get tooltip content for a specific method // Get tooltip content for a specific method
const getMethodTooltip = (option: MethodOption) => { const getMethodTooltip = useCallback((option: MethodOption) => {
const tooltipContent = useSplitSettingsTips(option.value); const tooltipContent = getSplitSettingsTips(t, option.value);
return tooltipContent?.tips || []; return tooltipContent?.tips || [];
}; }, [t]);
// Get the method name for the settings step title // Get the method name for the settings step title
const getSettingsTitle = () => { const getSettingsTitle = () => {