mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-13 02:18:16 +01:00
V2 change metadata (#4433)
# Description of Changes Add Change Metadata tool
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { Stack, Divider, Text } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ChangeMetadataParameters, createCustomMetadataFunctions } 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 AdvancedOptionsStep from "./steps/AdvancedOptionsStep";
|
||||
|
||||
interface ChangeMetadataSingleStepProps {
|
||||
parameters: ChangeMetadataParameters;
|
||||
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const ChangeMetadataSingleStep = ({
|
||||
parameters,
|
||||
onParameterChange,
|
||||
disabled = false
|
||||
}: ChangeMetadataSingleStepProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Get custom metadata functions using the utility
|
||||
const { addCustomMetadata, removeCustomMetadata, updateCustomMetadata } = createCustomMetadataFunctions(
|
||||
parameters,
|
||||
onParameterChange
|
||||
);
|
||||
|
||||
// Extract metadata from uploaded files
|
||||
const { isExtractingMetadata } = useMetadataExtraction({
|
||||
updateParameter: onParameterChange,
|
||||
});
|
||||
|
||||
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 />
|
||||
|
||||
{/* Advanced Options */}
|
||||
<Stack gap="md">
|
||||
<Text size="sm" fw={500}>
|
||||
{t('changeMetadata.advanced.title', 'Advanced Options')}
|
||||
</Text>
|
||||
<AdvancedOptionsStep
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={fieldsDisabled}
|
||||
addCustomMetadata={addCustomMetadata}
|
||||
removeCustomMetadata={removeCustomMetadata}
|
||||
updateCustomMetadata={updateCustomMetadata}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangeMetadataSingleStep;
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Stack, Select, Divider } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||
import { TrappedStatus } from "../../../../types/metadata";
|
||||
import CustomMetadataStep from "./CustomMetadataStep";
|
||||
|
||||
interface AdvancedOptionsStepProps {
|
||||
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 AdvancedOptionsStep = ({
|
||||
parameters,
|
||||
onParameterChange,
|
||||
disabled = false,
|
||||
addCustomMetadata,
|
||||
removeCustomMetadata,
|
||||
updateCustomMetadata
|
||||
}: AdvancedOptionsStepProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
{/* Trapped Status */}
|
||||
<Select
|
||||
label={t('changeMetadata.trapped.label', 'Trapped Status')}
|
||||
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') }
|
||||
]}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Custom Metadata */}
|
||||
<CustomMetadataStep
|
||||
parameters={parameters}
|
||||
onParameterChange={onParameterChange}
|
||||
disabled={disabled}
|
||||
addCustomMetadata={addCustomMetadata}
|
||||
removeCustomMetadata={removeCustomMetadata}
|
||||
updateCustomMetadata={updateCustomMetadata}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
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,28 @@
|
||||
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.checkbox', 'Delete all metadata')}
|
||||
checked={parameters.deleteAll}
|
||||
onChange={(e) => onParameterChange('deleteAll', e.target.checked)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteAllStep;
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Stack } from "@mantine/core";
|
||||
import { DateTimePicker } from "@mantine/dates";
|
||||
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">
|
||||
<DateTimePicker
|
||||
label={t('changeMetadata.creationDate.label', 'Creation Date')}
|
||||
placeholder={t('changeMetadata.creationDate.placeholder', 'Creation date')}
|
||||
value={parameters.creationDate}
|
||||
onChange={(date) => onParameterChange('creationDate', date ? new Date(date) : null)}
|
||||
disabled={disabled}
|
||||
clearable
|
||||
/>
|
||||
|
||||
<DateTimePicker
|
||||
label={t('changeMetadata.modificationDate.label', 'Modification Date')}
|
||||
placeholder={t('changeMetadata.modificationDate.placeholder', 'Modification date')}
|
||||
value={parameters.modificationDate}
|
||||
onChange={(date) => onParameterChange('modificationDate', date ? new Date(date) : null)}
|
||||
disabled={disabled}
|
||||
clearable
|
||||
/>
|
||||
</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;
|
||||
108
frontend/src/components/tooltips/useChangeMetadataTips.ts
Normal file
108
frontend/src/components/tooltips/useChangeMetadataTips.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TooltipContent } from '../../types/tips';
|
||||
|
||||
export const useDeleteAllTips = (): TooltipContent => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
header: {
|
||||
title: t("changeMetadata.tooltip.deleteAll.title", "Remove Existing Metadata")
|
||||
},
|
||||
tips: [
|
||||
{
|
||||
description: t("changeMetadata.tooltip.deleteAll.text", "Complete metadata deletion to ensure privacy."),
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
export const useStandardMetadataTips = (): TooltipContent => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
header: {
|
||||
title: t("changeMetadata.tooltip.standardFields.title", "Standard Fields")
|
||||
},
|
||||
tips: [
|
||||
{
|
||||
description: t("changeMetadata.tooltip.standardFields.text", "Common PDF metadata fields that describe the document."),
|
||||
bullets: [
|
||||
t("changeMetadata.tooltip.standardFields.bullet1", "Title: Document name or heading"),
|
||||
t("changeMetadata.tooltip.standardFields.bullet2", "Author: Person who created the document"),
|
||||
t("changeMetadata.tooltip.standardFields.bullet3", "Subject: Brief description of content"),
|
||||
t("changeMetadata.tooltip.standardFields.bullet4", "Keywords: Search terms for the document"),
|
||||
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: [
|
||||
{
|
||||
description: t("changeMetadata.tooltip.dates.text", "When the document was created and modified."),
|
||||
bullets: [
|
||||
t("changeMetadata.tooltip.dates.bullet1", "Creation Date: When original document was made"),
|
||||
t("changeMetadata.tooltip.dates.bullet2", "Modification Date: When last changed"),
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
export const useCustomMetadataTips = (): TooltipContent => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
header: {
|
||||
title: t("changeMetadata.tooltip.customFields.title", "Custom Metadata")
|
||||
},
|
||||
tips: [
|
||||
{
|
||||
description: t("changeMetadata.tooltip.customFields.text", "Add your own custom key-value metadata pairs."),
|
||||
bullets: [
|
||||
t("changeMetadata.tooltip.customFields.bullet1", "Add any custom fields relevant to your document"),
|
||||
t("changeMetadata.tooltip.customFields.bullet2", "Examples: Department, Project, Version, Status"),
|
||||
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")
|
||||
]
|
||||
},
|
||||
{
|
||||
title: t("changeMetadata.tooltip.customFields.title", "Custom Metadata"),
|
||||
description: t("changeMetadata.tooltip.customFields.text", "Add your own custom key-value metadata pairs."),
|
||||
bullets: [
|
||||
t("changeMetadata.tooltip.customFields.bullet1", "Add any custom fields relevant to your document"),
|
||||
t("changeMetadata.tooltip.customFields.bullet2", "Examples: Department, Project, Version, Status"),
|
||||
t("changeMetadata.tooltip.customFields.bullet3", "Both key and value are required for each entry")
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user