Skip to content

Commit

Permalink
Re-enable editing for the new Samples query (#165)
Browse files Browse the repository at this point in the history
* Create a mutation placeholder for the new samples update flow

* Implement resolvers for the new sample mutation flow

* Implement update flow for the new samples query

* Fix bug in new samples query when filtering for Tempo data

* Re-enable the higher export limit for samples

* Perform various code cleanups, pruning, and refactors

* Fix bug in new samples query when filtering search values

* Fix bug where export >500 rows shows cols hidden by users
  • Loading branch information
qu8n authored Oct 3, 2024
1 parent 833dff8 commit 3e90b6f
Show file tree
Hide file tree
Showing 13 changed files with 1,635 additions and 1,451 deletions.
5 changes: 1 addition & 4 deletions frontend/src/components/RecordsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
} from "ag-grid-community";
import { DataName, useHookLazyGeneric } from "../shared/types";
import SamplesList, { SampleContext } from "./SamplesList";
import { Sample, SortDirection } from "../generated/graphql";
import { SortDirection } from "../generated/graphql";
import { defaultColDef } from "../shared/helpers";
import { PatientIdsTriplet } from "../pages/patients/PatientsPage";
import {
Expand Down Expand Up @@ -55,7 +55,6 @@ interface IRecordsListProps {
handleDownload: () => void;
samplesColDefs: ColDef[];
sampleContext?: SampleContext;
sampleKeyForUpdate?: keyof Sample;
userEmail?: string | null;
setUserEmail?: Dispatch<SetStateAction<string | null>>;
setCustomSearchVals?: Dispatch<SetStateAction<PatientIdsTriplet[]>>;
Expand All @@ -81,7 +80,6 @@ export default function RecordsList({
handleDownload,
samplesColDefs,
sampleContext,
sampleKeyForUpdate,
userEmail,
setUserEmail,
customToolbarUI,
Expand Down Expand Up @@ -272,7 +270,6 @@ export default function RecordsList({
parentDataName={dataName}
sampleContext={sampleContext}
setUnsavedChanges={setUnsavedChanges}
sampleKeyForUpdate={sampleKeyForUpdate}
userEmail={userEmail}
setUserEmail={setUserEmail}
/>
Expand Down
29 changes: 14 additions & 15 deletions frontend/src/components/SamplesList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Sample, useDashboardSamplesQuery } from "../generated/graphql";
import { useDashboardSamplesQuery } from "../generated/graphql";
import AutoSizer from "react-virtualized-auto-sizer";
import { Button, Col, Container } from "react-bootstrap";
import { Dispatch, SetStateAction, useRef } from "react";
import { DownloadModal } from "./DownloadModal";
// import { UpdateModal } from "./UpdateModal";
import { UpdateModal } from "./UpdateModal";
import { AlertModal } from "./AlertModal";
import { buildTsvString } from "../utils/stringBuilders";
import {
Expand Down Expand Up @@ -48,7 +48,6 @@ interface ISampleListProps {
setUnsavedChanges?: (unsavedChanges: boolean) => void;
parentDataName?: DataName;
sampleContext?: SampleContext;
sampleKeyForUpdate?: keyof Sample;
userEmail?: string | null;
setUserEmail?: Dispatch<SetStateAction<string | null>>;
customToolbarUI?: JSX.Element;
Expand All @@ -59,7 +58,6 @@ export default function SamplesList({
parentDataName,
sampleContext,
setUnsavedChanges,
sampleKeyForUpdate = "hasMetadataSampleMetadata",
userEmail,
setUserEmail,
customToolbarUI,
Expand All @@ -77,11 +75,12 @@ export default function SamplesList({
const params = useParams();
const hasParams = Object.keys(params).length > 0;

const { loading, error, data, startPolling, stopPolling, refetch } =
const { error, data, startPolling, stopPolling, refetch } =
useDashboardSamplesQuery({
variables: {
searchVals: [],
sampleContext,
limit: MAX_ROWS_TABLE,
},
pollInterval: POLLING_INTERVAL,
});
Expand All @@ -95,6 +94,7 @@ export default function SamplesList({
refetch({
searchVals: parseUserSearchVal(userSearchVal),
sampleContext,
limit: MAX_ROWS_TABLE,
}).then(() => {
gridRef.current?.api?.hideOverlay();
});
Expand Down Expand Up @@ -232,23 +232,24 @@ export default function SamplesList({
{showDownloadModal && (
<DownloadModal
loader={() => {
const allColumns = gridRef.current?.columnApi?.getAllGridColumns();
return sampleCount <= MAX_ROWS_TABLE
? Promise.resolve(
buildTsvString(samples!, columnDefs, allColumns)
)
: refetch({ limit: MAX_ROWS_EXPORT }).then((result) =>
buildTsvString(
samples!,
result.data.dashboardSamples!,
columnDefs,
gridRef.current?.columnApi?.getAllGridColumns()
allColumns
)
)
: refetch().then((result) =>
buildTsvString(result.data.dashboardSamples!, columnDefs)
);
}}
onComplete={() => {
setShowDownloadModal(false);
// Reset the limit back to the default value of MAX_ROWS_TABLE.
// Otherwise, polling will use the most recent value MAX_ROWS_EXPORT
refetch();
refetch({ limit: MAX_ROWS_TABLE });
}}
exportFileName={[
parentDataName?.slice(0, -1),
Expand All @@ -260,16 +261,15 @@ export default function SamplesList({
/>
)}

{/* {showUpdateModal && (
{showUpdateModal && (
<UpdateModal
changes={changes}
samples={samples!}
onSuccess={handleDiscardChanges}
onHide={() => setShowUpdateModal(false)}
onOpen={() => stopPolling()}
sampleKeyForUpdate={sampleKeyForUpdate}
/>
)} */}
)}

<AlertModal
show={showAlertModal}
Expand Down Expand Up @@ -382,7 +382,6 @@ export default function SamplesList({
setSampleCount(data?.dashboardSampleCount?.totalCount || 0);
}}
onGridColumnsChanged={() => handleSearch(userSearchVal)}
suppressClickEdit={true} // temporarily disable cell editing
/>
</div>
)}
Expand Down
98 changes: 41 additions & 57 deletions frontend/src/components/UpdateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,32 @@ import "ag-grid-enterprise";
import styles from "./records.module.scss";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { ChangesByPrimaryId, SampleChange } from "../shared/helpers";
import { SampleChange } from "../shared/helpers";
import {
DashboardSample,
DashboardSampleInput,
DashboardSamplesQuery,
SampleUpdateInput,
SampleWhere,
useUpdateSamplesMutation,
useUpdateDashboardSamplesMutation,
} from "../generated/graphql";
import _ from "lodash";

const columnDefs = [
{ field: "primaryId", rowGroup: true, hide: true },
{ field: "fieldName" },
{ field: "oldValue" },
{ field: "newValue" },
];

type ChangesByPrimaryId = {
[primaryId: string]: {
[fieldName: string]: string;
};
};

interface UpdateModalProps {
changes: SampleChange[];
onSuccess: () => void;
onHide: () => void;
samples: DashboardSamplesQuery["dashboardSamples"];
onOpen?: () => void;
sampleKeyForUpdate: keyof DashboardSample;
onOpen: () => void;
}

export function UpdateModal({
Expand All @@ -31,21 +40,13 @@ export function UpdateModal({
onSuccess,
onOpen,
samples,
sampleKeyForUpdate,
}: UpdateModalProps) {
const columnDefs = [
{ field: "primaryId", rowGroup: true, hide: true },
{ field: "fieldName" },
{ field: "oldValue" },
{ field: "newValue" },
];

useEffect(() => {
onOpen && onOpen();
// eslint-disable-next-line
}, []);

const [updateSamplesMutation] = useUpdateSamplesMutation();
const [updateDashboardSamplesMutation] = useUpdateDashboardSamplesMutation();

async function handleSubmitUpdates() {
const changesByPrimaryId: ChangesByPrimaryId = {};
Expand All @@ -57,49 +58,32 @@ export function UpdateModal({
}
}

const updatedSamples = _.cloneDeep(samples);

updatedSamples?.forEach((s) => {
if (!s) return; // TODO: fix this

const primaryId = s.primaryId as string;
if (primaryId in changesByPrimaryId) {
s.revisable = false;

_.forEach(changesByPrimaryId[primaryId], (v, k) => {
/* @ts-ignore */
s[sampleKeyForUpdate][0][k] = v;
});
let newDashboardSamples: DashboardSampleInput[] = [];
samples.forEach((s) => {
if (s.primaryId in changesByPrimaryId) {
const newDashboardSample = {
...s,
revisable: false,
changedFieldNames: Object.keys(changesByPrimaryId[s.primaryId]),
};
for (const [fieldName, newValue] of Object.entries(
changesByPrimaryId[s.primaryId]
)) {
if (fieldName in s) {
(newDashboardSample as any)[fieldName] = newValue;
}
}
delete newDashboardSample.__typename;
newDashboardSamples.push(newDashboardSample);
}
});

for (const [primaryId, changedFields] of Object.entries(
changesByPrimaryId
)) {
updateSamplesMutation({
variables: {
where: {
hasMetadataSampleMetadata_SOME: {
primaryId: primaryId,
},
} as SampleWhere,
update: {
[sampleKeyForUpdate]: [
{
update: {
node: changedFields!,
},
},
],
} as SampleUpdateInput,
},
optimisticResponse: {
updateSamples: {
samples: updatedSamples as any, // TODO: fix this
},
},
});
}
updateDashboardSamplesMutation({
variables: { newDashboardSamples },
optimisticResponse: {
updateDashboardSamples: newDashboardSamples,
},
});

onSuccess();
onHide();
Expand Down
Loading

0 comments on commit 3e90b6f

Please sign in to comment.