Skip to content

Commit

Permalink
WIP export
Browse files Browse the repository at this point in the history
  • Loading branch information
salimkanoun committed Sep 29, 2024
1 parent 167d964 commit b8b832b
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 28 deletions.
4 changes: 2 additions & 2 deletions src/content/patients/AccordionPatient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const AccordionPatient = ({ patient, onPatientSelectionChange, onEditPatient, on
onDeletePatient(patient);
}

const handleSaveClick = (event: React.MouseEvent<HTMLButtonElement | SVGElement>) => {
const handleDownloadClick = (event: React.MouseEvent<HTMLButtonElement | SVGElement>) => {
event.stopPropagation();
const id = toastSuccess("Download started")
exportRessource("patients", patient.id, (mb) => updateExistingToast(id, "Downloaded " + mb + " mb"))
Expand All @@ -63,7 +63,7 @@ const AccordionPatient = ({ patient, onPatientSelectionChange, onEditPatient, on
<div className="flex justify-end w-full space-x-7">
<CheckBox bordered={false} onClick={(event) => event.stopPropagation()} onChange={(event) => setSelected(event.target.checked)} checked={selected} />
<EditButton onClick={handleEditClick} />
<DownloadButton onClick={handleSaveClick} />
<DownloadButton onClick={handleDownloadClick} />
<DeleteButton onClick={handleDeleteClick} />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/content/studies/StudyRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const StudyRoot = ({ patient, onStudyUpdated, onStudySelected, selectedStudies,
};

return (
<div className="flex flex-col min-h-screen">
<div className="flex flex-col">
<div className="flex-grow">
<StudyTable
studies={studies}
Expand Down
131 changes: 107 additions & 24 deletions src/export/ExportRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,128 @@ import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../store";
import ExportStudyTable from "./ExportStudyTable";
import ExportSeriesTable from "./ExportSeriesTable";
import { RiDownload2Line as DownloadIcon } from "react-icons/ri";
import { Button, Card, CardFooter } from "../ui";
import { Colors } from "../utils";
import { Colors, useCustomMutation, useCustomQuery, useCustomToast } from "../utils";
import DropdownButton from "../ui/menu/DropDownButton";
import { getModalities, getPeers } from "../services";
import { useMemo } from "react";
import useToasts from "../services/useToasts";
import { exportResourcesId, exportRessource } from "../services/export";
import { flushExportList } from "../reducers/ExportSlice";

const ExportRoot = () => {

const { toastSuccess, updateExistingToast } = useCustomToast()
const dispatch = useDispatch();
const exportSeriesList = useSelector((state: RootState) => state.export.series);
const exportStudyList = useSelector((state: RootState) => state.export.studies);

const { data: modalities } = useCustomQuery(
['modalities'],
() => getModalities()
)

const { data: peers } = useCustomQuery(
['modalities'],
() => getPeers()
)

const { } = useCustomMutation(

)

const handleClearList = () => {
dispatch(flushExportList())
}

const handleDownload = (hierarchical: boolean) => {
const id = toastSuccess("Download started")
const seriesIds = Object.values(exportSeriesList).map((series) => series.id)
exportResourcesId(seriesIds, (mb) => updateExistingToast(id, "Downloaded " + mb + " mb"), undefined, hierarchical, undefined)
}

const handleExport = () => {
const handleExportToModality = (modalityName: string) => {

}

const downloadOptions = [
{
label: 'Dicomdir',
icon: <DownloadIcon />,
color: 'green',
action: () => handleDownload(false)
},
{
label: 'Hierarchical',
icon: <DownloadIcon />,
color: 'green',
action: () => handleDownload(true)
},
];

const aetOptions = useMemo(() => {
return modalities?.map((modality) => {
return {
label: modality.name,
//icon: <DownloadIcon />,
//color: 'green',
action: () => handleExportToModality(modality.name)
}
}) ?? []
}, [modalities])

const peersOptions = useMemo(() => {
return peers?.map((modality) => {
return {
label: modality.name,
//icon: <DownloadIcon />,
//color: 'green',
action: () => handleExportToModality(modality.name)
}
}) ?? []
}, [peers])

return (
<Card>
<div className="flex flex-col">
<ExportStudyTable studies={Object.values(exportStudyList)}/>
<ExportSeriesTable series={Object.values(exportSeriesList)}/>

</div>
<div>
<CardFooter color={Colors.light} className="flex justify-center gap-3">
<Button
onClick={handleClearList}
color={Colors.warning}
>
Empty List
</Button>
<Button
onClick={handleExport}
color={Colors.danger}
>
Download
</Button>
</CardFooter>
</div>
<div className="flex flex-col">
<ExportStudyTable studies={Object.values(exportStudyList)} />
<ExportSeriesTable series={Object.values(exportSeriesList)} />
</div>
<div>
<CardFooter color={Colors.light} className="flex flex-grow justify-center gap-3">
<div className="flex w-4/5 justify-center gap-3">
<DropdownButton
row={null}
buttonText="Download"
options={downloadOptions}
/>
<DropdownButton
row={null}
buttonText="Send To Modality"
options={aetOptions}
/>
<DropdownButton
row={null}
buttonText="Send To Peer"
options={peersOptions}
/>
<Button
color={Colors.primary}
>Send To GaelO</Button>
</div>
<div className="flex w-1/5 justify-end gap-3">
<Button color={Colors.secondary}>Download as CSV</Button>
<Button
onClick={handleClearList}
color={Colors.warning}
>
Empty List
</Button>
</div>

</CardFooter>
</div>
</Card>
)
}
Expand Down
5 changes: 4 additions & 1 deletion src/export/ExportSeriesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { ColumnDef } from "@tanstack/react-table";
import { Button, Table } from "../ui"
import { Colors, Series } from "../utils";
import { useMemo } from "react";
import { useDispatch } from "react-redux";
import { removeSeriesFromExportList } from "../reducers/ExportSlice";

type ExportSeriesTableProps = {
series: Series[]
}
const ExportSeriesTable = ({ series }: ExportSeriesTableProps) => {
console.log(series)
const dispatch = useDispatch()

const handleDelete = (seriesId: string) => {
dispatch(removeSeriesFromExportList({seriesId : seriesId}))
};

const columns: ColumnDef<Series>[] = useMemo(
Expand Down
5 changes: 5 additions & 0 deletions src/export/ExportStudyTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ColumnDef } from "@tanstack/react-table";

import { Table, Button } from "../ui";
import { Colors, Study } from "../utils";
import { removeSeriesFromExportList } from "../reducers/ExportSlice";

type ExportStudyTableProps = {
studies: Study[];
Expand All @@ -13,6 +14,10 @@ const ExportStudyTable = ({ studies }: ExportStudyTableProps) => {
const dispatch = useDispatch();

const handleDelete = (studyId: string) => {
const studyToDelete = studies.find(study => study.id === studyId)
for(const seriesId of studyToDelete.series){
dispatch(removeSeriesFromExportList({seriesId : seriesId}))
}
};

const columns: ColumnDef<Study>[] = useMemo(
Expand Down
37 changes: 37 additions & 0 deletions src/services/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,43 @@ export const exportFileThroughFilesystemAPI = async (
await readableStream.pipeThrough(progress).pipeTo(writableStream);
};

export const exportResourcesId = (
ids: string[],
onProgress = (_mb: number) => {},
abortController = new AbortController(),
hierarchical = true,
transferSyntax: string | undefined = undefined,
): Promise<any> => {
const body = {
Resources:ids,
Asynchronous: false,
Transcode: transferSyntax,
};
let url = hierarchical ? "/api/tools/create-archive" : "/api/tools/create-media"

return fetch(url, {
method: "POST",
headers: {
Authorization: "Bearer " + getToken(),
"Content-Type": "application/json",
Accept: "application/zip",
},
body: JSON.stringify(body),
signal: abortController.signal
})
.then((answer) => {
if (!answer.ok) throw answer;
const readableStream = answer.body;
let contentType = getContentType(answer.headers);
let filename = getContentDispositionFilename(answer.headers);
exportFileThroughFilesystemAPI(readableStream, contentType, filename, onProgress);
return true;
})
.catch((error) => {
throw error;
});
};

export const exportRessource = (
level: "studies" | "patients" | "series",
studyId: string,
Expand Down

0 comments on commit b8b832b

Please sign in to comment.