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": {
"tags": "Title,author,date,creation,time,publisher,producer,stats",
"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",
"filenamePrefix": "metadata",
"settings": {
@ -1125,16 +1118,15 @@
"placeholder": "Document producer"
},
"dates": {
"title": "Document Dates",
"format": "Format: yyyy/MM/dd HH:mm:ss"
"title": "Document Dates"
},
"creationDate": {
"label": "Creation Date",
"placeholder": "e.g. 2025/01/17 14:30:00"
"placeholder": "Creation date"
},
"modificationDate": {
"label": "Modification Date",
"placeholder": "e.g. 2025/01/17 14:30:00"
"placeholder": "Modification date"
},
"trapped": {
"label": "Trapped Status",
@ -1179,8 +1171,7 @@
"title": "Date Fields",
"text": "When the document was created and modified.",
"bullet1": "Creation Date: When original document was made",
"bullet2": "Modification Date: When last changed",
"bullet3": "Format: yyyy/MM/dd HH:mm:ss (e.g., 2025/01/17 14:30:00)"
"bullet2": "Modification Date: When last changed"
},
"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 { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";
@ -16,43 +16,22 @@ const DocumentDatesStep = ({
}: DocumentDatesStepProps) => {
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 (
<Stack gap="md">
<Text size="xs" c="dimmed">
{t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')}
</Text>
<DateTimePicker
label={t('changeMetadata.creationDate.label', 'Creation Date')}
placeholder={t('changeMetadata.creationDate.placeholder', 'e.g. 2025/01/17 14:30:00')}
value={parseDate(parameters.creationDate)}
onChange={(date) => onParameterChange('creationDate', formatDate(parseDate(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', 'e.g. 2025/01/17 14:30:00')}
value={parseDate(parameters.modificationDate)}
onChange={(date) => onParameterChange('modificationDate', formatDate(parseDate(date)))}
placeholder={t('changeMetadata.modificationDate.placeholder', 'Modification date')}
value={parameters.modificationDate}
onChange={(date) => onParameterChange('modificationDate', date ? new Date(date) : null)}
disabled={disabled}
clearable
/>

View File

@ -54,7 +54,6 @@ export const useDocumentDatesTips = (): TooltipContent => {
bullets: [
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.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: '',
creator: '',
producer: '',
creationDate: '',
modificationDate: '',
creationDate: null,
modificationDate: null,
trapped: TrappedStatus.UNKNOWN,
customMetadata: [],
deleteAll: false,
@ -62,8 +62,8 @@ describe('buildChangeMetadataFormData', () => {
keywords: 'test, keywords',
creator: 'Test Creator',
producer: 'Test Producer',
creationDate: '2025/01/17 14:30:00',
modificationDate: '2025/01/17 15:30:00',
creationDate: new Date('2025/01/17 14:30:00'),
modificationDate: new Date('2025/01/17 15:30:00'),
trapped: TrappedStatus.TRUE,
},
expectedFormData: {

View File

@ -3,6 +3,18 @@ import { useToolOperation, ToolType } from '../shared/useToolOperation';
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
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
export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters, file: File): FormData => {
const formData = new FormData();
@ -16,9 +28,9 @@ export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters
formData.append("creator", parameters.creator || "");
formData.append("producer", parameters.producer || "");
// Date fields
formData.append("creationDate", parameters.creationDate || "");
formData.append("modificationDate", parameters.modificationDate || "");
// Date fields - convert Date objects to strings
formData.append("creationDate", formatDateForBackend(parameters.creationDate));
formData.append("modificationDate", formatDateForBackend(parameters.modificationDate));
// Trapped status
formData.append("trapped", parameters.trapped || "");

View File

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

View File

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

View File

@ -47,8 +47,8 @@ export const useMetadataExtraction = (params: MetadataExtractionParams) => {
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('creationDate', metadata.creationDate ? new Date(metadata.creationDate) : null);
params.updateParameter('modificationDate', metadata.modificationDate ? new Date(metadata.modificationDate) : null);
params.updateParameter('trapped', metadata.trapped);
params.updateParameter('customMetadata', metadata.customMetadata);