mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
Desktop connection SaaS: config, billing, team support (#5768)
Co-authored-by: James Brunton <[email protected]> Co-authored-by: James Brunton <[email protected]>
This commit is contained in:
co-authored by
James Brunton
James Brunton
parent
86072ec91a
commit
5c39acecd8
@@ -1,10 +1,11 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import apiClient from '@app/services/apiClient';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ConvertParameters, defaultParameters } from '@app/hooks/tools/convert/useConvertParameters';
|
||||
import { createFileFromApiResponse } from '@app/utils/fileResponseUtils';
|
||||
import { useToolOperation, ToolType, CustomProcessorResult } from '@app/hooks/tools/shared/useToolOperation';
|
||||
import { getEndpointUrl, isImageFormat, isWebFormat, isOfficeFormat } from '@app/utils/convertUtils';
|
||||
import { getEndpointUrl, getEndpointName, isImageFormat, isWebFormat, isOfficeFormat } from '@app/utils/convertUtils';
|
||||
import { useToolCloudStatus } from '@app/hooks/useToolCloudStatus';
|
||||
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const shouldProcessFilesSeparately = (
|
||||
@@ -195,9 +196,21 @@ export const convertOperationConfig = {
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useConvertOperation = () => {
|
||||
export const useConvertOperation = (parameters?: ConvertParameters) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Calculate current endpoint name for cloud detection
|
||||
const currentEndpointName = useMemo(() => {
|
||||
if (!parameters?.fromExtension || !parameters?.toExtension) return undefined;
|
||||
|
||||
// Map PDF/X to use PDF/A endpoint (same as in convertProcessor)
|
||||
const actualToExtension = parameters.toExtension === 'pdfx' ? 'pdfa' : parameters.toExtension;
|
||||
return getEndpointName(parameters.fromExtension, actualToExtension);
|
||||
}, [parameters?.fromExtension, parameters?.toExtension]);
|
||||
|
||||
// Check if current conversion will use cloud
|
||||
const willUseCloud = useToolCloudStatus(currentEndpointName);
|
||||
|
||||
const customConvertProcessor = useCallback(async (
|
||||
parameters: ConvertParameters,
|
||||
selectedFiles: File[]
|
||||
@@ -205,7 +218,7 @@ export const useConvertOperation = () => {
|
||||
return convertProcessor(parameters, selectedFiles);
|
||||
}, []);
|
||||
|
||||
return useToolOperation<ConvertParameters>({
|
||||
const operation = useToolOperation<ConvertParameters>({
|
||||
...convertOperationConfig,
|
||||
customProcessor: customConvertProcessor, // Use instance-specific processor for translation support
|
||||
getErrorMessage: (error) => {
|
||||
@@ -218,4 +231,10 @@ export const useConvertOperation = () => {
|
||||
return t("convert.errorConversion", "An error occurred while converting the file.");
|
||||
},
|
||||
});
|
||||
|
||||
// Override willUseCloud with our calculated value
|
||||
return {
|
||||
...operation,
|
||||
willUseCloud,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@ import { createNewStirlingFileStub } from '@app/types/fileContext';
|
||||
import { ToolOperation } from '@app/types/file';
|
||||
import { ToolId } from '@app/types/toolId';
|
||||
import { ensureBackendReady } from '@app/services/backendReadinessGuard';
|
||||
import { useWillUseCloud } from '@app/hooks/useWillUseCloud';
|
||||
import { useCreditCheck } from '@app/hooks/useCreditCheck';
|
||||
|
||||
// Re-export for backwards compatibility
|
||||
export type { ProcessingProgress, ResponseHandler };
|
||||
@@ -147,6 +149,7 @@ export interface ToolOperationHook<TParams = void> {
|
||||
status: string;
|
||||
errorMessage: string | null;
|
||||
progress: ProcessingProgress | null;
|
||||
willUseCloud?: boolean;
|
||||
|
||||
// Actions
|
||||
executeOperation: (params: TParams, selectedFiles: StirlingFile[]) => Promise<void>;
|
||||
@@ -183,6 +186,16 @@ export const useToolOperation = <TParams>(
|
||||
const { processFiles, cancelOperation: cancelApiCalls } = useToolApiCalls<TParams>();
|
||||
const { generateThumbnails, createDownloadInfo, cleanupBlobUrls, extractZipFiles } = useToolResources();
|
||||
|
||||
const { checkCredits } = useCreditCheck(config.operationType);
|
||||
|
||||
// Determine endpoint for cloud usage check
|
||||
const endpointString = config.toolType !== ToolType.custom && config.endpoint
|
||||
? (typeof config.endpoint === 'function'
|
||||
? (config.defaultParameters ? config.endpoint(config.defaultParameters) : undefined)
|
||||
: config.endpoint)
|
||||
: undefined;
|
||||
const willUseCloud = useWillUseCloud(endpointString);
|
||||
|
||||
// Track last operation for undo functionality
|
||||
const lastOperationRef = useRef<{
|
||||
inputFiles: File[];
|
||||
@@ -217,7 +230,24 @@ export const useToolOperation = <TParams>(
|
||||
return;
|
||||
}
|
||||
|
||||
const backendReady = await ensureBackendReady();
|
||||
// Get endpoint (static or dynamic) for backend readiness check
|
||||
const endpoint = config.customProcessor
|
||||
? undefined // Custom processors may not have endpoints
|
||||
: typeof config.endpoint === 'function'
|
||||
? config.endpoint(params)
|
||||
: config.endpoint;
|
||||
|
||||
// Credit check for cloud operations (desktop SaaS mode only, no-op in web builds)
|
||||
if (willUseCloud && endpoint) {
|
||||
const creditError = await checkCredits();
|
||||
if (creditError !== null) {
|
||||
actions.setError(creditError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Backend readiness check (will skip for SaaS-routed endpoints)
|
||||
const backendReady = await ensureBackendReady(endpoint);
|
||||
if (!backendReady) {
|
||||
actions.setError(t('backendHealth.offline', 'Embedded backend is offline. Please try again shortly.'));
|
||||
return;
|
||||
@@ -507,7 +537,7 @@ export const useToolOperation = <TParams>(
|
||||
actions.setLoading(false);
|
||||
actions.setProgress(null);
|
||||
}
|
||||
}, [t, config, actions, addFiles, consumeFiles, processFiles, generateThumbnails, createDownloadInfo, cleanupBlobUrls, extractZipFiles]);
|
||||
}, [t, config, actions, addFiles, consumeFiles, processFiles, generateThumbnails, createDownloadInfo, cleanupBlobUrls, extractZipFiles, willUseCloud, checkCredits]);
|
||||
|
||||
const cancelOperation = useCallback(() => {
|
||||
cancelApiCalls();
|
||||
@@ -591,6 +621,7 @@ export const useToolOperation = <TParams>(
|
||||
status: state.status,
|
||||
errorMessage: state.errorMessage,
|
||||
progress: state.progress,
|
||||
willUseCloud,
|
||||
|
||||
// Actions
|
||||
executeOperation,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Comprehensive conversion status data
|
||||
*/
|
||||
export interface ConversionStatus {
|
||||
availability: Record<string, boolean>; // Available on local OR SaaS?
|
||||
cloudStatus: Record<string, boolean>; // Will use cloud?
|
||||
localOnly: Record<string, boolean>; // Available ONLY locally (not on SaaS)?
|
||||
}
|
||||
|
||||
/**
|
||||
* Core stub for conversion cloud status checking
|
||||
* Desktop layer provides the real implementation
|
||||
* In web builds, always returns empty objects (no cloud routing)
|
||||
*/
|
||||
export function useConversionCloudStatus(): ConversionStatus {
|
||||
return {
|
||||
availability: {},
|
||||
cloudStatus: {},
|
||||
localOnly: {},
|
||||
}; // Core stub - web builds don't use cloud
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Core stub for credit checking before cloud operations
|
||||
* Desktop layer shadows this with the real implementation
|
||||
* In web builds, always allows the operation (no credit system)
|
||||
*/
|
||||
export function useCreditCheck(_operationType?: string) {
|
||||
return {
|
||||
checkCredits: async (): Promise<string | null> => null, // null = allowed
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Core stub for tool cloud status checking
|
||||
* Desktop layer provides the real implementation
|
||||
* In web builds, always returns false (no cloud routing)
|
||||
*/
|
||||
export function useToolCloudStatus(_endpointName?: string): boolean {
|
||||
return false; // Core stub - web builds don't use cloud
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Core stub for cloud usage detection
|
||||
* Desktop layer provides the real implementation
|
||||
* In web builds, always returns false since there's no cloud routing
|
||||
*/
|
||||
export function useWillUseCloud(_endpoint?: string): boolean {
|
||||
return false; // Core stub - web builds don't use cloud
|
||||
}
|
||||
Reference in New Issue
Block a user