mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-04-22 23:08:53 +02:00
Change to use dpdm for circular import scanning (#5788)
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import eslint from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
|
||||
const srcGlobs = [
|
||||
'src/**/*.{js,mjs,jsx,ts,tsx}',
|
||||
@@ -78,21 +77,4 @@ export default defineConfig(
|
||||
}
|
||||
}
|
||||
},
|
||||
// Config for import plugin
|
||||
{
|
||||
...importPlugin.flatConfigs.recommended,
|
||||
...importPlugin.flatConfigs.typescript,
|
||||
rules: {
|
||||
// ...importPlugin.flatConfigs.recommended.rules, // Temporarily disabled until codebase conformant
|
||||
...importPlugin.flatConfigs.typescript.rules,
|
||||
'import/no-cycle': 'error',
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
2166
frontend/package-lock.json
generated
2166
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,9 @@
|
||||
"predev": "npm run generate-icons",
|
||||
"dev": "vite",
|
||||
"prebuild": "npm run generate-icons",
|
||||
"lint": "eslint --max-warnings=0",
|
||||
"lint": "npm run lint:eslint && npm run lint:cycles",
|
||||
"lint:eslint": "eslint --max-warnings=0",
|
||||
"lint:cycles": "dpdm src --circular --no-warning --no-tree --exit-code circular:1",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri-dev": "tauri dev --no-watch",
|
||||
@@ -149,9 +151,8 @@
|
||||
"@typescript-eslint/parser": "^8.44.1",
|
||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"dpdm": "^3.14.0",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"jsdom": "^27.0.0",
|
||||
"license-checker": "^25.0.1",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
|
||||
import apiClient from '@app/services/apiClient';
|
||||
import { getSimulatedAppConfig } from '@app/testing/serverExperienceSimulations';
|
||||
import type { AppConfig, AppConfigBootstrapMode } from '@app/types/appConfig';
|
||||
|
||||
/**
|
||||
* Sleep utility for delays
|
||||
@@ -14,55 +15,7 @@ export interface AppConfigRetryOptions {
|
||||
initialDelay?: number;
|
||||
}
|
||||
|
||||
export interface AppConfig {
|
||||
baseUrl?: string;
|
||||
contextPath?: string;
|
||||
serverPort?: number;
|
||||
frontendUrl?: string;
|
||||
appNameNavbar?: string;
|
||||
languages?: string[];
|
||||
defaultLocale?: string;
|
||||
logoStyle?: 'modern' | 'classic';
|
||||
enableLogin?: boolean;
|
||||
showSettingsWhenNoLogin?: boolean;
|
||||
enableEmailInvites?: boolean;
|
||||
enableOAuth?: boolean;
|
||||
enableSaml?: boolean;
|
||||
isAdmin?: boolean;
|
||||
enableAlphaFunctionality?: boolean;
|
||||
enableAnalytics?: boolean | null;
|
||||
enablePosthog?: boolean | null;
|
||||
enableScarf?: boolean | null;
|
||||
enableDesktopInstallSlide?: boolean;
|
||||
premiumEnabled?: boolean;
|
||||
premiumKey?: string;
|
||||
termsAndConditions?: string;
|
||||
privacyPolicy?: string;
|
||||
cookiePolicy?: string;
|
||||
impressum?: string;
|
||||
accessibilityStatement?: string;
|
||||
runningProOrHigher?: boolean;
|
||||
runningEE?: boolean;
|
||||
license?: string;
|
||||
SSOAutoLogin?: boolean;
|
||||
serverCertificateEnabled?: boolean;
|
||||
enableMobileScanner?: boolean;
|
||||
mobileScannerConvertToPdf?: boolean;
|
||||
mobileScannerImageResolution?: string;
|
||||
mobileScannerPageFormat?: string;
|
||||
mobileScannerStretchToFit?: boolean;
|
||||
appVersion?: string;
|
||||
machineType?: string;
|
||||
activeSecurity?: boolean;
|
||||
dependenciesReady?: boolean;
|
||||
error?: string;
|
||||
isNewServer?: boolean;
|
||||
isNewUser?: boolean;
|
||||
defaultHideUnavailableTools?: boolean;
|
||||
defaultHideUnavailableConversions?: boolean;
|
||||
}
|
||||
|
||||
export type AppConfigBootstrapMode = 'blocking' | 'non-blocking';
|
||||
export type { AppConfig, AppConfigBootstrapMode };
|
||||
|
||||
interface AppConfigContextValue {
|
||||
config: AppConfig | null;
|
||||
|
||||
@@ -6,10 +6,7 @@ import { downloadFiles } from '@app/utils/downloadUtils';
|
||||
import { FileId } from '@app/types/file';
|
||||
import { groupFilesByOriginal } from '@app/utils/fileHistoryUtils';
|
||||
import { openFilesFromDisk } from '@app/services/openFilesFromDisk';
|
||||
|
||||
// Module-level storage for file path mappings (quickKey -> localFilePath)
|
||||
// Used to pass file paths from Tauri file dialog to FileContext
|
||||
export const pendingFilePathMappings = new Map<string, string>();
|
||||
export { pendingFilePathMappings } from '@app/services/pendingFilePathMappings';
|
||||
|
||||
// Type for the context value - now contains everything directly
|
||||
interface FileManagerContextValue {
|
||||
|
||||
@@ -1,38 +1,17 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { signatureStorageService, type StorageType } from '@app/services/signatureStorageService';
|
||||
import { useAppConfig } from '@app/contexts/AppConfigContext';
|
||||
import type {
|
||||
SavedSignature,
|
||||
SavedSignaturePayload,
|
||||
SavedSignatureType,
|
||||
SignatureScope,
|
||||
} from '@app/types/signature';
|
||||
|
||||
export const MAX_SAVED_SIGNATURES_BACKEND = 20; // Backend limit per user
|
||||
export const MAX_SAVED_SIGNATURES_LOCALSTORAGE = 10; // LocalStorage limit
|
||||
|
||||
export type SavedSignatureType = 'canvas' | 'image' | 'text';
|
||||
export type SignatureScope = 'personal' | 'shared' | 'localStorage';
|
||||
|
||||
export type SavedSignaturePayload =
|
||||
| {
|
||||
type: 'canvas';
|
||||
dataUrl: string;
|
||||
}
|
||||
| {
|
||||
type: 'image';
|
||||
dataUrl: string;
|
||||
}
|
||||
| {
|
||||
type: 'text';
|
||||
dataUrl: string;
|
||||
signerName: string;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
textColor: string;
|
||||
};
|
||||
|
||||
export type SavedSignature = SavedSignaturePayload & {
|
||||
id: string;
|
||||
label: string;
|
||||
scope: SignatureScope;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
export type { SavedSignature, SavedSignaturePayload, SavedSignatureType, SignatureScope };
|
||||
|
||||
export type AddSignatureResult =
|
||||
| { success: true; signature: SavedSignature }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { openFileDialog } from '@app/services/fileDialogService';
|
||||
import { pendingFilePathMappings } from '@app/contexts/FileManagerContext';
|
||||
import { pendingFilePathMappings } from '@app/services/pendingFilePathMappings';
|
||||
import { getDocumentFileDialogFilter } from '@app/utils/fileDialogUtils';
|
||||
|
||||
interface OpenFilesFromDiskOptions {
|
||||
|
||||
3
frontend/src/core/services/pendingFilePathMappings.ts
Normal file
3
frontend/src/core/services/pendingFilePathMappings.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// Module-level storage for file path mappings (quickKey -> localFilePath)
|
||||
// Used to pass file paths from Tauri file dialog to FileManagerContext
|
||||
export const pendingFilePathMappings = new Map<string, string>();
|
||||
@@ -1,5 +1,5 @@
|
||||
import apiClient from '@app/services/apiClient';
|
||||
import type { SavedSignature } from '@app/hooks/tools/sign/useSavedSignatures';
|
||||
import type { SavedSignature } from '@app/types/signature';
|
||||
|
||||
export type StorageType = 'backend' | 'localStorage';
|
||||
|
||||
|
||||
49
frontend/src/core/types/appConfig.ts
Normal file
49
frontend/src/core/types/appConfig.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
export interface AppConfig {
|
||||
baseUrl?: string;
|
||||
contextPath?: string;
|
||||
serverPort?: number;
|
||||
frontendUrl?: string;
|
||||
appNameNavbar?: string;
|
||||
languages?: string[];
|
||||
defaultLocale?: string;
|
||||
logoStyle?: 'modern' | 'classic';
|
||||
enableLogin?: boolean;
|
||||
showSettingsWhenNoLogin?: boolean;
|
||||
enableEmailInvites?: boolean;
|
||||
enableOAuth?: boolean;
|
||||
enableSaml?: boolean;
|
||||
isAdmin?: boolean;
|
||||
enableAlphaFunctionality?: boolean;
|
||||
enableAnalytics?: boolean | null;
|
||||
enablePosthog?: boolean | null;
|
||||
enableScarf?: boolean | null;
|
||||
enableDesktopInstallSlide?: boolean;
|
||||
premiumEnabled?: boolean;
|
||||
premiumKey?: string;
|
||||
termsAndConditions?: string;
|
||||
privacyPolicy?: string;
|
||||
cookiePolicy?: string;
|
||||
impressum?: string;
|
||||
accessibilityStatement?: string;
|
||||
runningProOrHigher?: boolean;
|
||||
runningEE?: boolean;
|
||||
license?: string;
|
||||
SSOAutoLogin?: boolean;
|
||||
serverCertificateEnabled?: boolean;
|
||||
enableMobileScanner?: boolean;
|
||||
mobileScannerConvertToPdf?: boolean;
|
||||
mobileScannerImageResolution?: string;
|
||||
mobileScannerPageFormat?: string;
|
||||
mobileScannerStretchToFit?: boolean;
|
||||
appVersion?: string;
|
||||
machineType?: string;
|
||||
activeSecurity?: boolean;
|
||||
dependenciesReady?: boolean;
|
||||
error?: string;
|
||||
isNewServer?: boolean;
|
||||
isNewUser?: boolean;
|
||||
defaultHideUnavailableTools?: boolean;
|
||||
defaultHideUnavailableConversions?: boolean;
|
||||
}
|
||||
|
||||
export type AppConfigBootstrapMode = 'blocking' | 'non-blocking';
|
||||
28
frontend/src/core/types/signature.ts
Normal file
28
frontend/src/core/types/signature.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export type SavedSignatureType = 'canvas' | 'image' | 'text';
|
||||
export type SignatureScope = 'personal' | 'shared' | 'localStorage';
|
||||
|
||||
export type SavedSignaturePayload =
|
||||
| {
|
||||
type: 'canvas';
|
||||
dataUrl: string;
|
||||
}
|
||||
| {
|
||||
type: 'image';
|
||||
dataUrl: string;
|
||||
}
|
||||
| {
|
||||
type: 'text';
|
||||
dataUrl: string;
|
||||
signerName: string;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
textColor: string;
|
||||
};
|
||||
|
||||
export type SavedSignature = SavedSignaturePayload & {
|
||||
id: string;
|
||||
label: string;
|
||||
scope: SignatureScope;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
27
frontend/src/desktop/services/authTokenStore.ts
Normal file
27
frontend/src/desktop/services/authTokenStore.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
const TOKEN_KEY = 'stirling_jwt';
|
||||
|
||||
/**
|
||||
* Read auth token from any available source (Tauri store or localStorage).
|
||||
* Kept separate to avoid circular dependencies between auth and backend services.
|
||||
*/
|
||||
export async function getAuthTokenFromAnySource(): Promise<string | null> {
|
||||
// Try Tauri store first
|
||||
try {
|
||||
const token = await invoke<string | null>('get_auth_token');
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Desktop AuthTokenStore] Failed to read from Tauri store:', error);
|
||||
}
|
||||
|
||||
// Fallback to localStorage
|
||||
try {
|
||||
return localStorage.getItem(TOKEN_KEY);
|
||||
} catch (error) {
|
||||
console.error('[Desktop AuthTokenStore] Failed to read from localStorage:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { fetch } from '@tauri-apps/plugin-http';
|
||||
import { connectionModeService } from '@app/services/connectionModeService';
|
||||
import { getAuthTokenFromAnySource } from '@app/services/authTokenStore';
|
||||
|
||||
export type BackendStatus = 'stopped' | 'starting' | 'healthy' | 'unhealthy';
|
||||
|
||||
@@ -122,8 +123,7 @@ export class TauriBackendService {
|
||||
*/
|
||||
private async getAuthToken(): Promise<string | null> {
|
||||
try {
|
||||
const { authService } = await import('./authService');
|
||||
return await authService.getAuthToken();
|
||||
return await getAuthTokenFromAnySource();
|
||||
} catch (error) {
|
||||
console.debug('[TauriBackendService] Failed to get auth token:', error);
|
||||
return null;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PlanFeature } from '@app/services/licenseService';
|
||||
import type { PlanFeature } from '@app/types/license';
|
||||
|
||||
/**
|
||||
* Shared plan feature definitions for Stirling PDF Self-Hosted
|
||||
|
||||
@@ -2,11 +2,7 @@ import apiClient from '@app/services/apiClient';
|
||||
import { supabase, isSupabaseConfigured } from '@app/services/supabaseClient';
|
||||
import { getCheckoutMode } from '@app/utils/protocolDetection';
|
||||
import { PLAN_FEATURES, PLAN_HIGHLIGHTS } from '@app/constants/planConstants';
|
||||
|
||||
export interface PlanFeature {
|
||||
name: string;
|
||||
included: boolean;
|
||||
}
|
||||
import type { LicenseInfo, PlanFeature } from '@app/types/license';
|
||||
|
||||
export interface PlanTier {
|
||||
id: string;
|
||||
@@ -69,13 +65,7 @@ export interface LicenseKeyResponse {
|
||||
plan?: string;
|
||||
}
|
||||
|
||||
export interface LicenseInfo {
|
||||
licenseType: 'NORMAL' | 'SERVER' | 'ENTERPRISE';
|
||||
enabled: boolean;
|
||||
maxUsers: number;
|
||||
hasKey: boolean;
|
||||
licenseKey?: string; // The actual license key (for upgrades)
|
||||
}
|
||||
export type { LicenseInfo, PlanFeature };
|
||||
|
||||
export interface LicenseSaveResponse {
|
||||
success: boolean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { AppConfig } from '@app/contexts/AppConfigContext';
|
||||
import type { LicenseInfo } from '@app/services/licenseService';
|
||||
import type { AppConfig } from '@app/types/appConfig';
|
||||
import type { LicenseInfo } from '@app/types/license';
|
||||
|
||||
interface WauResponse {
|
||||
trackingSince: string;
|
||||
@@ -208,4 +208,3 @@ export function getSimulatedLicenseInfo(): LicenseInfo | null {
|
||||
}
|
||||
|
||||
export const DEV_TESTING_ENABLED = DEV_TESTING_MODE;
|
||||
|
||||
|
||||
12
frontend/src/proprietary/types/license.ts
Normal file
12
frontend/src/proprietary/types/license.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface PlanFeature {
|
||||
name: string;
|
||||
included: boolean;
|
||||
}
|
||||
|
||||
export interface LicenseInfo {
|
||||
licenseType: 'NORMAL' | 'SERVER' | 'ENTERPRISE';
|
||||
enabled: boolean;
|
||||
maxUsers: number;
|
||||
hasKey: boolean;
|
||||
licenseKey?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user