mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 01:19:24 +00:00
Refactor into tool steps
This commit is contained in:
parent
6d04a80216
commit
55b8455b66
@ -1143,6 +1143,9 @@
|
|||||||
"true": "True",
|
"true": "True",
|
||||||
"false": "False"
|
"false": "False"
|
||||||
},
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "Advanced Options"
|
||||||
|
},
|
||||||
"customFields": {
|
"customFields": {
|
||||||
"title": "Custom Metadata",
|
"title": "Custom Metadata",
|
||||||
"description": "Add custom metadata fields to the document",
|
"description": "Add custom metadata fields to the document",
|
||||||
@ -1185,6 +1188,27 @@
|
|||||||
"bullet1": "Custom Metadata: Add your own key-value pairs",
|
"bullet1": "Custom Metadata: Add your own key-value pairs",
|
||||||
"bullet2": "Trapped Status: High-quality printing setting",
|
"bullet2": "Trapped Status: High-quality printing setting",
|
||||||
"bullet3": "Delete All: Remove all metadata for privacy"
|
"bullet3": "Delete All: Remove all metadata for privacy"
|
||||||
|
},
|
||||||
|
"deleteAll": {
|
||||||
|
"title": "Delete All Metadata",
|
||||||
|
"text": "Complete metadata removal for privacy and clean documents."
|
||||||
|
},
|
||||||
|
"customFields": {
|
||||||
|
"title": "Custom Metadata",
|
||||||
|
"text": "Add your own custom key-value metadata pairs.",
|
||||||
|
"bullet1": "Add any custom fields relevant to your document",
|
||||||
|
"bullet2": "Examples: Department, Project, Version, Status",
|
||||||
|
"bullet3": "Both key and value are required for each entry"
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "Advanced Options",
|
||||||
|
"trapped": {
|
||||||
|
"title": "Trapped Status",
|
||||||
|
"description": "Indicates if document is prepared for high-quality printing.",
|
||||||
|
"bullet1": "True: Document has been trapped for printing",
|
||||||
|
"bullet2": "False: Document has not been trapped",
|
||||||
|
"bullet3": "Unknown: Trapped status is not specified"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
import { Stack, TextInput, Select, Checkbox, Button, Group, Divider, Text } from "@mantine/core";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { ChangeMetadataParameters } from "../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
|
||||||
import { TrappedStatus } from "../../../types/metadata";
|
|
||||||
import { PDFMetadataService } from "../../../services/pdfMetadataService";
|
|
||||||
import { useSelectedFiles } from "../../../contexts/file/fileHooks";
|
|
||||||
|
|
||||||
interface ChangeMetadataSettingsProps {
|
|
||||||
parameters: ChangeMetadataParameters;
|
|
||||||
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
addCustomMetadata: (key?: string, value?: string) => void;
|
|
||||||
removeCustomMetadata: (id: string) => void;
|
|
||||||
updateCustomMetadata: (id: string, key: string, value: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const ChangeMetadataSettings = ({
|
|
||||||
parameters,
|
|
||||||
onParameterChange,
|
|
||||||
disabled = false,
|
|
||||||
addCustomMetadata,
|
|
||||||
removeCustomMetadata,
|
|
||||||
updateCustomMetadata
|
|
||||||
}: ChangeMetadataSettingsProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { selectedFiles } = useSelectedFiles();
|
|
||||||
const [isExtractingMetadata, setIsExtractingMetadata] = useState(false);
|
|
||||||
const [hasExtractedMetadata, setHasExtractedMetadata] = useState(false);
|
|
||||||
|
|
||||||
const isDeleteAllEnabled = parameters.deleteAll;
|
|
||||||
const fieldsDisabled = disabled || isDeleteAllEnabled || isExtractingMetadata;
|
|
||||||
|
|
||||||
// Extract metadata from first file when files change
|
|
||||||
useEffect(() => {
|
|
||||||
const extractMetadata = async () => {
|
|
||||||
if (selectedFiles.length === 0 || hasExtractedMetadata) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstFile = selectedFiles[0];
|
|
||||||
if (!firstFile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsExtractingMetadata(true);
|
|
||||||
try {
|
|
||||||
const result = await PDFMetadataService.extractMetadata(firstFile);
|
|
||||||
|
|
||||||
if (result.success) {
|
|
||||||
const metadata = result.metadata;
|
|
||||||
|
|
||||||
// Pre-populate all fields with extracted metadata
|
|
||||||
onParameterChange('title', metadata.title);
|
|
||||||
onParameterChange('author', metadata.author);
|
|
||||||
onParameterChange('subject', metadata.subject);
|
|
||||||
onParameterChange('keywords', metadata.keywords);
|
|
||||||
onParameterChange('creator', metadata.creator);
|
|
||||||
onParameterChange('producer', metadata.producer);
|
|
||||||
onParameterChange('creationDate', metadata.creationDate);
|
|
||||||
onParameterChange('modificationDate', metadata.modificationDate);
|
|
||||||
onParameterChange('trapped', metadata.trapped);
|
|
||||||
|
|
||||||
// Set custom metadata entries directly to avoid state update timing issues
|
|
||||||
onParameterChange('customMetadata', metadata.customMetadata);
|
|
||||||
|
|
||||||
setHasExtractedMetadata(true);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Failed to extract metadata:', error);
|
|
||||||
} finally {
|
|
||||||
setIsExtractingMetadata(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extractMetadata();
|
|
||||||
}, [selectedFiles, hasExtractedMetadata, onParameterChange, addCustomMetadata, updateCustomMetadata, removeCustomMetadata, parameters.customMetadata]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack gap="md">
|
|
||||||
{/* Delete All Option */}
|
|
||||||
<Checkbox
|
|
||||||
label={t('changeMetadata.deleteAll.label', 'Delete all metadata')}
|
|
||||||
description={t('changeMetadata.deleteAll.description', 'Remove all metadata from the PDF document')}
|
|
||||||
checked={parameters.deleteAll}
|
|
||||||
onChange={(e) => onParameterChange('deleteAll', e.target.checked)}
|
|
||||||
disabled={disabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* Standard Metadata Fields */}
|
|
||||||
<Stack gap="md">
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{t('changeMetadata.standardFields.title', 'Standard Metadata')}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.title.label', 'Title')}
|
|
||||||
placeholder={t('changeMetadata.title.placeholder', 'Document title')}
|
|
||||||
value={parameters.title}
|
|
||||||
onChange={(e) => onParameterChange('title', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.author.label', 'Author')}
|
|
||||||
placeholder={t('changeMetadata.author.placeholder', 'Document author')}
|
|
||||||
value={parameters.author}
|
|
||||||
onChange={(e) => onParameterChange('author', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.subject.label', 'Subject')}
|
|
||||||
placeholder={t('changeMetadata.subject.placeholder', 'Document subject')}
|
|
||||||
value={parameters.subject}
|
|
||||||
onChange={(e) => onParameterChange('subject', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.keywords.label', 'Keywords')}
|
|
||||||
placeholder={t('changeMetadata.keywords.placeholder', 'Document keywords')}
|
|
||||||
value={parameters.keywords}
|
|
||||||
onChange={(e) => onParameterChange('keywords', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.creator.label', 'Creator')}
|
|
||||||
placeholder={t('changeMetadata.creator.placeholder', 'Document creator')}
|
|
||||||
value={parameters.creator}
|
|
||||||
onChange={(e) => onParameterChange('creator', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.producer.label', 'Producer')}
|
|
||||||
placeholder={t('changeMetadata.producer.placeholder', 'Document producer')}
|
|
||||||
value={parameters.producer}
|
|
||||||
onChange={(e) => onParameterChange('producer', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* Date Fields */}
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{t('changeMetadata.dates.title', 'Document Dates')}
|
|
||||||
</Text>
|
|
||||||
<Text size="xs" c="dimmed">
|
|
||||||
{t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.creationDate.label', 'Creation Date')}
|
|
||||||
placeholder={t('changeMetadata.creationDate.placeholder', 'e.g. 2025/01/17 14:30:00')}
|
|
||||||
value={parameters.creationDate}
|
|
||||||
onChange={(e) => onParameterChange('creationDate', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label={t('changeMetadata.modificationDate.label', 'Modification Date')}
|
|
||||||
placeholder={t('changeMetadata.modificationDate.placeholder', 'e.g. 2025/01/17 14:30:00')}
|
|
||||||
value={parameters.modificationDate}
|
|
||||||
onChange={(e) => onParameterChange('modificationDate', e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Trapped Status */}
|
|
||||||
<Select
|
|
||||||
label={t('changeMetadata.trapped.label', 'Trapped Status')}
|
|
||||||
description={t('changeMetadata.trapped.description', 'Indicates whether the document has been trapped for high-quality printing')}
|
|
||||||
value={parameters.trapped}
|
|
||||||
onChange={(value) => {
|
|
||||||
if (value) {
|
|
||||||
onParameterChange('trapped', value as TrappedStatus);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
data={[
|
|
||||||
{ value: TrappedStatus.UNKNOWN, label: t('changeMetadata.trapped.unknown', 'Unknown') },
|
|
||||||
{ value: TrappedStatus.TRUE, label: t('changeMetadata.trapped.true', 'True') },
|
|
||||||
{ value: TrappedStatus.FALSE, label: t('changeMetadata.trapped.false', 'False') }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{/* Custom Metadata */}
|
|
||||||
<Stack gap="sm">
|
|
||||||
<Group justify="space-between" align="center">
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{t('changeMetadata.customFields.title', 'Custom Metadata')}
|
|
||||||
</Text>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant="light"
|
|
||||||
onClick={() => addCustomMetadata()}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
>
|
|
||||||
{t('changeMetadata.customFields.add', 'Add Field')}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
{parameters.customMetadata.length > 0 && (
|
|
||||||
<Text size="xs" c="dimmed">
|
|
||||||
{t('changeMetadata.customFields.description', 'Add custom metadata fields to the document')}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{parameters.customMetadata.map((entry) => (
|
|
||||||
<Stack key={entry.id} gap="xs">
|
|
||||||
<TextInput
|
|
||||||
placeholder={t('changeMetadata.customFields.keyPlaceholder', 'Custom key')}
|
|
||||||
value={entry.key}
|
|
||||||
onChange={(e) => updateCustomMetadata(entry.id, e.target.value, entry.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
placeholder={t('changeMetadata.customFields.valuePlaceholder', 'Custom value')}
|
|
||||||
value={entry.value}
|
|
||||||
onChange={(e) => updateCustomMetadata(entry.id, entry.key, e.target.value)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant="light"
|
|
||||||
color="red"
|
|
||||||
onClick={() => removeCustomMetadata(entry.id)}
|
|
||||||
disabled={fieldsDisabled}
|
|
||||||
>
|
|
||||||
{t('changeMetadata.customFields.remove', 'Remove')}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ChangeMetadataSettings;
|
|
@ -0,0 +1,121 @@
|
|||||||
|
import { Stack, Divider, Text } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
import { useMetadataExtraction } from "../../../hooks/tools/changeMetadata/useMetadataExtraction";
|
||||||
|
import DeleteAllStep from "./steps/DeleteAllStep";
|
||||||
|
import StandardMetadataStep from "./steps/StandardMetadataStep";
|
||||||
|
import DocumentDatesStep from "./steps/DocumentDatesStep";
|
||||||
|
import CustomMetadataStep from "./steps/CustomMetadataStep";
|
||||||
|
import AdvancedOptionsStep from "./steps/AdvancedOptionsStep";
|
||||||
|
|
||||||
|
interface ChangeMetadataSingleStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
addCustomMetadata: (key?: string, value?: string) => void;
|
||||||
|
removeCustomMetadata: (id: string) => void;
|
||||||
|
updateCustomMetadata: (id: string, key: string, value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChangeMetadataSingleStep = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false,
|
||||||
|
addCustomMetadata,
|
||||||
|
removeCustomMetadata,
|
||||||
|
updateCustomMetadata
|
||||||
|
}: ChangeMetadataSingleStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
// Create a params object that matches the hook interface
|
||||||
|
const paramsHook = {
|
||||||
|
parameters,
|
||||||
|
updateParameter: onParameterChange,
|
||||||
|
addCustomMetadata,
|
||||||
|
removeCustomMetadata,
|
||||||
|
updateCustomMetadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extract metadata from uploaded files
|
||||||
|
const { isExtractingMetadata } = useMetadataExtraction(paramsHook);
|
||||||
|
|
||||||
|
const isDeleteAllEnabled = parameters.deleteAll;
|
||||||
|
const fieldsDisabled = disabled || isDeleteAllEnabled || isExtractingMetadata;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="md">
|
||||||
|
{/* Delete All */}
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.deleteAll.label', 'Delete All Metadata')}
|
||||||
|
</Text>
|
||||||
|
<DeleteAllStep
|
||||||
|
parameters={parameters}
|
||||||
|
onParameterChange={onParameterChange}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
{/* Standard Metadata Fields */}
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.standardFields.title', 'Standard Metadata')}
|
||||||
|
</Text>
|
||||||
|
<StandardMetadataStep
|
||||||
|
parameters={parameters}
|
||||||
|
onParameterChange={onParameterChange}
|
||||||
|
disabled={fieldsDisabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
{/* Document Dates */}
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.dates.title', 'Document Dates')}
|
||||||
|
</Text>
|
||||||
|
<DocumentDatesStep
|
||||||
|
parameters={parameters}
|
||||||
|
onParameterChange={onParameterChange}
|
||||||
|
disabled={fieldsDisabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
{/* Custom Metadata */}
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.customFields.title', 'Custom Metadata')}
|
||||||
|
</Text>
|
||||||
|
<CustomMetadataStep
|
||||||
|
parameters={parameters}
|
||||||
|
onParameterChange={onParameterChange}
|
||||||
|
disabled={fieldsDisabled}
|
||||||
|
addCustomMetadata={addCustomMetadata}
|
||||||
|
removeCustomMetadata={removeCustomMetadata}
|
||||||
|
updateCustomMetadata={updateCustomMetadata}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
{/* Advanced Options */}
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.advanced.title', 'Advanced Options')}
|
||||||
|
</Text>
|
||||||
|
<AdvancedOptionsStep
|
||||||
|
parameters={parameters}
|
||||||
|
onParameterChange={onParameterChange}
|
||||||
|
disabled={fieldsDisabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChangeMetadataSingleStep;
|
@ -0,0 +1,39 @@
|
|||||||
|
import { Select } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
import { TrappedStatus } from "../../../../types/metadata";
|
||||||
|
|
||||||
|
interface AdvancedOptionsStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AdvancedOptionsStep = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false
|
||||||
|
}: AdvancedOptionsStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label={t('changeMetadata.trapped.label', 'Trapped Status')}
|
||||||
|
description={t('changeMetadata.trapped.description', 'Indicates whether the document has been trapped for high-quality printing')}
|
||||||
|
value={parameters.trapped}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (value) {
|
||||||
|
onParameterChange('trapped', value as TrappedStatus);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled || parameters.deleteAll}
|
||||||
|
data={[
|
||||||
|
{ value: TrappedStatus.UNKNOWN, label: t('changeMetadata.trapped.unknown', 'Unknown') },
|
||||||
|
{ value: TrappedStatus.TRUE, label: t('changeMetadata.trapped.true', 'True') },
|
||||||
|
{ value: TrappedStatus.FALSE, label: t('changeMetadata.trapped.false', 'False') }
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdvancedOptionsStep;
|
@ -0,0 +1,74 @@
|
|||||||
|
import { Stack, TextInput, Button, Group, Text } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
|
||||||
|
interface CustomMetadataStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
addCustomMetadata: (key?: string, value?: string) => void;
|
||||||
|
removeCustomMetadata: (id: string) => void;
|
||||||
|
updateCustomMetadata: (id: string, key: string, value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomMetadataStep = ({
|
||||||
|
parameters,
|
||||||
|
disabled = false,
|
||||||
|
addCustomMetadata,
|
||||||
|
removeCustomMetadata,
|
||||||
|
updateCustomMetadata
|
||||||
|
}: CustomMetadataStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="sm">
|
||||||
|
<Group justify="space-between" align="center">
|
||||||
|
<Text size="sm" fw={500}>
|
||||||
|
{t('changeMetadata.customFields.title', 'Custom Metadata')}
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="light"
|
||||||
|
onClick={() => addCustomMetadata()}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{t('changeMetadata.customFields.add', 'Add Field')}
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{parameters.customMetadata.length > 0 && (
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
{t('changeMetadata.customFields.description', 'Add custom metadata fields to the document')}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{parameters.customMetadata.map((entry) => (
|
||||||
|
<Stack key={entry.id} gap="xs">
|
||||||
|
<TextInput
|
||||||
|
placeholder={t('changeMetadata.customFields.keyPlaceholder', 'Custom key')}
|
||||||
|
value={entry.key}
|
||||||
|
onChange={(e) => updateCustomMetadata(entry.id, e.target.value, entry.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder={t('changeMetadata.customFields.valuePlaceholder', 'Custom value')}
|
||||||
|
value={entry.value}
|
||||||
|
onChange={(e) => updateCustomMetadata(entry.id, entry.key, e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="light"
|
||||||
|
color="red"
|
||||||
|
onClick={() => removeCustomMetadata(entry.id)}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{t('changeMetadata.customFields.remove', 'Remove')}
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomMetadataStep;
|
@ -0,0 +1,29 @@
|
|||||||
|
import { Checkbox } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
|
||||||
|
interface DeleteAllStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeleteAllStep = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false
|
||||||
|
}: DeleteAllStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
label={t('changeMetadata.deleteAll.label', 'Delete all metadata')}
|
||||||
|
description={t('changeMetadata.deleteAll.description', 'Remove all metadata from the PDF document')}
|
||||||
|
checked={parameters.deleteAll}
|
||||||
|
onChange={(e) => onParameterChange('deleteAll', e.target.checked)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeleteAllStep;
|
@ -0,0 +1,43 @@
|
|||||||
|
import { Stack, TextInput, Text } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
|
||||||
|
interface DocumentDatesStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DocumentDatesStep = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false
|
||||||
|
}: DocumentDatesStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="md">
|
||||||
|
<Text size="xs" c="dimmed">
|
||||||
|
{t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.creationDate.label', 'Creation Date')}
|
||||||
|
placeholder={t('changeMetadata.creationDate.placeholder', 'e.g. 2025/01/17 14:30:00')}
|
||||||
|
value={parameters.creationDate}
|
||||||
|
onChange={(e) => onParameterChange('creationDate', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.modificationDate.label', 'Modification Date')}
|
||||||
|
placeholder={t('changeMetadata.modificationDate.placeholder', 'e.g. 2025/01/17 14:30:00')}
|
||||||
|
value={parameters.modificationDate}
|
||||||
|
onChange={(e) => onParameterChange('modificationDate', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DocumentDatesStep;
|
@ -0,0 +1,71 @@
|
|||||||
|
import { Stack, TextInput } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
|
|
||||||
|
interface StandardMetadataStepProps {
|
||||||
|
parameters: ChangeMetadataParameters;
|
||||||
|
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StandardMetadataStep = ({
|
||||||
|
parameters,
|
||||||
|
onParameterChange,
|
||||||
|
disabled = false
|
||||||
|
}: StandardMetadataStepProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="md">
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.title.label', 'Title')}
|
||||||
|
placeholder={t('changeMetadata.title.placeholder', 'Document title')}
|
||||||
|
value={parameters.title}
|
||||||
|
onChange={(e) => onParameterChange('title', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.author.label', 'Author')}
|
||||||
|
placeholder={t('changeMetadata.author.placeholder', 'Document author')}
|
||||||
|
value={parameters.author}
|
||||||
|
onChange={(e) => onParameterChange('author', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.subject.label', 'Subject')}
|
||||||
|
placeholder={t('changeMetadata.subject.placeholder', 'Document subject')}
|
||||||
|
value={parameters.subject}
|
||||||
|
onChange={(e) => onParameterChange('subject', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.keywords.label', 'Keywords')}
|
||||||
|
placeholder={t('changeMetadata.keywords.placeholder', 'Document keywords')}
|
||||||
|
value={parameters.keywords}
|
||||||
|
onChange={(e) => onParameterChange('keywords', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.creator.label', 'Creator')}
|
||||||
|
placeholder={t('changeMetadata.creator.placeholder', 'Document creator')}
|
||||||
|
value={parameters.creator}
|
||||||
|
onChange={(e) => onParameterChange('creator', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label={t('changeMetadata.producer.label', 'Producer')}
|
||||||
|
placeholder={t('changeMetadata.producer.placeholder', 'Document producer')}
|
||||||
|
value={parameters.producer}
|
||||||
|
onChange={(e) => onParameterChange('producer', e.target.value)}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StandardMetadataStep;
|
@ -1,12 +1,28 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { TooltipContent } from '../../types/tips';
|
import { TooltipContent } from '../../types/tips';
|
||||||
|
|
||||||
export const useChangeMetadataTips = (): TooltipContent => {
|
export const useDeleteAllTips = (): TooltipContent => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
header: {
|
header: {
|
||||||
title: t("changeMetadata.tooltip.header.title", "PDF Metadata Overview")
|
title: t("changeMetadata.tooltip.deleteAll.title", "Delete All Metadata")
|
||||||
|
},
|
||||||
|
tips: [
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.tooltip.deleteAll.title", "Delete All Metadata"),
|
||||||
|
description: t("changeMetadata.tooltip.deleteAll.text", "Complete metadata removal for privacy and clean documents."),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useStandardMetadataTips = (): TooltipContent => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: {
|
||||||
|
title: t("changeMetadata.tooltip.standardFields.title", "Standard Fields")
|
||||||
},
|
},
|
||||||
tips: [
|
tips: [
|
||||||
{
|
{
|
||||||
@ -19,7 +35,19 @@ export const useChangeMetadataTips = (): TooltipContent => {
|
|||||||
t("changeMetadata.tooltip.standardFields.bullet4", "Keywords: Search terms for the document"),
|
t("changeMetadata.tooltip.standardFields.bullet4", "Keywords: Search terms for the document"),
|
||||||
t("changeMetadata.tooltip.standardFields.bullet5", "Creator/Producer: Software used to create the PDF")
|
t("changeMetadata.tooltip.standardFields.bullet5", "Creator/Producer: Software used to create the PDF")
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDocumentDatesTips = (): TooltipContent => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: {
|
||||||
|
title: t("changeMetadata.tooltip.dates.title", "Date Fields")
|
||||||
|
},
|
||||||
|
tips: [
|
||||||
{
|
{
|
||||||
title: t("changeMetadata.tooltip.dates.title", "Date Fields"),
|
title: t("changeMetadata.tooltip.dates.title", "Date Fields"),
|
||||||
description: t("changeMetadata.tooltip.dates.text", "When the document was created and modified."),
|
description: t("changeMetadata.tooltip.dates.text", "When the document was created and modified."),
|
||||||
@ -28,14 +56,47 @@ export const useChangeMetadataTips = (): TooltipContent => {
|
|||||||
t("changeMetadata.tooltip.dates.bullet2", "Modification Date: When last changed"),
|
t("changeMetadata.tooltip.dates.bullet2", "Modification Date: When last changed"),
|
||||||
t("changeMetadata.tooltip.dates.bullet3", "Format: yyyy/MM/dd HH:mm:ss (e.g., 2025/01/17 14:30:00)")
|
t("changeMetadata.tooltip.dates.bullet3", "Format: yyyy/MM/dd HH:mm:ss (e.g., 2025/01/17 14:30:00)")
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCustomMetadataTips = (): TooltipContent => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: {
|
||||||
|
title: t("changeMetadata.tooltip.customFields.title", "Custom Metadata")
|
||||||
|
},
|
||||||
|
tips: [
|
||||||
{
|
{
|
||||||
title: t("changeMetadata.tooltip.options.title", "Additional Options"),
|
title: t("changeMetadata.tooltip.customFields.title", "Custom Metadata"),
|
||||||
description: t("changeMetadata.tooltip.options.text", "Custom fields and privacy controls."),
|
description: t("changeMetadata.tooltip.customFields.text", "Add your own custom key-value metadata pairs."),
|
||||||
bullets: [
|
bullets: [
|
||||||
t("changeMetadata.tooltip.options.bullet1", "Custom Metadata: Add your own key-value pairs"),
|
t("changeMetadata.tooltip.customFields.bullet1", "Add any custom fields relevant to your document"),
|
||||||
t("changeMetadata.tooltip.options.bullet2", "Trapped Status: High-quality printing setting"),
|
t("changeMetadata.tooltip.customFields.bullet2", "Examples: Department, Project, Version, Status"),
|
||||||
t("changeMetadata.tooltip.options.bullet3", "Delete All: Remove all metadata for privacy")
|
t("changeMetadata.tooltip.customFields.bullet3", "Both key and value are required for each entry")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAdvancedOptionsTips = (): TooltipContent => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: {
|
||||||
|
title: t("changeMetadata.tooltip.advanced.title", "Advanced Options")
|
||||||
|
},
|
||||||
|
tips: [
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.tooltip.advanced.trapped.title", "Trapped Status"),
|
||||||
|
description: t("changeMetadata.tooltip.advanced.trapped.description", "Indicates if document is prepared for high-quality printing."),
|
||||||
|
bullets: [
|
||||||
|
t("changeMetadata.tooltip.advanced.trapped.bullet1", "True: Document has been trapped for printing"),
|
||||||
|
t("changeMetadata.tooltip.advanced.trapped.bullet2", "False: Document has not been trapped"),
|
||||||
|
t("changeMetadata.tooltip.advanced.trapped.bullet3", "Unknown: Trapped status is not specified")
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -53,7 +53,7 @@ import RedactSingleStepSettings from "../components/tools/redact/RedactSingleSte
|
|||||||
import Redact from "../tools/Redact";
|
import Redact from "../tools/Redact";
|
||||||
import { ToolId } from "../types/toolId";
|
import { ToolId } from "../types/toolId";
|
||||||
import MergeSettings from '../components/tools/merge/MergeSettings';
|
import MergeSettings from '../components/tools/merge/MergeSettings';
|
||||||
import ChangeMetadataSettings from "../components/tools/changeMetadata/ChangeMetadataSettings";
|
import ChangeMetadataSingleStep from "../components/tools/changeMetadata/ChangeMetadataSingleStep";
|
||||||
|
|
||||||
const showPlaceholderTools = true; // Show all tools; grey out unavailable ones in UI
|
const showPlaceholderTools = true; // Show all tools; grey out unavailable ones in UI
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["update-metadata"],
|
endpoints: ["update-metadata"],
|
||||||
operationConfig: changeMetadataOperationConfig,
|
operationConfig: changeMetadataOperationConfig,
|
||||||
settingsComponent: ChangeMetadataSettings,
|
settingsComponent: ChangeMetadataSingleStep,
|
||||||
},
|
},
|
||||||
// Page Formatting
|
// Page Formatting
|
||||||
|
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { PDFMetadataService } from "../../../services/pdfMetadataService";
|
||||||
|
import { useSelectedFiles } from "../../../contexts/file/fileHooks";
|
||||||
|
import { ChangeMetadataParametersHook } from "./useChangeMetadataParameters";
|
||||||
|
|
||||||
|
export const useMetadataExtraction = (params: ChangeMetadataParametersHook) => {
|
||||||
|
const { selectedFiles } = useSelectedFiles();
|
||||||
|
const [isExtractingMetadata, setIsExtractingMetadata] = useState(false);
|
||||||
|
const [hasExtractedMetadata, setHasExtractedMetadata] = useState(false);
|
||||||
|
|
||||||
|
// Extract metadata from first file when files change
|
||||||
|
useEffect(() => {
|
||||||
|
const extractMetadata = async () => {
|
||||||
|
if (selectedFiles.length === 0 || hasExtractedMetadata) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstFile = selectedFiles[0];
|
||||||
|
if (!firstFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsExtractingMetadata(true);
|
||||||
|
try {
|
||||||
|
const result = await PDFMetadataService.extractMetadata(firstFile);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
const metadata = result.metadata;
|
||||||
|
|
||||||
|
// Pre-populate all fields with extracted metadata
|
||||||
|
params.updateParameter('title', metadata.title);
|
||||||
|
params.updateParameter('author', metadata.author);
|
||||||
|
params.updateParameter('subject', metadata.subject);
|
||||||
|
params.updateParameter('keywords', metadata.keywords);
|
||||||
|
params.updateParameter('creator', metadata.creator);
|
||||||
|
params.updateParameter('producer', metadata.producer);
|
||||||
|
params.updateParameter('creationDate', metadata.creationDate);
|
||||||
|
params.updateParameter('modificationDate', metadata.modificationDate);
|
||||||
|
params.updateParameter('trapped', metadata.trapped);
|
||||||
|
|
||||||
|
// Set custom metadata entries directly to avoid state update timing issues
|
||||||
|
params.updateParameter('customMetadata', metadata.customMetadata);
|
||||||
|
|
||||||
|
setHasExtractedMetadata(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to extract metadata:', error);
|
||||||
|
} finally {
|
||||||
|
setIsExtractingMetadata(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extractMetadata();
|
||||||
|
}, [selectedFiles, hasExtractedMetadata, params]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isExtractingMetadata,
|
||||||
|
hasExtractedMetadata,
|
||||||
|
};
|
||||||
|
};
|
@ -1,15 +1,40 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||||
import ChangeMetadataSettings from "../components/tools/changeMetadata/ChangeMetadataSettings";
|
import DeleteAllStep from "../components/tools/changeMetadata/steps/DeleteAllStep";
|
||||||
|
import StandardMetadataStep from "../components/tools/changeMetadata/steps/StandardMetadataStep";
|
||||||
|
import DocumentDatesStep from "../components/tools/changeMetadata/steps/DocumentDatesStep";
|
||||||
|
import CustomMetadataStep from "../components/tools/changeMetadata/steps/CustomMetadataStep";
|
||||||
|
import AdvancedOptionsStep from "../components/tools/changeMetadata/steps/AdvancedOptionsStep";
|
||||||
import { useChangeMetadataParameters } from "../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
import { useChangeMetadataParameters } from "../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||||
import { useChangeMetadataOperation } from "../hooks/tools/changeMetadata/useChangeMetadataOperation";
|
import { useChangeMetadataOperation } from "../hooks/tools/changeMetadata/useChangeMetadataOperation";
|
||||||
|
import { useMetadataExtraction } from "../hooks/tools/changeMetadata/useMetadataExtraction";
|
||||||
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
import { useChangeMetadataTips } from "../components/tooltips/useChangeMetadataTips";
|
import {
|
||||||
|
useDeleteAllTips,
|
||||||
|
useStandardMetadataTips,
|
||||||
|
useDocumentDatesTips,
|
||||||
|
useCustomMetadataTips,
|
||||||
|
useAdvancedOptionsTips
|
||||||
|
} from "../components/tooltips/useChangeMetadataTips";
|
||||||
|
|
||||||
const ChangeMetadata = (props: BaseToolProps) => {
|
const ChangeMetadata = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const changeMetadataTips = useChangeMetadataTips();
|
|
||||||
|
// Individual tooltips for each step
|
||||||
|
const deleteAllTips = useDeleteAllTips();
|
||||||
|
const standardMetadataTips = useStandardMetadataTips();
|
||||||
|
const documentDatesTips = useDocumentDatesTips();
|
||||||
|
const customMetadataTips = useCustomMetadataTips();
|
||||||
|
const advancedOptionsTips = useAdvancedOptionsTips();
|
||||||
|
|
||||||
|
// Individual step collapse states
|
||||||
|
const [deleteAllCollapsed, setDeleteAllCollapsed] = useState(false);
|
||||||
|
const [standardMetadataCollapsed, setStandardMetadataCollapsed] = useState(false);
|
||||||
|
const [documentDatesCollapsed, setDocumentDatesCollapsed] = useState(true);
|
||||||
|
const [customMetadataCollapsed, setCustomMetadataCollapsed] = useState(true);
|
||||||
|
const [advancedOptionsCollapsed, setAdvancedOptionsCollapsed] = useState(true);
|
||||||
|
|
||||||
const base = useBaseTool(
|
const base = useBaseTool(
|
||||||
'changeMetadata',
|
'changeMetadata',
|
||||||
@ -18,6 +43,14 @@ const ChangeMetadata = (props: BaseToolProps) => {
|
|||||||
props,
|
props,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Extract metadata from uploaded files
|
||||||
|
const { isExtractingMetadata } = useMetadataExtraction(base.params);
|
||||||
|
|
||||||
|
// Compute actual collapsed state based on results and user state
|
||||||
|
const getActualCollapsedState = (userCollapsed: boolean) => {
|
||||||
|
return (!base.hasFiles || base.hasResults) ? true : userCollapsed; // Force collapse when results are shown
|
||||||
|
};
|
||||||
|
|
||||||
return createToolFlow({
|
return createToolFlow({
|
||||||
files: {
|
files: {
|
||||||
selectedFiles: base.selectedFiles,
|
selectedFiles: base.selectedFiles,
|
||||||
@ -25,21 +58,83 @@ const ChangeMetadata = (props: BaseToolProps) => {
|
|||||||
},
|
},
|
||||||
steps: [
|
steps: [
|
||||||
{
|
{
|
||||||
title: t("changeMetadata.settings.title", "Metadata Settings"),
|
title: t("changeMetadata.deleteAll.label", "Delete All Metadata"),
|
||||||
isCollapsed: base.settingsCollapsed,
|
isCollapsed: getActualCollapsedState(deleteAllCollapsed),
|
||||||
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
onCollapsedClick: base.hasResults
|
||||||
tooltip: changeMetadataTips,
|
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
|
||||||
|
: () => setDeleteAllCollapsed(!deleteAllCollapsed),
|
||||||
|
tooltip: deleteAllTips,
|
||||||
content: (
|
content: (
|
||||||
<ChangeMetadataSettings
|
<DeleteAllStep
|
||||||
parameters={base.params.parameters}
|
parameters={base.params.parameters}
|
||||||
onParameterChange={base.params.updateParameter}
|
onParameterChange={base.params.updateParameter}
|
||||||
disabled={base.endpointLoading}
|
disabled={base.endpointLoading || isExtractingMetadata}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.standardFields.title", "Standard Metadata"),
|
||||||
|
isCollapsed: getActualCollapsedState(standardMetadataCollapsed),
|
||||||
|
onCollapsedClick: base.hasResults
|
||||||
|
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
|
||||||
|
: () => setStandardMetadataCollapsed(!standardMetadataCollapsed),
|
||||||
|
tooltip: standardMetadataTips,
|
||||||
|
content: (
|
||||||
|
<StandardMetadataStep
|
||||||
|
parameters={base.params.parameters}
|
||||||
|
onParameterChange={base.params.updateParameter}
|
||||||
|
disabled={base.endpointLoading || base.params.parameters.deleteAll || isExtractingMetadata}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.dates.title", "Document Dates"),
|
||||||
|
isCollapsed: getActualCollapsedState(documentDatesCollapsed),
|
||||||
|
onCollapsedClick: base.hasResults
|
||||||
|
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
|
||||||
|
: () => setDocumentDatesCollapsed(!documentDatesCollapsed),
|
||||||
|
tooltip: documentDatesTips,
|
||||||
|
content: (
|
||||||
|
<DocumentDatesStep
|
||||||
|
parameters={base.params.parameters}
|
||||||
|
onParameterChange={base.params.updateParameter}
|
||||||
|
disabled={base.endpointLoading || base.params.parameters.deleteAll || isExtractingMetadata}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.customFields.title", "Custom Metadata"),
|
||||||
|
isCollapsed: getActualCollapsedState(customMetadataCollapsed),
|
||||||
|
onCollapsedClick: base.hasResults
|
||||||
|
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
|
||||||
|
: () => setCustomMetadataCollapsed(!customMetadataCollapsed),
|
||||||
|
tooltip: customMetadataTips,
|
||||||
|
content: (
|
||||||
|
<CustomMetadataStep
|
||||||
|
parameters={base.params.parameters}
|
||||||
|
onParameterChange={base.params.updateParameter}
|
||||||
|
disabled={base.endpointLoading || base.params.parameters.deleteAll || isExtractingMetadata}
|
||||||
addCustomMetadata={base.params.addCustomMetadata}
|
addCustomMetadata={base.params.addCustomMetadata}
|
||||||
removeCustomMetadata={base.params.removeCustomMetadata}
|
removeCustomMetadata={base.params.removeCustomMetadata}
|
||||||
updateCustomMetadata={base.params.updateCustomMetadata}
|
updateCustomMetadata={base.params.updateCustomMetadata}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("changeMetadata.advanced.title", "Advanced Options"),
|
||||||
|
isCollapsed: getActualCollapsedState(advancedOptionsCollapsed),
|
||||||
|
onCollapsedClick: base.hasResults
|
||||||
|
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
|
||||||
|
: () => setAdvancedOptionsCollapsed(!advancedOptionsCollapsed),
|
||||||
|
tooltip: advancedOptionsTips,
|
||||||
|
content: (
|
||||||
|
<AdvancedOptionsStep
|
||||||
|
parameters={base.params.parameters}
|
||||||
|
onParameterChange={base.params.updateParameter}
|
||||||
|
disabled={base.endpointLoading || isExtractingMetadata}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
executeButton: {
|
executeButton: {
|
||||||
text: t("changeMetadata.submit", "Update Metadata"),
|
text: t("changeMetadata.submit", "Update Metadata"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user