Compare commits

..

No commits in common. "1ac062155fe317a89804b957b3c755bf1a90206b" and "668c47d5a09b8910875116cd7086f5d04a9bbefc" have entirely different histories.

4 changed files with 74 additions and 146 deletions

View File

@ -14,7 +14,6 @@
"@emotion/styled": "^11.14.0", "@emotion/styled": "^11.14.0",
"@iconify/react": "^6.0.0", "@iconify/react": "^6.0.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.1",
"@mantine/dates": "^8.0.1",
"@mantine/dropzone": "^8.0.1", "@mantine/dropzone": "^8.0.1",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.1",
"@mui/icons-material": "^7.1.0", "@mui/icons-material": "^7.1.0",
@ -1654,22 +1653,6 @@
"react-dom": "^18.x || ^19.x" "react-dom": "^18.x || ^19.x"
} }
}, },
"node_modules/@mantine/dates": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-8.0.1.tgz",
"integrity": "sha512-YCmV5jiGE9Ts2uhNS217IA1Hd5kAa8oaEtfnU0bS1sL36zKEf2s6elmzY718XdF8tFil0jJWAj0jiCrA3/udMg==",
"license": "MIT",
"dependencies": {
"clsx": "^2.1.1"
},
"peerDependencies": {
"@mantine/core": "8.0.1",
"@mantine/hooks": "8.0.1",
"dayjs": ">=1.0.0",
"react": "^18.x || ^19.x",
"react-dom": "^18.x || ^19.x"
}
},
"node_modules/@mantine/dropzone": { "node_modules/@mantine/dropzone": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-8.0.1.tgz", "resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-8.0.1.tgz",
@ -4384,13 +4367,6 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.18",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
"license": "MIT",
"peer": true
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",

View File

@ -10,7 +10,6 @@
"@emotion/styled": "^11.14.0", "@emotion/styled": "^11.14.0",
"@iconify/react": "^6.0.0", "@iconify/react": "^6.0.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.1",
"@mantine/dates": "^8.0.1",
"@mantine/dropzone": "^8.0.1", "@mantine/dropzone": "^8.0.1",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.1",
"@mui/icons-material": "^7.1.0", "@mui/icons-material": "^7.1.0",

View File

@ -1,5 +1,4 @@
import { Stack, Text } from "@mantine/core"; import { Stack, TextInput, Text } from "@mantine/core";
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,45 +15,26 @@ 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"> <Text size="xs" c="dimmed">
{t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')} {t('changeMetadata.dates.format', 'Format: yyyy/MM/dd HH:mm:ss')}
</Text> </Text>
<DateTimePicker <TextInput
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', 'e.g. 2025/01/17 14:30:00')}
value={parseDate(parameters.creationDate)} value={parameters.creationDate}
onChange={(date) => onParameterChange('creationDate', formatDate(parseDate(date)))} onChange={(e) => onParameterChange('creationDate', e.target.value)}
disabled={disabled} disabled={disabled}
clearable
/> />
<DateTimePicker <TextInput
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', 'e.g. 2025/01/17 14:30:00')}
value={parseDate(parameters.modificationDate)} value={parameters.modificationDate}
onChange={(date) => onParameterChange('modificationDate', formatDate(parseDate(date)))} onChange={(e) => onParameterChange('modificationDate', e.target.value)}
disabled={disabled} disabled={disabled}
clearable
/> />
</Stack> </Stack>
); );

View File

@ -17,14 +17,6 @@ import {
useAdvancedOptionsTips useAdvancedOptionsTips
} from "../components/tooltips/useChangeMetadataTips"; } from "../components/tooltips/useChangeMetadataTips";
enum MetadataStep {
NONE = 'none',
DELETE_ALL = 'deleteAll',
STANDARD_METADATA = 'standardMetadata',
DOCUMENT_DATES = 'documentDates',
ADVANCED_OPTIONS = 'advancedOptions'
}
const ChangeMetadata = (props: BaseToolProps) => { const ChangeMetadata = (props: BaseToolProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -34,8 +26,11 @@ const ChangeMetadata = (props: BaseToolProps) => {
const documentDatesTips = useDocumentDatesTips(); const documentDatesTips = useDocumentDatesTips();
const advancedOptionsTips = useAdvancedOptionsTips(); const advancedOptionsTips = useAdvancedOptionsTips();
// Individual step collapse states - only one can be open at a time // Individual step collapse states
const [openStep, setOpenStep] = useState<MetadataStep>(MetadataStep.DELETE_ALL); const [deleteAllCollapsed, setDeleteAllCollapsed] = useState(false);
const [standardMetadataCollapsed, setStandardMetadataCollapsed] = useState(false);
const [documentDatesCollapsed, setDocumentDatesCollapsed] = useState(true);
const [advancedOptionsCollapsed, setAdvancedOptionsCollapsed] = useState(true);
const base = useBaseTool( const base = useBaseTool(
'changeMetadata', 'changeMetadata',
@ -47,55 +42,68 @@ const ChangeMetadata = (props: BaseToolProps) => {
// Extract metadata from uploaded files // Extract metadata from uploaded files
const { isExtractingMetadata } = useMetadataExtraction(base.params); const { isExtractingMetadata } = useMetadataExtraction(base.params);
// Compute actual collapsed state based on results and accordion behavior // Compute actual collapsed state based on results and user state
const getActualCollapsedState = (stepName: MetadataStep) => { const getActualCollapsedState = (userCollapsed: boolean) => {
return (!base.hasFiles || base.hasResults) ? true : openStep !== stepName; return (!base.hasFiles || base.hasResults) ? true : userCollapsed; // Force collapse when results are shown
}; };
// Handle step toggle for accordion behavior return createToolFlow({
const handleStepToggle = (stepName: MetadataStep) => { files: {
if (base.hasResults) { selectedFiles: base.selectedFiles,
if (base.settingsCollapsed) { isCollapsed: base.hasResults,
base.handleSettingsReset(); },
} steps: [
return; {
} title: t("changeMetadata.deleteAll.label", "Delete All Metadata"),
setOpenStep(openStep === stepName ? MetadataStep.NONE : stepName); isCollapsed: getActualCollapsedState(deleteAllCollapsed),
}; onCollapsedClick: base.hasResults
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
// Create step objects : () => setDeleteAllCollapsed(!deleteAllCollapsed),
const createStandardMetadataStep = () => ({ tooltip: deleteAllTips,
content: (
<DeleteAllStep
parameters={base.params.parameters}
onParameterChange={base.params.updateParameter}
disabled={base.endpointLoading || isExtractingMetadata}
/>
),
},
{
title: t("changeMetadata.standardFields.title", "Standard Metadata"), title: t("changeMetadata.standardFields.title", "Standard Metadata"),
isCollapsed: getActualCollapsedState(MetadataStep.STANDARD_METADATA), isCollapsed: getActualCollapsedState(standardMetadataCollapsed),
onCollapsedClick: () => handleStepToggle(MetadataStep.STANDARD_METADATA), onCollapsedClick: base.hasResults
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
: () => setStandardMetadataCollapsed(!standardMetadataCollapsed),
tooltip: standardMetadataTips, tooltip: standardMetadataTips,
content: ( content: (
<StandardMetadataStep <StandardMetadataStep
parameters={base.params.parameters} parameters={base.params.parameters}
onParameterChange={base.params.updateParameter} onParameterChange={base.params.updateParameter}
disabled={base.endpointLoading || isExtractingMetadata} disabled={base.endpointLoading || base.params.parameters.deleteAll || isExtractingMetadata}
/> />
), ),
}); },
{
const createDocumentDatesStep = () => ({
title: t("changeMetadata.dates.title", "Document Dates"), title: t("changeMetadata.dates.title", "Document Dates"),
isCollapsed: getActualCollapsedState(MetadataStep.DOCUMENT_DATES), isCollapsed: getActualCollapsedState(documentDatesCollapsed),
onCollapsedClick: () => handleStepToggle(MetadataStep.DOCUMENT_DATES), onCollapsedClick: base.hasResults
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
: () => setDocumentDatesCollapsed(!documentDatesCollapsed),
tooltip: documentDatesTips, tooltip: documentDatesTips,
content: ( content: (
<DocumentDatesStep <DocumentDatesStep
parameters={base.params.parameters} parameters={base.params.parameters}
onParameterChange={base.params.updateParameter} onParameterChange={base.params.updateParameter}
disabled={base.endpointLoading || isExtractingMetadata} disabled={base.endpointLoading || base.params.parameters.deleteAll || isExtractingMetadata}
/> />
), ),
}); },
{
const createAdvancedOptionsStep = () => ({
title: t("changeMetadata.advanced.title", "Advanced Options"), title: t("changeMetadata.advanced.title", "Advanced Options"),
isCollapsed: getActualCollapsedState(MetadataStep.ADVANCED_OPTIONS), isCollapsed: getActualCollapsedState(advancedOptionsCollapsed),
onCollapsedClick: () => handleStepToggle(MetadataStep.ADVANCED_OPTIONS), onCollapsedClick: base.hasResults
? (base.settingsCollapsed ? base.handleSettingsReset : undefined)
: () => setAdvancedOptionsCollapsed(!advancedOptionsCollapsed),
tooltip: advancedOptionsTips, tooltip: advancedOptionsTips,
content: ( content: (
<AdvancedOptionsStep <AdvancedOptionsStep
@ -107,43 +115,8 @@ const ChangeMetadata = (props: BaseToolProps) => {
updateCustomMetadata={base.params.updateCustomMetadata} updateCustomMetadata={base.params.updateCustomMetadata}
/> />
), ),
});
// Build steps array based on deleteAll state
const buildSteps = () => {
const steps = [
{
title: t("changeMetadata.deleteAll.label", "Delete All Metadata"),
isCollapsed: getActualCollapsedState(MetadataStep.DELETE_ALL),
onCollapsedClick: () => handleStepToggle(MetadataStep.DELETE_ALL),
tooltip: deleteAllTips,
content: (
<DeleteAllStep
parameters={base.params.parameters}
onParameterChange={base.params.updateParameter}
disabled={base.endpointLoading || isExtractingMetadata}
/>
),
}, },
]; ],
if (!base.params.parameters.deleteAll) {
steps.push(
createStandardMetadataStep(),
createDocumentDatesStep(),
createAdvancedOptionsStep()
);
}
return steps;
};
return createToolFlow({
files: {
selectedFiles: base.selectedFiles,
isCollapsed: base.hasResults,
},
steps: buildSteps(),
executeButton: { executeButton: {
text: t("changeMetadata.submit", "Update Metadata"), text: t("changeMetadata.submit", "Update Metadata"),
isVisible: !base.hasResults, isVisible: !base.hasResults,