diff --git a/docker-compose.yml b/docker-compose.yml
index b8c830cb..c486fb20 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -63,6 +63,7 @@ services:
PYTHON_PLUGIN_ENABLED: "true"
TRANSFERS_PLUGIN_ENABLED: "true"
WORKLISTS_PLUGIN_ENABLED: "true"
+ ORTHANC__OVERWRITE_INSTANCES: "true"
ORTHANC__DICOM_WEB__ENABLE: "true"
ORTHANC__DICOM_WEB__ROOT: "/dicom-web/"
ORTHANC__DICOM_WEB__ENABLEWADO: "true"
@@ -70,6 +71,7 @@ services:
ORTHANC__DICOM_WEB__SSL: "true"
ORTHANC__DICOM_WEB__STUDIES_METADATA: "MainDicomTags"
ORTHANC__DICOM_WEB__SERIES_METADATA: "Full"
+
volumes:
orthanc-flow:
diff --git a/package.json b/package.json
index 6ad9f12b..499b6de7 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,9 @@
"axios": "^1.7.3",
"i18next": "^23.12.2",
"jwt-decode": "^4.0.0",
+ "mime-types": "^2.1.35",
"moment": "^2.30.1",
+ "native-file-system-adapter": "^3.0.1",
"preline": "^2.4.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -53,6 +55,7 @@
"@storybook/theming": "^8.2.8",
"@tanstack/eslint-plugin-query": "^5.51.15",
"@types/jwt-decode": "^3.1.0",
+ "@types/mime-types": "^2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-query": "^1.2.9",
diff --git a/src/content/ContentRoot.tsx b/src/content/ContentRoot.tsx
index 883ab6be..d7c5a66f 100644
--- a/src/content/ContentRoot.tsx
+++ b/src/content/ContentRoot.tsx
@@ -95,6 +95,7 @@ const ContentRoot: React.FC = () => {
return (
= ({ patient, onEditPatient, onDeletePatient, onStudyUpdated }) => {
+ const {toastSuccess} = useCustomToast()
const [selectedStudyId, setSelectedStudyId] = useState(null);
const handleStudySelected = (studyId: string) => {
@@ -33,6 +35,12 @@ const AccordionPatient: React.FC = ({ patient, onEditPati
onDeletePatient(patient);
}
+ const handleSaveClick = (event: React.MouseEvent) => {
+ event.stopPropagation();
+ toastSuccess("Download started, follow progression in console")
+ exportRessource("patients", patient.id, (mb)=>{console.log(mb + "mb")})
+ }
+
return (
<>
= ({ patient, onEditPati
Nb of Studies: {patient.getStudies().length}
+
diff --git a/src/content/patients/EditPatient.tsx b/src/content/patients/EditPatient.tsx
index c8b6fa5f..7b47e0c8 100644
--- a/src/content/patients/EditPatient.tsx
+++ b/src/content/patients/EditPatient.tsx
@@ -1,8 +1,8 @@
-import React from "react";
+import React, { useState } from "react";
import Patient from "../../model/Patient";
import { modifyPatient } from "../../services";
import { useCustomMutation, useCustomToast } from "../../utils";
-import { PatientPayload, OrthancResponse } from "../../utils/types";
+import { PatientModifyPayload, OrthancResponse } from "../../utils/types";
import PatientEditForm from './PatientEditForm';
import { Modal } from "../../ui";
@@ -14,32 +14,40 @@ type EditPatientProps = {
}
const EditPatient: React.FC = ({ patient, onEditPatient, onClose, show }) => {
- const { toastSuccess, toastError } = useCustomToast();
+ const { toastError } = useCustomToast();
+ const [jobId, setJobId] = useState(null);
- const { mutateAsync: mutatePatient } = useCustomMutation(
+ const { mutateAsync: mutatePatient } = useCustomMutation(
({ id, payload }) => modifyPatient(id, payload),
[['jobs']],
{
- onSuccess: async () => {
- toastSuccess(`Patient updated successfully`);
- onEditPatient(patient);
- onClose();
+ onSuccess: async (data) => {
+ setJobId(data.id);
},
- onError: (error: any) => {
- toastError(`Failed to update patient: ${error}`);
+ onError: () => {
+ toastError(`Failed to update patient`);
}
}
);
- const handleSubmit = ({ id, payload }: { id: string; payload: PatientPayload }) => {
+ const handleSubmit = ({ id, payload }: { id: string; payload: PatientModifyPayload }) => {
mutatePatient({ id, payload });
};
+ const handleJobCompletion = (job: string) => {
+ if (job === "Success") {
+ onEditPatient(patient);
+ onClose();
+ } else if (job === "Failure") {
+ toastError(`Failed to update Study `);
+ }
+ };
+
return (
Edit patient
-
+
);
diff --git a/src/content/patients/PatientEditForm.tsx b/src/content/patients/PatientEditForm.tsx
index 8471a9f3..67c540fc 100644
--- a/src/content/patients/PatientEditForm.tsx
+++ b/src/content/patients/PatientEditForm.tsx
@@ -1,53 +1,62 @@
import React, { ChangeEvent, useState, useEffect } from "react";
import { Button, Input, Spinner } from "../../ui";
import Patient from "../../model/Patient";
-import { PatientMainDicomTags, PatientPayload } from "../../utils/types";
+import { PatientMainDicomTags, PatientModifyPayload } from "../../utils/types";
import CheckBox from "../../ui/Checkbox";
import { Colors } from "../../utils";
import InputWithDelete from "../../ui/InputWithDelete";
+import ProgressJobs from "../../query/ProgressJobs";
type PatientEditFormProps = {
+ jobId: string | null;
patient: Patient;
- onSubmit: (data: { id: string; payload: PatientPayload }) => void;
- onCancel: () => void;
+ onSubmit: (data: { id: string; payload: PatientModifyPayload }) => void;
+ onJobCompleted: (jobStatus :string) => void;
};
- const PatientEditForm = ({ patient, onSubmit, onCancel }: PatientEditFormProps) => {
- const [patientId, setPatientId] = useState(patient?.patientId ?? "");
- const [patientName, setPatientName] = useState(patient?.patientName ?? null);
- const [patientBirthDate, setPatientBirthDate] = useState(patient?.patientBirthDate ?? null);
- const [patientSex, setPatientSex] = useState(patient?.patientSex ?? null);
- const [removePrivateTags, setRemovePrivateTags] = useState(false);
- const [keepSource, setKeepSource] = useState(false);
- const [fieldsToRemove, setFieldsToRemove] = useState([]);
-
- if (!patient) return ;
-
- const handleFieldRemoval = (field: string, checked: boolean) => {
- setFieldsToRemove((prev) =>
- checked ? [...prev, field] : prev.filter((item) => item !== field)
- );
- };
-
- const handleSubmit = (event: React.FormEvent) => {
- event.preventDefault();
- const replace: Partial = {};
-
- if (patientName !== patient.patientName) replace.patientName = patientName;
- if (patientBirthDate !== patient.patientBirthDate) replace.patientBirthDate = patientBirthDate;
- if (patientSex !== patient.patientSex) replace.patientSex = patientSex;
-
- const payload: PatientPayload = {
- replace,
- remove: fieldsToRemove,
- removePrivateTags,
- keepSource,
- force: true,
- synchronous: false,
- };
- onSubmit({ id: patientId, payload });
+const PatientEditForm = ({ patient, jobId, onSubmit, onJobCompleted }: PatientEditFormProps) => {
+ const [patientId, setPatientId] = useState(patient?.patientId ?? "");
+ const [patientName, setPatientName] = useState(patient?.patientName ?? null);
+ const [patientBirthDate, setPatientBirthDate] = useState(patient?.patientBirthDate ?? null);
+ const [patientSex, setPatientSex] = useState(patient?.patientSex ?? null);
+ const [removePrivateTags, setRemovePrivateTags] = useState(false);
+ const [keepSource, setKeepSource] = useState(false);
+ const [fieldsToRemove, setFieldsToRemove] = useState([]);
+ const [keepUIDs, setKeepUIDs] = useState(false)
+
+ if (!patient) return ;
+
+ useEffect(() => {
+ if (keepUIDs) setKeepSource(true)
+ }, [keepUIDs])
+
+ const handleFieldRemoval = (field: string, checked: boolean) => {
+ setFieldsToRemove((prev) =>
+ checked ? [...prev, field] : prev.filter((item) => item !== field)
+ );
+ };
+
+ const handleSubmit = (event: React.FormEvent) => {
+ event.preventDefault();
+ const replace: Partial = {};
+
+ if (patientName !== patient.patientName) replace.patientName = patientName;
+ if (patientId !== patient.patientId) replace.patientId = patientId;
+ if (patientBirthDate !== patient.patientBirthDate) replace.patientBirthDate = patientBirthDate;
+ if (patientSex !== patient.patientSex) replace.patientSex = patientSex;
+
+ const payload: PatientModifyPayload = {
+ replace,
+ remove: fieldsToRemove,
+ removePrivateTags,
+ keepSource,
+ force: true,
+ synchronous: false,
+ keep: keepUIDs ? ['StudyInstanceUID', 'SeriesInstanceUID', 'SOPInstanceUID'] : [],
};
-
+ onSubmit({ id: patient.id, payload });
+ };
+
return (