diff --git a/.github/workflows/PR-Auto-Deploy-V2.yml b/.github/workflows/PR-Auto-Deploy-V2.yml
index 7094ef72d..3ece9fc4f 100644
--- a/.github/workflows/PR-Auto-Deploy-V2.yml
+++ b/.github/workflows/PR-Auto-Deploy-V2.yml
@@ -48,6 +48,7 @@ jobs:
"DarioGii"
"ConnorYoh"
"EthanHealy01"
+ "jbrunton96"
)
# Check if author is in the authorized list
diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml
index 877a78524..d08c4ad04 100644
--- a/.github/workflows/PR-Demo-Comment-with-react.yml
+++ b/.github/workflows/PR-Demo-Comment-with-react.yml
@@ -29,6 +29,7 @@ jobs:
github.event.comment.user.login == 'reecebrowne' ||
github.event.comment.user.login == 'DarioGii' ||
github.event.comment.user.login == 'EthanHealy01' ||
+ github.event.comment.user.login == 'jbrunton96' ||
github.event.comment.user.login == 'ConnorYoh'
)
outputs:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b0e51a8bf..b2a9abe17 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -53,7 +53,7 @@ jobs:
with:
gradle-version: 8.14
- name: Build with Gradle and spring security ${{ matrix.spring-security }}
- run: ./gradlew clean build
+ run: ./gradlew clean build -PnoSpotless
env:
DISABLE_ADDITIONAL_FEATURES: ${{ matrix.spring-security }}
- name: Check Test Reports Exist
diff --git a/build.gradle b/build.gradle
index 0c62a0e07..4ad54559e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -203,9 +203,17 @@ subprojects {
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
- dependsOn "spotlessApply"
+ if (!project.hasProperty("noSpotless")) {
+ dependsOn "spotlessApply"
+ }
+}
+gradle.taskGraph.whenReady { graph ->
+ if (project.hasProperty("noSpotless")) {
+ tasks.matching { it.name.startsWith("spotless") }.configureEach {
+ enabled = false
+ }
+ }
}
-
licenseReport {
projects = [project]
renderers = [new JsonReportRenderer()]
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index de5001850..852204b25 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { RainbowThemeProvider } from './components/shared/RainbowThemeProvider';
import { FileContextProvider } from './contexts/FileContext';
+import { FilesModalProvider } from './contexts/FilesModalContext';
import HomePage from './pages/HomePage';
// Import global styles
@@ -11,7 +12,9 @@ export default function App() {
return (
-
+
+
+
);
diff --git a/frontend/src/components/fileEditor/FileEditor.tsx b/frontend/src/components/fileEditor/FileEditor.tsx
index b4222d9ae..ca5f594b8 100644
--- a/frontend/src/components/fileEditor/FileEditor.tsx
+++ b/frontend/src/components/fileEditor/FileEditor.tsx
@@ -665,46 +665,35 @@ const FileEditor = ({
return (
-
-
+
+
+
-
-
- {showBulkActions && !toolMode && (
- <>
-
-
-
- >
- )}
-
- {/* Load from storage and upload buttons */}
- {showUpload && (
- <>
-
-
-
-
- >
- )}
-
+ >
+ )}
+
{files.length === 0 && !localLoading && !zipExtractionProgress.isExtracting ? (
@@ -866,7 +855,8 @@ const FileEditor = ({
{error}
)}
-
+
+
);
};
diff --git a/frontend/src/components/shared/FileUploadModal.tsx b/frontend/src/components/shared/FileUploadModal.tsx
new file mode 100644
index 000000000..a83e96e62
--- /dev/null
+++ b/frontend/src/components/shared/FileUploadModal.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import { Modal } from '@mantine/core';
+import FileUploadSelector from './FileUploadSelector';
+import { useFilesModalContext } from '../../contexts/FilesModalContext';
+import { Tool } from '../../types/tool';
+
+interface FileUploadModalProps {
+ selectedTool?: Tool | null;
+}
+
+const FileUploadModal: React.FC = ({ selectedTool }) => {
+ const { isFilesModalOpen, closeFilesModal, onFileSelect, onFilesSelect } = useFilesModalContext();
+
+
+ return (
+
+
+
+ );
+};
+
+export default FileUploadModal;
\ No newline at end of file
diff --git a/frontend/src/components/shared/LandingPage.tsx b/frontend/src/components/shared/LandingPage.tsx
new file mode 100644
index 000000000..977f1f280
--- /dev/null
+++ b/frontend/src/components/shared/LandingPage.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Container, Stack, Text, Button } from '@mantine/core';
+import FolderIcon from '@mui/icons-material/FolderRounded';
+import { useFilesModalContext } from '../../contexts/FilesModalContext';
+
+interface LandingPageProps {
+ title: string;
+}
+
+const LandingPage = ({ title }: LandingPageProps) => {
+ const { openFilesModal } = useFilesModalContext();
+ return (
+
+
+
+ {title}
+
+ }
+ size="lg"
+ onClick={openFilesModal}
+ >
+ Open Files
+
+
+
+ );
+};
+
+export default LandingPage;
\ No newline at end of file
diff --git a/frontend/src/components/shared/QuickAccessBar.tsx b/frontend/src/components/shared/QuickAccessBar.tsx
index 22a49617e..2f78a0a9f 100644
--- a/frontend/src/components/shared/QuickAccessBar.tsx
+++ b/frontend/src/components/shared/QuickAccessBar.tsx
@@ -11,6 +11,7 @@ import { useRainbowThemeContext } from "./RainbowThemeProvider";
import rainbowStyles from '../../styles/rainbow.module.css';
import AppConfigModal from './AppConfigModal';
import { useIsOverflowing } from '../../hooks/useIsOverflowing';
+import { useFilesModalContext } from '../../contexts/FilesModalContext';
import './QuickAccessBar.css';
interface QuickAccessBarProps {
@@ -30,6 +31,7 @@ interface ButtonConfig {
isRound?: boolean;
size?: 'sm' | 'md' | 'lg' | 'xl';
onClick: () => void;
+ type?: 'navigation' | 'modal' | 'action'; // navigation = main nav, modal = triggers modal, action = other actions
}
function NavHeader({
@@ -111,11 +113,16 @@ const QuickAccessBar = ({
readerMode,
}: QuickAccessBarProps) => {
const { isRainbowMode } = useRainbowThemeContext();
+ const { openFilesModal, isFilesModalOpen } = useFilesModalContext();
const [configModalOpen, setConfigModalOpen] = useState(false);
const [activeButton, setActiveButton] = useState('tools');
const scrollableRef = useRef(null);
const isOverflow = useIsOverflowing(scrollableRef);
+ const handleFilesButtonClick = () => {
+ openFilesModal();
+ };
+
const buttonConfigs: ButtonConfig[] = [
{
id: 'read',
@@ -124,6 +131,7 @@ const QuickAccessBar = ({
tooltip: 'Read documents',
size: 'lg',
isRound: false,
+ type: 'navigation',
onClick: () => {
setActiveButton('read');
onReaderToggle();
@@ -139,6 +147,7 @@ const QuickAccessBar = ({
tooltip: 'Sign your document',
size: 'lg',
isRound: false,
+ type: 'navigation',
onClick: () => setActiveButton('sign')
},
{
@@ -148,6 +157,7 @@ const QuickAccessBar = ({
tooltip: 'Automate workflows',
size: 'lg',
isRound: false,
+ type: 'navigation',
onClick: () => setActiveButton('automate')
},
{
@@ -157,7 +167,8 @@ const QuickAccessBar = ({
tooltip: 'Manage files',
isRound: true,
size: 'lg',
- onClick: () => setActiveButton('files')
+ type: 'modal',
+ onClick: handleFilesButtonClick
},
{
id: 'activity',
@@ -169,6 +180,7 @@ const QuickAccessBar = ({
tooltip: 'View activity and analytics',
isRound: true,
size: 'lg',
+ type: 'navigation',
onClick: () => setActiveButton('activity')
},
{
@@ -177,6 +189,7 @@ const QuickAccessBar = ({
icon: ,
tooltip: 'Configure settings',
size: 'lg',
+ type: 'modal',
onClick: () => {
setConfigModalOpen(true);
}
@@ -190,8 +203,16 @@ const QuickAccessBar = ({
return config.isRound ? CIRCULAR_BORDER_RADIUS : ROUND_BORDER_RADIUS;
};
+ const isButtonActive = (config: ButtonConfig): boolean => {
+ return (
+ (config.type === 'navigation' && activeButton === config.id) ||
+ (config.type === 'modal' && config.id === 'files' && isFilesModalOpen) ||
+ (config.type === 'modal' && config.id === 'config' && configModalOpen)
+ );
+ };
+
const getButtonStyle = (config: ButtonConfig) => {
- const isActive = activeButton === config.id;
+ const isActive = isButtonActive(config);
if (isActive) {
return {
@@ -202,7 +223,7 @@ const QuickAccessBar = ({
};
}
- // Inactive state - use consistent inactive colors
+ // Inactive state for all buttons
return {
backgroundColor: 'var(--icon-inactive-bg)',
color: 'var(--icon-inactive-color)',
@@ -254,13 +275,14 @@ const QuickAccessBar = ({
variant="subtle"
onClick={config.onClick}
style={getButtonStyle(config)}
- className={activeButton === config.id ? 'activeIconScale' : ''}
+ className={isButtonActive(config) ? 'activeIconScale' : ''}
+ data-testid={`${config.id}-button`}
>
{config.icon}
-
+
{config.name}
@@ -281,30 +303,29 @@ const QuickAccessBar = ({
{/* Config button at the bottom */}
-
-
-
{
- setConfigModalOpen(true);
- }}
- style={{
- backgroundColor: 'var(--icon-inactive-bg)',
- color: 'var(--icon-inactive-color)',
- border: 'none',
- borderRadius: '8px',
- }}
- >
-
-
-
-
-
- Config
-
-
-
+ {buttonConfigs
+ .filter(config => config.id === 'config')
+ .map(config => (
+
+
+
+
+ {config.icon}
+
+
+
+ {config.name}
+
+
+
+ ))}
diff --git a/frontend/src/components/tools/convert/ConvertSettings.tsx b/frontend/src/components/tools/convert/ConvertSettings.tsx
index fa6134f54..a3051c88f 100644
--- a/frontend/src/components/tools/convert/ConvertSettings.tsx
+++ b/frontend/src/components/tools/convert/ConvertSettings.tsx
@@ -198,7 +198,7 @@ const ConvertSettings = ({
(null);
+
+export const FilesModalProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ const { addToActiveFiles, addMultipleFiles } = useFileHandler();
+
+ const filesModal = useFilesModal({
+ onFileSelect: addToActiveFiles,
+ onFilesSelect: addMultipleFiles,
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useFilesModalContext = () => {
+ const context = useContext(FilesModalContext);
+ if (!context) {
+ throw new Error('useFilesModalContext must be used within FilesModalProvider');
+ }
+ return context;
+};
\ No newline at end of file
diff --git a/frontend/src/hooks/useFileHandler.ts b/frontend/src/hooks/useFileHandler.ts
new file mode 100644
index 000000000..efd988906
--- /dev/null
+++ b/frontend/src/hooks/useFileHandler.ts
@@ -0,0 +1,27 @@
+import { useCallback } from 'react';
+import { useFileContext } from '../contexts/FileContext';
+
+export const useFileHandler = () => {
+ const { activeFiles, addFiles } = useFileContext();
+
+ const addToActiveFiles = useCallback(async (file: File) => {
+ const exists = activeFiles.some(f => f.name === file.name && f.size === file.size);
+ if (!exists) {
+ await addFiles([file]);
+ }
+ }, [activeFiles, addFiles]);
+
+ const addMultipleFiles = useCallback(async (files: File[]) => {
+ const newFiles = files.filter(file =>
+ !activeFiles.some(f => f.name === file.name && f.size === file.size)
+ );
+ if (newFiles.length > 0) {
+ await addFiles(newFiles);
+ }
+ }, [activeFiles, addFiles]);
+
+ return {
+ addToActiveFiles,
+ addMultipleFiles,
+ };
+};
\ No newline at end of file
diff --git a/frontend/src/hooks/useFilesModal.ts b/frontend/src/hooks/useFilesModal.ts
new file mode 100644
index 000000000..49e9f2c5e
--- /dev/null
+++ b/frontend/src/hooks/useFilesModal.ts
@@ -0,0 +1,57 @@
+import { useState, useCallback } from 'react';
+
+export interface UseFilesModalReturn {
+ isFilesModalOpen: boolean;
+ openFilesModal: () => void;
+ closeFilesModal: () => void;
+ onFileSelect?: (file: File) => void;
+ onFilesSelect?: (files: File[]) => void;
+ onModalClose?: () => void;
+ setOnModalClose: (callback: () => void) => void;
+}
+
+interface UseFilesModalProps {
+ onFileSelect?: (file: File) => void;
+ onFilesSelect?: (files: File[]) => void;
+}
+
+export const useFilesModal = ({
+ onFileSelect,
+ onFilesSelect
+}: UseFilesModalProps = {}): UseFilesModalReturn => {
+ const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
+ const [onModalClose, setOnModalClose] = useState<(() => void) | undefined>();
+
+ const openFilesModal = useCallback(() => {
+ setIsFilesModalOpen(true);
+ }, []);
+
+ const closeFilesModal = useCallback(() => {
+ setIsFilesModalOpen(false);
+ onModalClose?.();
+ }, [onModalClose]);
+
+ const handleFileSelect = useCallback((file: File) => {
+ onFileSelect?.(file);
+ closeFilesModal();
+ }, [onFileSelect, closeFilesModal]);
+
+ const handleFilesSelect = useCallback((files: File[]) => {
+ onFilesSelect?.(files);
+ closeFilesModal();
+ }, [onFilesSelect, closeFilesModal]);
+
+ const setModalCloseCallback = useCallback((callback: () => void) => {
+ setOnModalClose(() => callback);
+ }, []);
+
+ return {
+ isFilesModalOpen,
+ openFilesModal,
+ closeFilesModal,
+ onFileSelect: handleFileSelect,
+ onFilesSelect: handleFilesSelect,
+ onModalClose,
+ setOnModalClose: setModalCloseCallback,
+ };
+};
\ No newline at end of file
diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx
index cde8d3320..cccce7667 100644
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -1,9 +1,10 @@
-import React, { useState, useCallback, useEffect} from "react";
+import React, { useState, useCallback, useEffect, useRef } from "react";
import { useTranslation } from 'react-i18next';
import { useFileContext } from "../contexts/FileContext";
import { FileSelectionProvider, useFileSelection } from "../contexts/FileSelectionContext";
import { useToolManagement } from "../hooks/useToolManagement";
-import { Group, Box, Button, Container } from "@mantine/core";
+import { useFileHandler } from "../hooks/useFileHandler";
+import { Group, Box, Button } from "@mantine/core";
import { useRainbowThemeContext } from "../components/shared/RainbowThemeProvider";
import { PageEditorFunctions } from "../types/pageEditor";
import rainbowStyles from '../styles/rainbow.module.css';
@@ -14,17 +15,19 @@ import FileEditor from "../components/fileEditor/FileEditor";
import PageEditor from "../components/pageEditor/PageEditor";
import PageEditorControls from "../components/pageEditor/PageEditorControls";
import Viewer from "../components/viewer/Viewer";
-import FileUploadSelector from "../components/shared/FileUploadSelector";
import ToolRenderer from "../components/tools/ToolRenderer";
import QuickAccessBar from "../components/shared/QuickAccessBar";
+import LandingPage from "../components/shared/LandingPage";
+import FileUploadModal from "../components/shared/FileUploadModal";
function HomePageContent() {
const { t } = useTranslation();
const { isRainbowMode } = useRainbowThemeContext();
const fileContext = useFileContext();
- const { activeFiles, currentView, currentMode, setCurrentView, addFiles } = fileContext;
+ const { activeFiles, currentView, setCurrentView } = fileContext;
const { setMaxFiles, setIsToolMode, setSelectedFiles } = useFileSelection();
+ const { addToActiveFiles } = useFileHandler();
const {
selectedToolKey,
@@ -33,6 +36,7 @@ function HomePageContent() {
selectTool,
clearToolSelection,
} = useToolManagement();
+
const [sidebarsVisible, setSidebarsVisible] = useState(true);
const [leftPanelView, setLeftPanelView] = useState<'toolPicker' | 'toolContent'>('toolPicker');
const [readerMode, setReaderMode] = useState(false);
@@ -77,12 +81,6 @@ function HomePageContent() {
setCurrentView(view as any);
}, [setCurrentView]);
- const addToActiveFiles = useCallback(async (file: File) => {
- const exists = activeFiles.some(f => f.name === file.name && f.size === file.size);
- if (!exists) {
- await addFiles([file]);
- }
- }, [activeFiles, addFiles]);
@@ -183,26 +181,12 @@ function HomePageContent() {
}}
>
{!activeFiles[0] ? (
-
- {
- addToActiveFiles(file);
- }}
- onFilesSelect={(files) => {
- files.forEach(addToActiveFiles);
- }}
- accept={["*/*"]}
- supportedExtensions={selectedTool?.supportedFormats || ["pdf"]}
- loading={false}
- showRecentFiles={true}
- maxRecentFiles={8}
- />
-
+
) : currentView === "fileEditor" ? (
) : (
-
- {
- addToActiveFiles(file);
- }}
- onFilesSelect={(files) => {
- files.forEach(addToActiveFiles);
- }}
- accept={["*/*"]}
- supportedExtensions={selectedTool?.supportedFormats || ["pdf"]}
- loading={false}
- showRecentFiles={true}
- maxRecentFiles={8}
- />
-
+
)}
+
+ {/* Global Modals */}
+
);
}
diff --git a/frontend/src/tests/convert/ConvertE2E.spec.ts b/frontend/src/tests/convert/ConvertE2E.spec.ts
index e60f7826c..90d203b55 100644
--- a/frontend/src/tests/convert/ConvertE2E.spec.ts
+++ b/frontend/src/tests/convert/ConvertE2E.spec.ts
@@ -127,6 +127,27 @@ const getExpectedExtension = (toFormat: string): string => {
return extensionMap[toFormat] || '.pdf';
};
+/**
+ * Helper function to upload files through the modal system
+ */
+async function uploadFileViaModal(page: Page, filePath: string) {
+ // Click the Files button in the QuickAccessBar to open the modal
+ await page.click('[data-testid="files-button"]');
+
+ // Wait for the modal to open
+ await page.waitForSelector('.mantine-Modal-overlay', { state: 'visible' }, { timeout: 5000 });
+ //await page.waitForSelector('[data-testid="file-upload-modal"]', { timeout: 5000 });
+
+ // Upload the file through the modal's file input
+ await page.setInputFiles('input[type="file"]', filePath);
+
+ // Wait for the file to be processed and the modal to close
+ await page.waitForSelector('[data-testid="file-upload-modal"]', { state: 'hidden' });
+
+ // Wait for the file thumbnail to appear in the main interface
+ await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+}
+
/**
* Generic test function for any conversion
*/
@@ -288,8 +309,8 @@ test.describe('Convert Tool E2E Tests', () => {
// Wait for the page to load
await page.waitForLoadState('networkidle');
- // Wait for the file upload area to appear (shown when no active files)
- await page.waitForSelector('[data-testid="file-dropzone"]', { timeout: 10000 });
+ // Wait for the QuickAccessBar to appear
+ await page.waitForSelector('[data-testid="files-button"]', { timeout: 10000 });
});
test.describe('Dynamic Conversion Tests', () => {
@@ -302,8 +323,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -314,8 +334,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -326,8 +345,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -338,8 +356,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -350,8 +367,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -362,8 +378,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -374,8 +389,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -386,8 +400,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -398,8 +411,7 @@ test.describe('Convert Tool E2E Tests', () => {
test.skip(!isAvailable, `Endpoint ${conversion.endpoint} is not available`);
const testFile = getTestFileForFormat(conversion.fromFormat);
- await page.setInputFiles('input[type="file"]', testFile);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, testFile);
await testConversion(page, conversion);
});
@@ -410,8 +422,7 @@ test.describe('Convert Tool E2E Tests', () => {
// Test that disabled conversions don't appear in dropdowns when they shouldn't
test('should not show conversion button when no valid conversions available', async ({ page }) => {
// This test ensures the convert button is disabled when no valid conversion is possible
- await page.setInputFiles('input[type="file"]', TEST_FILES.pdf);
- await page.waitForSelector('[data-testid="file-thumbnail"]', { timeout: 10000 });
+ await uploadFileViaModal(page, TEST_FILES.pdf);
// Click the Convert tool button
await page.click('[data-testid="tool-convert"]');