mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-23 20:59:23 +00:00
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:
parent
23d86deae7
commit
888bac9408
@ -1970,6 +1970,7 @@
|
|||||||
"dropFilesHere": "Drop files here or click to upload",
|
"dropFilesHere": "Drop files here or click to upload",
|
||||||
"pdfFilesOnly": "PDF files only",
|
"pdfFilesOnly": "PDF files only",
|
||||||
"supportedFileTypes": "Supported file types",
|
"supportedFileTypes": "Supported file types",
|
||||||
|
"upload": "Upload",
|
||||||
"uploadFile": "Upload File",
|
"uploadFile": "Upload File",
|
||||||
"uploadFiles": "Upload Files",
|
"uploadFiles": "Upload Files",
|
||||||
"noFilesInStorage": "No files available in storage. Upload some files first.",
|
"noFilesInStorage": "No files available in storage. Upload some files first.",
|
||||||
|
@ -17,7 +17,7 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card withBorder p={0} h={`calc(${modalHeight} * 0.32 - 1rem)`} style={{ flex: 1, overflow: 'hidden' }}>
|
<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">
|
<Text size="sm" fw={500} ta="center" c="white">
|
||||||
{t('fileManager.details', 'File Details')}
|
{t('fileManager.details', 'File Details')}
|
||||||
</Text>
|
</Text>
|
||||||
@ -31,7 +31,7 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Group justify="space-between" py="xs">
|
<Group justify="space-between" py="xs">
|
||||||
<Text size="sm" c="dimmed">{t('fileManager.fileFormat', 'Format')}</Text>
|
<Text size="sm" c="dimmed">{t('fileManager.fileFormat', 'Format')}</Text>
|
||||||
{currentFile ? (
|
{currentFile ? (
|
||||||
@ -43,7 +43,7 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
|||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Group justify="space-between" py="xs">
|
<Group justify="space-between" py="xs">
|
||||||
<Text size="sm" c="dimmed">{t('fileManager.fileSize', 'Size')}</Text>
|
<Text size="sm" c="dimmed">{t('fileManager.fileSize', 'Size')}</Text>
|
||||||
<Text size="sm" fw={500}>
|
<Text size="sm" fw={500}>
|
||||||
@ -51,7 +51,7 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Group justify="space-between" py="xs">
|
<Group justify="space-between" py="xs">
|
||||||
<Text size="sm" c="dimmed">{t('fileManager.fileVersion', 'Version')}</Text>
|
<Text size="sm" c="dimmed">{t('fileManager.fileVersion', 'Version')}</Text>
|
||||||
<Text size="sm" fw={500}>
|
<Text size="sm" fw={500}>
|
||||||
@ -64,4 +64,4 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FileInfoCard;
|
export default FileInfoCard;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Stack, Text, Button, Group } from '@mantine/core';
|
import { Stack, Text, Button, Group } from '@mantine/core';
|
||||||
import HistoryIcon from '@mui/icons-material/History';
|
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 CloudIcon from '@mui/icons-material/Cloud';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useFileManagerContext } from '../../contexts/FileManagerContext';
|
import { useFileManagerContext } from '../../contexts/FileManagerContext';
|
||||||
@ -10,7 +10,7 @@ interface FileSourceButtonsProps {
|
|||||||
horizontal?: boolean;
|
horizontal?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
|
const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
|
||||||
horizontal = false
|
horizontal = false
|
||||||
}) => {
|
}) => {
|
||||||
const { activeSource, onSourceChange, onLocalFileClick } = useFileManagerContext();
|
const { activeSource, onSourceChange, onLocalFileClick } = useFileManagerContext();
|
||||||
@ -44,11 +44,11 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
|
|||||||
>
|
>
|
||||||
{horizontal ? t('fileManager.recent', 'Recent') : t('fileManager.recent', 'Recent')}
|
{horizontal ? t('fileManager.recent', 'Recent') : t('fileManager.recent', 'Recent')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
color='var(--mantine-color-gray-6)'
|
color='var(--mantine-color-gray-6)'
|
||||||
leftSection={<FolderIcon />}
|
leftSection={<UploadIcon />}
|
||||||
justify={horizontal ? "center" : "flex-start"}
|
justify={horizontal ? "center" : "flex-start"}
|
||||||
onClick={onLocalFileClick}
|
onClick={onLocalFileClick}
|
||||||
fullWidth={!horizontal}
|
fullWidth={!horizontal}
|
||||||
@ -63,9 +63,9 @@ 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>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={buttonProps.variant('drive')}
|
variant={buttonProps.variant('drive')}
|
||||||
leftSection={<CloudIcon />}
|
leftSection={<CloudIcon />}
|
||||||
@ -100,4 +100,4 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FileSourceButtons;
|
export default FileSourceButtons;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
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 { FileMetadata } from '../../types/file';
|
||||||
import DocumentThumbnail from './filePreview/DocumentThumbnail';
|
import DocumentThumbnail from './filePreview/DocumentThumbnail';
|
||||||
import DocumentStack from './filePreview/DocumentStack';
|
import DocumentStack from './filePreview/DocumentStack';
|
||||||
@ -38,7 +39,21 @@ const FilePreview: React.FC<FilePreviewProps> = ({
|
|||||||
onPrevious,
|
onPrevious,
|
||||||
onNext
|
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;
|
const hasMultipleFiles = totalFiles > 1;
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Text } from "@mantine/core";
|
import { Text, Anchor } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
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 {
|
export interface FileStatusIndicatorProps {
|
||||||
selectedFiles?: File[];
|
selectedFiles?: File[];
|
||||||
@ -12,13 +15,39 @@ const FileStatusIndicator = ({
|
|||||||
placeholder,
|
placeholder,
|
||||||
}: FileStatusIndicatorProps) => {
|
}: FileStatusIndicatorProps) => {
|
||||||
const { t } = useTranslation();
|
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) {
|
if (selectedFiles.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Text size="sm" c="dimmed">
|
<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>
|
</Text>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ export interface ToolStepProps {
|
|||||||
_stepNumber?: number; // Internal prop set by ToolStepContainer
|
_stepNumber?: number; // Internal prop set by ToolStepContainer
|
||||||
_excludeFromCount?: boolean; // Internal prop to exclude from visible count calculation
|
_excludeFromCount?: boolean; // Internal prop to exclude from visible count calculation
|
||||||
_noPadding?: boolean; // Internal prop to exclude from default left padding
|
_noPadding?: boolean; // Internal prop to exclude from default left padding
|
||||||
|
alwaysShowTooltip?: boolean; // Force tooltip to show even when collapsed
|
||||||
tooltip?: {
|
tooltip?: {
|
||||||
content?: React.ReactNode;
|
content?: React.ReactNode;
|
||||||
tips?: TooltipTip[];
|
tips?: TooltipTip[];
|
||||||
@ -38,9 +39,10 @@ export interface ToolStepProps {
|
|||||||
const renderTooltipTitle = (
|
const renderTooltipTitle = (
|
||||||
title: string,
|
title: string,
|
||||||
tooltip: ToolStepProps['tooltip'],
|
tooltip: ToolStepProps['tooltip'],
|
||||||
isCollapsed: boolean
|
isCollapsed: boolean,
|
||||||
|
alwaysShowTooltip: boolean = false
|
||||||
) => {
|
) => {
|
||||||
if (tooltip && !isCollapsed) {
|
if (tooltip && (!isCollapsed || alwaysShowTooltip)) {
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={tooltip.content}
|
content={tooltip.content}
|
||||||
@ -77,6 +79,7 @@ const ToolStep = ({
|
|||||||
showNumber,
|
showNumber,
|
||||||
_stepNumber,
|
_stepNumber,
|
||||||
_noPadding,
|
_noPadding,
|
||||||
|
alwaysShowTooltip = false,
|
||||||
tooltip
|
tooltip
|
||||||
}: ToolStepProps) => {
|
}: ToolStepProps) => {
|
||||||
if (!isVisible) return null;
|
if (!isVisible) return null;
|
||||||
@ -118,7 +121,7 @@ const ToolStep = ({
|
|||||||
{stepNumber}
|
{stepNumber}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{renderTooltipTitle(title, tooltip, isCollapsed)}
|
{renderTooltipTitle(title, tooltip, isCollapsed, alwaysShowTooltip)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{isCollapsed ? (
|
{isCollapsed ? (
|
||||||
|
53
frontend/src/components/tools/shared/ToolWorkflowTitle.tsx
Normal file
53
frontend/src/components/tools/shared/ToolWorkflowTitle.tsx
Normal 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 />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { Stack } from '@mantine/core';
|
|||||||
import { createToolSteps, ToolStepProvider } from './ToolStep';
|
import { createToolSteps, ToolStepProvider } from './ToolStep';
|
||||||
import OperationButton from './OperationButton';
|
import OperationButton from './OperationButton';
|
||||||
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
|
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
|
||||||
|
import { ToolWorkflowTitle, ToolWorkflowTitleProps } from './ToolWorkflowTitle';
|
||||||
|
|
||||||
export interface FilesStepConfig {
|
export interface FilesStepConfig {
|
||||||
selectedFiles: File[];
|
selectedFiles: File[];
|
||||||
@ -45,7 +46,10 @@ export interface ReviewStepConfig {
|
|||||||
testId?: string;
|
testId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TitleConfig extends ToolWorkflowTitleProps {}
|
||||||
|
|
||||||
export interface ToolFlowConfig {
|
export interface ToolFlowConfig {
|
||||||
|
title?: TitleConfig;
|
||||||
files: FilesStepConfig;
|
files: FilesStepConfig;
|
||||||
steps: MiddleStepConfig[];
|
steps: MiddleStepConfig[];
|
||||||
executeButton?: ExecuteButtonConfig;
|
executeButton?: ExecuteButtonConfig;
|
||||||
@ -63,6 +67,8 @@ export function createToolFlow(config: ToolFlowConfig) {
|
|||||||
return (
|
return (
|
||||||
<Stack gap="sm" p="sm" h="95vh" w="100%" style={{ overflow: 'auto' }}>
|
<Stack gap="sm" p="sm" h="95vh" w="100%" style={{ overflow: 'auto' }}>
|
||||||
<ToolStepProvider forceStepNumbers={config.forceStepNumbers}>
|
<ToolStepProvider forceStepNumbers={config.forceStepNumbers}>
|
||||||
|
{config.title && <ToolWorkflowTitle {...config.title} />}
|
||||||
|
|
||||||
{/* Files Step */}
|
{/* Files Step */}
|
||||||
{config.files.isVisible !== false && steps.createFilesStep({
|
{config.files.isVisible !== false && steps.createFilesStep({
|
||||||
selectedFiles: config.files.selectedFiles,
|
selectedFiles: config.files.selectedFiles,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user