Added optional title for tool workflow (#4256)

- Added optional title for tool workflow - Not added to any tool. Just
there for when we need it
- Added add files button to files step
- renamed Local files button in filemanager to Upload Files
-

---------

Co-authored-by: Connor Yoh <connor@stirlingpdf.com>
Co-authored-by: James Brunton <jbrunton96@gmail.com>
This commit is contained in:
ConnorYoh 2025-08-22 17:12:14 +01:00 committed by GitHub
parent 23d86deae7
commit 888bac9408
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 129 additions and 22 deletions

View File

@ -1970,6 +1970,7 @@
"dropFilesHere": "Drop files here or click to upload",
"pdfFilesOnly": "PDF files only",
"supportedFileTypes": "Supported file types",
"upload": "Upload",
"uploadFile": "Upload File",
"uploadFiles": "Upload Files",
"noFilesInStorage": "No files available in storage. Upload some files first.",

View File

@ -17,7 +17,7 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
return (
<Card withBorder p={0} h={`calc(${modalHeight} * 0.32 - 1rem)`} style={{ flex: 1, overflow: 'hidden' }}>
<Box bg="blue.6" p="sm" style={{ borderTopLeftRadius: 'var(--mantine-radius-md)', borderTopRightRadius: 'var(--mantine-radius-md)' }}>
<Box bg="gray.4" p="sm" style={{ borderTopLeftRadius: 'var(--mantine-radius-md)', borderTopRightRadius: 'var(--mantine-radius-md)' }}>
<Text size="sm" fw={500} ta="center" c="white">
{t('fileManager.details', 'File Details')}
</Text>

View File

@ -1,7 +1,7 @@
import React from 'react';
import { Stack, Text, Button, Group } from '@mantine/core';
import HistoryIcon from '@mui/icons-material/History';
import FolderIcon from '@mui/icons-material/Folder';
import UploadIcon from '@mui/icons-material/Upload';
import CloudIcon from '@mui/icons-material/Cloud';
import { useTranslation } from 'react-i18next';
import { useFileManagerContext } from '../../contexts/FileManagerContext';
@ -48,7 +48,7 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
<Button
variant="subtle"
color='var(--mantine-color-gray-6)'
leftSection={<FolderIcon />}
leftSection={<UploadIcon />}
justify={horizontal ? "center" : "flex-start"}
onClick={onLocalFileClick}
fullWidth={!horizontal}
@ -63,7 +63,7 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
}
}}
>
{horizontal ? t('fileManager.localFiles', 'Local') : t('fileManager.localFiles', 'Local Files')}
{horizontal ? t('fileUpload.uploadFiles', 'Upload') : t('fileUpload.uploadFiles', 'Upload Files')}
</Button>
<Button

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Box } from '@mantine/core';
import { Box, Center } from '@mantine/core';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import { FileMetadata } from '../../types/file';
import DocumentThumbnail from './filePreview/DocumentThumbnail';
import DocumentStack from './filePreview/DocumentStack';
@ -38,7 +39,21 @@ const FilePreview: React.FC<FilePreviewProps> = ({
onPrevious,
onNext
}) => {
if (!file) return null;
if (!file) {
return (
<Box style={{ width: '100%', height: '100%' }}>
<Center style={{ width: '100%', height: '100%' }}>
<InsertDriveFileIcon
style={{
fontSize: '4rem',
color: 'var(--mantine-color-gray-4)',
opacity: 0.6
}}
/>
</Center>
</Box>
);
}
const hasMultipleFiles = totalFiles > 1;

View File

@ -1,6 +1,9 @@
import React from "react";
import { Text } from "@mantine/core";
import { Text, Anchor } from "@mantine/core";
import { useTranslation } from "react-i18next";
import FolderIcon from '@mui/icons-material/Folder';
import { useFilesModalContext } from "../../../contexts/FilesModalContext";
import { useAllFiles } from "../../../contexts/FileContext";
export interface FileStatusIndicatorProps {
selectedFiles?: File[];
@ -12,13 +15,39 @@ const FileStatusIndicator = ({
placeholder,
}: FileStatusIndicatorProps) => {
const { t } = useTranslation();
const defaultPlaceholder = placeholder || t("files.placeholder", "Select a PDF file in the main view to get started");
const { openFilesModal } = useFilesModalContext();
const { files: workbenchFiles } = useAllFiles();
// Only show content when no files are selected
// Check if there are no files in the workbench
if (workbenchFiles.length === 0) {
return (
<Text size="sm" c="dimmed">
{t("files.noFiles", "No files uploaded. ")}{" "}
<Anchor
size="sm"
onClick={openFilesModal}
style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
>
<FolderIcon style={{ fontSize: '14px' }} />
{t("files.addFiles", "Add files")}
</Anchor>
</Text>
);
}
// Show selection status when there are files in workbench
if (selectedFiles.length === 0) {
return (
<Text size="sm" c="dimmed">
{defaultPlaceholder}
{t("files.selectFromWorkbench", "Select files from the workbench or ") + " "}
<Anchor
size="sm"
onClick={openFilesModal}
style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
>
<FolderIcon style={{ fontSize: '14px' }} />
{t("files.addFiles", "Add files")}
</Anchor>
</Text>
);
}

View File

@ -25,6 +25,7 @@ export interface ToolStepProps {
_stepNumber?: number; // Internal prop set by ToolStepContainer
_excludeFromCount?: boolean; // Internal prop to exclude from visible count calculation
_noPadding?: boolean; // Internal prop to exclude from default left padding
alwaysShowTooltip?: boolean; // Force tooltip to show even when collapsed
tooltip?: {
content?: React.ReactNode;
tips?: TooltipTip[];
@ -38,9 +39,10 @@ export interface ToolStepProps {
const renderTooltipTitle = (
title: string,
tooltip: ToolStepProps['tooltip'],
isCollapsed: boolean
isCollapsed: boolean,
alwaysShowTooltip: boolean = false
) => {
if (tooltip && !isCollapsed) {
if (tooltip && (!isCollapsed || alwaysShowTooltip)) {
return (
<Tooltip
content={tooltip.content}
@ -77,6 +79,7 @@ const ToolStep = ({
showNumber,
_stepNumber,
_noPadding,
alwaysShowTooltip = false,
tooltip
}: ToolStepProps) => {
if (!isVisible) return null;
@ -118,7 +121,7 @@ const ToolStep = ({
{stepNumber}
</Text>
)}
{renderTooltipTitle(title, tooltip, isCollapsed)}
{renderTooltipTitle(title, tooltip, isCollapsed, alwaysShowTooltip)}
</Flex>
{isCollapsed ? (

View File

@ -0,0 +1,53 @@
import React from 'react';
import { Flex, Text, Divider } from '@mantine/core';
import { Tooltip } from '../../shared/Tooltip';
export interface ToolWorkflowTitleProps {
title: string;
tooltip?: {
content?: React.ReactNode;
tips?: any[];
header?: {
title: string;
logo?: React.ReactNode;
};
};
}
export function ToolWorkflowTitle({ title, tooltip }: ToolWorkflowTitleProps) {
if (tooltip) {
return (
<>
<Flex justify="center" w="100%">
<Tooltip
content={tooltip.content}
tips={tooltip.tips}
header={tooltip.header}
sidebarTooltip={true}
>
<Flex align="center" gap="xs" onClick={(e) => e.stopPropagation()}>
<Text fw={500} size="xl" p="md">
{title}
</Text>
<span className="material-symbols-rounded" style={{ fontSize: '1.2rem', color: 'var(--icon-files-color)' }}>
gpp_maybe
</span>
</Flex>
</Tooltip>
</Flex>
<Divider />
</>
);
}
return (
<>
<Flex justify="center" w="100%">
<Text fw={500} size="xl" p="md">
{title}
</Text>
</Flex>
<Divider />
</>
);
}

View File

@ -3,6 +3,7 @@ import { Stack } from '@mantine/core';
import { createToolSteps, ToolStepProvider } from './ToolStep';
import OperationButton from './OperationButton';
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
import { ToolWorkflowTitle, ToolWorkflowTitleProps } from './ToolWorkflowTitle';
export interface FilesStepConfig {
selectedFiles: File[];
@ -45,7 +46,10 @@ export interface ReviewStepConfig {
testId?: string;
}
export interface TitleConfig extends ToolWorkflowTitleProps {}
export interface ToolFlowConfig {
title?: TitleConfig;
files: FilesStepConfig;
steps: MiddleStepConfig[];
executeButton?: ExecuteButtonConfig;
@ -63,6 +67,8 @@ export function createToolFlow(config: ToolFlowConfig) {
return (
<Stack gap="sm" p="sm" h="95vh" w="100%" style={{ overflow: 'auto' }}>
<ToolStepProvider forceStepNumbers={config.forceStepNumbers}>
{config.title && <ToolWorkflowTitle {...config.title} />}
{/* Files Step */}
{config.files.isVisible !== false && steps.createFilesStep({
selectedFiles: config.files.selectedFiles,