Store dates as Date objects

This commit is contained in:
James Brunton 2025-09-15 14:05:36 +01:00
parent 87f89c108a
commit 93366beeae
8 changed files with 49 additions and 87 deletions

View File

@ -1081,13 +1081,6 @@
"changeMetadata": { "changeMetadata": {
"tags": "Title,author,date,creation,time,publisher,producer,stats", "tags": "Title,author,date,creation,time,publisher,producer,stats",
"header": "Change Metadata", "header": "Change Metadata",
"selectText": {
"1": "Please edit the variables you wish to change",
"2": "Delete all metadata",
"3": "Show Custom Metadata:",
"4": "Other Metadata:",
"5": "Add Custom Metadata Entry"
},
"submit": "Change", "submit": "Change",
"filenamePrefix": "metadata", "filenamePrefix": "metadata",
"settings": { "settings": {
@ -1125,16 +1118,15 @@
"placeholder": "Document producer" "placeholder": "Document producer"
}, },
"dates": { "dates": {
"title": "Document Dates", "title": "Document Dates"
"format": "Format: yyyy/MM/dd HH:mm:ss"
}, },
"creationDate": { "creationDate": {
"label": "Creation Date", "label": "Creation Date",
"placeholder": "e.g. 2025/01/17 14:30:00" "placeholder": "Creation date"
}, },
"modificationDate": { "modificationDate": {
"label": "Modification Date", "label": "Modification Date",
"placeholder": "e.g. 2025/01/17 14:30:00" "placeholder": "Modification date"
}, },
"trapped": { "trapped": {
"label": "Trapped Status", "label": "Trapped Status",
@ -1179,8 +1171,7 @@
"title": "Date Fields", "title": "Date Fields",
"text": "When the document was created and modified.", "text": "When the document was created and modified.",
"bullet1": "Creation Date: When original document was made", "bullet1": "Creation Date: When original document was made",
"bullet2": "Modification Date: When last changed", "bullet2": "Modification Date: When last changed"
"bullet3": "Format: yyyy/MM/dd HH:mm:ss (e.g., 2025/01/17 14:30:00)"
}, },
"options": { "options": {
"title": "Additional Options", "title": "Additional Options",

View File

@ -1,4 +1,4 @@
import { Stack, Text } from "@mantine/core"; import { Stack } from "@mantine/core";
import { DateTimePicker } from "@mantine/dates"; import { DateTimePicker } from "@mantine/dates";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
@ -16,43 +16,22 @@ const DocumentDatesStep = ({
}: DocumentDatesStepProps) => { }: DocumentDatesStepProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const parseDate = (dateString: string): Date | null => {
if (!dateString) return null;
const date = new Date(dateString.replace(/(\d{4})\/(\d{2})\/(\d{2}) (\d{2}):(\d{2}):(\d{2})/, '$1-$2-$3T$4:$5:$6'));
return isNaN(date.getTime()) ? null : date;
};
const formatDate = (date: Date | null): string => {
if (!date) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
return ( return (
<Stack gap="md"> <Stack gap="md">
<Text size="xs" c="dimmed">
{t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')}
</Text>
<DateTimePicker <DateTimePicker
label={t('changeMetadata.creationDate.label', 'Creation Date')} label={t('changeMetadata.creationDate.label', 'Creation Date')}
placeholder={t('changeMetadata.creationDate.placeholder', 'e.g. 2025/01/17 14:30:00')} placeholder={t('changeMetadata.creationDate.placeholder', 'Creation date')}
value={parseDate(parameters.creationDate)} value={parameters.creationDate}
onChange={(date) => onParameterChange('creationDate', formatDate(parseDate(date)))} onChange={(date) => onParameterChange('creationDate', date ? new Date(date) : null)}
disabled={disabled} disabled={disabled}
clearable clearable
/> />
<DateTimePicker <DateTimePicker
label={t('changeMetadata.modificationDate.label', 'Modification Date')} label={t('changeMetadata.modificationDate.label', 'Modification Date')}
placeholder={t('changeMetadata.modificationDate.placeholder', 'e.g. 2025/01/17 14:30:00')} placeholder={t('changeMetadata.modificationDate.placeholder', 'Modification date')}
value={parseDate(parameters.modificationDate)} value={parameters.modificationDate}
onChange={(date) => onParameterChange('modificationDate', formatDate(parseDate(date)))} onChange={(date) => onParameterChange('modificationDate', date ? new Date(date) : null)}
disabled={disabled} disabled={disabled}
clearable clearable
/> />

View File

@ -54,7 +54,6 @@ export const useDocumentDatesTips = (): TooltipContent => {
bullets: [ bullets: [
t("changeMetadata.tooltip.dates.bullet1", "Creation Date: When original document was made"), t("changeMetadata.tooltip.dates.bullet1", "Creation Date: When original document was made"),
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)")
] ]
} }
] ]

View File

@ -13,8 +13,8 @@ describe('buildChangeMetadataFormData', () => {
keywords: '', keywords: '',
creator: '', creator: '',
producer: '', producer: '',
creationDate: '', creationDate: null,
modificationDate: '', modificationDate: null,
trapped: TrappedStatus.UNKNOWN, trapped: TrappedStatus.UNKNOWN,
customMetadata: [], customMetadata: [],
deleteAll: false, deleteAll: false,
@ -62,8 +62,8 @@ describe('buildChangeMetadataFormData', () => {
keywords: 'test, keywords', keywords: 'test, keywords',
creator: 'Test Creator', creator: 'Test Creator',
producer: 'Test Producer', producer: 'Test Producer',
creationDate: '2025/01/17 14:30:00', creationDate: new Date('2025/01/17 14:30:00'),
modificationDate: '2025/01/17 15:30:00', modificationDate: new Date('2025/01/17 15:30:00'),
trapped: TrappedStatus.TRUE, trapped: TrappedStatus.TRUE,
}, },
expectedFormData: { expectedFormData: {

View File

@ -3,6 +3,18 @@ import { useToolOperation, ToolType } from '../shared/useToolOperation';
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
import { ChangeMetadataParameters, defaultParameters } from './useChangeMetadataParameters'; import { ChangeMetadataParameters, defaultParameters } from './useChangeMetadataParameters';
// Helper function to format Date object to string
const formatDateForBackend = (date: Date | null): string => {
if (!date) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
};
// Static function that can be used by both the hook and automation executor // Static function that can be used by both the hook and automation executor
export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters, file: File): FormData => { export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters, file: File): FormData => {
const formData = new FormData(); const formData = new FormData();
@ -16,9 +28,9 @@ export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters
formData.append("creator", parameters.creator || ""); formData.append("creator", parameters.creator || "");
formData.append("producer", parameters.producer || ""); formData.append("producer", parameters.producer || "");
// Date fields // Date fields - convert Date objects to strings
formData.append("creationDate", parameters.creationDate || ""); formData.append("creationDate", formatDateForBackend(parameters.creationDate));
formData.append("modificationDate", parameters.modificationDate || ""); formData.append("modificationDate", formatDateForBackend(parameters.modificationDate));
// Trapped status // Trapped status
formData.append("trapped", parameters.trapped || ""); formData.append("trapped", parameters.trapped || "");

View File

@ -1,5 +1,5 @@
import { renderHook, act } from '@testing-library/react'; import { renderHook, act } from '@testing-library/react';
import { useChangeMetadataParameters } from './useChangeMetadataParameters'; import { defaultParameters, useChangeMetadataParameters } from './useChangeMetadataParameters';
import { TrappedStatus } from '../../../types/metadata'; import { TrappedStatus } from '../../../types/metadata';
import { describe, expect, test } from 'vitest'; import { describe, expect, test } from 'vitest';
@ -7,19 +7,7 @@ describe('useChangeMetadataParameters', () => {
test('should initialize with default parameters', () => { test('should initialize with default parameters', () => {
const { result } = renderHook(() => useChangeMetadataParameters()); const { result } = renderHook(() => useChangeMetadataParameters());
expect(result.current.parameters).toEqual({ expect(result.current.parameters).toStrictEqual(defaultParameters);
title: '',
author: '',
subject: '',
keywords: '',
creator: '',
producer: '',
creationDate: '',
modificationDate: '',
trapped: TrappedStatus.UNKNOWN,
customMetadata: [],
deleteAll: false,
});
}); });
describe('parameter updates', () => { describe('parameter updates', () => {
@ -30,8 +18,8 @@ describe('useChangeMetadataParameters', () => {
{ paramName: 'keywords', value: 'test, metadata' }, { paramName: 'keywords', value: 'test, metadata' },
{ paramName: 'creator', value: 'Test Creator' }, { paramName: 'creator', value: 'Test Creator' },
{ paramName: 'producer', value: 'Test Producer' }, { paramName: 'producer', value: 'Test Producer' },
{ paramName: 'creationDate', value: '2025/01/17 14:30:00' }, { paramName: 'creationDate', value: new Date('2025/01/17 14:30:00') },
{ paramName: 'modificationDate', value: '2025/01/17 15:30:00' }, { paramName: 'modificationDate', value: new Date('2025/01/17 15:30:00') },
{ paramName: 'trapped', value: TrappedStatus.TRUE }, { paramName: 'trapped', value: TrappedStatus.TRUE },
{ paramName: 'deleteAll', value: true }, { paramName: 'deleteAll', value: true },
] as const)('should update $paramName parameter', ({ paramName, value }) => { ] as const)('should update $paramName parameter', ({ paramName, value }) => {
@ -54,8 +42,8 @@ describe('useChangeMetadataParameters', () => {
{ description: 'has keywords', updates: { keywords: 'test' }, expected: true }, { description: 'has keywords', updates: { keywords: 'test' }, expected: true },
{ description: 'has creator', updates: { creator: 'Test Creator' }, expected: true }, { description: 'has creator', updates: { creator: 'Test Creator' }, expected: true },
{ description: 'has producer', updates: { producer: 'Test Producer' }, expected: true }, { description: 'has producer', updates: { producer: 'Test Producer' }, expected: true },
{ description: 'has creation date', updates: { creationDate: '2025/01/17 14:30:00' }, expected: true }, { description: 'has creation date', updates: { creationDate: new Date('2025/01/17 14:30:00') }, expected: true },
{ description: 'has modification date', updates: { modificationDate: '2025/01/17 14:30:00' }, expected: true }, { description: 'has modification date', updates: { modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
{ description: 'has trapped status', updates: { trapped: TrappedStatus.TRUE }, expected: true }, { description: 'has trapped status', updates: { trapped: TrappedStatus.TRUE }, expected: true },
{ description: 'no meaningful content', updates: {}, expected: false }, { description: 'no meaningful content', updates: {}, expected: false },
{ description: 'whitespace only', updates: { title: ' ', author: ' ' }, expected: false }, { description: 'whitespace only', updates: { title: ' ', author: ' ' }, expected: false },
@ -72,11 +60,9 @@ describe('useChangeMetadataParameters', () => {
}); });
test.each([ test.each([
{ description: 'invalid creation date', updates: { title: 'Test', creationDate: 'invalid-date' }, expected: false }, { description: 'valid creation date', updates: { title: 'Test', creationDate: new Date('2025/01/17 14:30:00') }, expected: true },
{ description: 'invalid modification date', updates: { title: 'Test', modificationDate: 'not-a-date' }, expected: false }, { description: 'valid modification date', updates: { title: 'Test', modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
{ description: 'valid creation date', updates: { title: 'Test', creationDate: '2025/01/17 14:30:00' }, expected: true }, { description: 'empty dates are valid', updates: { title: 'Test', creationDate: null, modificationDate: null }, expected: true },
{ description: 'valid modification date', updates: { title: 'Test', modificationDate: '2025/01/17 14:30:00' }, expected: true },
{ description: 'empty dates are valid', updates: { title: 'Test', creationDate: '', modificationDate: '' }, expected: true },
])('should validate dates correctly with $description', ({ updates, expected }) => { ])('should validate dates correctly with $description', ({ updates, expected }) => {
const { result } = renderHook(() => useChangeMetadataParameters()); const { result } = renderHook(() => useChangeMetadataParameters());

View File

@ -11,9 +11,9 @@ export interface ChangeMetadataParameters extends BaseParameters {
creator: string; creator: string;
producer: string; producer: string;
// Date fields (format: yyyy/MM/dd HH:mm:ss) // Date fields
creationDate: string; creationDate: Date | null;
modificationDate: string; modificationDate: Date | null;
// Trapped status // Trapped status
trapped: TrappedStatus; trapped: TrappedStatus;
@ -32,8 +32,8 @@ export const defaultParameters: ChangeMetadataParameters = {
keywords: '', keywords: '',
creator: '', creator: '',
producer: '', producer: '',
creationDate: '', creationDate: null,
modificationDate: '', modificationDate: null,
trapped: TrappedStatus.UNKNOWN, trapped: TrappedStatus.UNKNOWN,
customMetadata: [], customMetadata: [],
deleteAll: false, deleteAll: false,
@ -57,8 +57,8 @@ const validateParameters = (params: ChangeMetadataParameters): boolean => {
|| params.keywords.trim() || params.keywords.trim()
|| params.creator.trim() || params.creator.trim()
|| params.producer.trim() || params.producer.trim()
|| params.creationDate.trim() || params.creationDate
|| params.modificationDate.trim() || params.modificationDate
|| params.trapped !== TrappedStatus.UNKNOWN || params.trapped !== TrappedStatus.UNKNOWN
); );
@ -66,12 +66,7 @@ const validateParameters = (params: ChangeMetadataParameters): boolean => {
entry => entry.key.trim() && entry.value.trim() entry => entry.key.trim() && entry.value.trim()
); );
// Date validation if provided return hasStandardMetadata || hasCustomMetadata;
const datePattern = /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/;
const isValidCreationDate = !params.creationDate.trim() || datePattern.test(params.creationDate);
const isValidModificationDate = !params.modificationDate.trim() || datePattern.test(params.modificationDate);
return (hasStandardMetadata || hasCustomMetadata) && isValidCreationDate && isValidModificationDate;
}; };
export type ChangeMetadataParametersHook = BaseParametersHook<ChangeMetadataParameters> & { export type ChangeMetadataParametersHook = BaseParametersHook<ChangeMetadataParameters> & {

View File

@ -47,8 +47,8 @@ export const useMetadataExtraction = (params: MetadataExtractionParams) => {
params.updateParameter('keywords', metadata.keywords); params.updateParameter('keywords', metadata.keywords);
params.updateParameter('creator', metadata.creator); params.updateParameter('creator', metadata.creator);
params.updateParameter('producer', metadata.producer); params.updateParameter('producer', metadata.producer);
params.updateParameter('creationDate', metadata.creationDate); params.updateParameter('creationDate', metadata.creationDate ? new Date(metadata.creationDate) : null);
params.updateParameter('modificationDate', metadata.modificationDate); params.updateParameter('modificationDate', metadata.modificationDate ? new Date(metadata.modificationDate) : null);
params.updateParameter('trapped', metadata.trapped); params.updateParameter('trapped', metadata.trapped);
params.updateParameter('customMetadata', metadata.customMetadata); params.updateParameter('customMetadata', metadata.customMetadata);