From 47260eb06781e6fe4a107a4a883a27694ec1fe5c Mon Sep 17 00:00:00 2001
From: Andrew Davison
Date: Thu, 7 Mar 2024 11:33:53 +0100
Subject: [PATCH] Use KeyValueTable component to display metadata
---
.../__tests__/components/DatasetCard.test.jsx | 4 +-
.../src/components/CellPatchingCard.jsx | 54 ++++++----------
apps/nar-v3/src/components/DataFileCard.jsx | 34 +++++-----
apps/nar-v3/src/components/KeyValueTable.jsx | 42 +++++++++++++
.../nar-v3/src/components/PatchedCellCard.jsx | 9 +--
apps/nar-v3/src/components/RecordingCard.jsx | 62 ++++++++-----------
apps/nar-v3/src/components/SliceCard.jsx | 11 ++--
.../src/components/SlicePreparationCard.jsx | 35 +++++------
apps/nar-v3/src/components/SubjectCard.jsx | 40 +++++-------
9 files changed, 148 insertions(+), 143 deletions(-)
create mode 100644 apps/nar-v3/src/components/KeyValueTable.jsx
diff --git a/apps/nar-v3/__tests__/components/DatasetCard.test.jsx b/apps/nar-v3/__tests__/components/DatasetCard.test.jsx
index 5862354..9a4634b 100644
--- a/apps/nar-v3/__tests__/components/DatasetCard.test.jsx
+++ b/apps/nar-v3/__tests__/components/DatasetCard.test.jsx
@@ -2,10 +2,8 @@ import { describe, test, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
-
import DatasetCard from "../../src/components/DatasetCard";
-
describe("DatasetCard component", () => {
test("should render without errors", async () => {
const dataset = {
@@ -545,7 +543,7 @@ describe("DatasetCard component", () => {
],
biologicalSex: "male",
},
- ]
+ ],
};
render();
diff --git a/apps/nar-v3/src/components/CellPatchingCard.jsx b/apps/nar-v3/src/components/CellPatchingCard.jsx
index cc70a42..886860d 100644
--- a/apps/nar-v3/src/components/CellPatchingCard.jsx
+++ b/apps/nar-v3/src/components/CellPatchingCard.jsx
@@ -21,12 +21,31 @@ import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
import { formatQuant } from "../utility";
function CellPatchingCard(props) {
const activity = props.activity;
+ const data = {
+ "Electrode description": activity.device[0].device.description,
+ "Pipette solution (more details to come)": activity.device[0].pipetteSolution.name,
+ "Seal resistance": activity.device[0].sealResistance.value
+ .map((item) => formatQuant(item))
+ .join(", "),
+ "Series resistance": activity.device[0].seriesResistance.value
+ .map((item) => formatQuant(item))
+ .join(", "),
+ "Holding potential": activity.device[0].holdingPotential.value
+ .map((item) => formatQuant(item))
+ .join(", "),
+ "Bath solution (more details to come)": activity.tissueBathSolution.name,
+ "Bath temperature": formatQuant(activity.bathTemperature),
+ Description: activity.description,
+ Type: activity.variation,
+ };
+
if (activity) {
return (
<>
@@ -34,40 +53,7 @@ function CellPatchingCard(props) {
Cell patching
{activity.label}
-
-
- - Electrode description
- - {activity.device[0].device.description}
- {/* activity.device[0].device.deviceType.name */}
- {/* activity.device[0].device.manufacturer.fullName */}
- - Pipette solution (more details to come)
- - {activity.device[0].pipetteSolution.name}
- - Seal resistance
- -
- {activity.device[0].sealResistance.value.map((item) => formatQuant(item)).join(", ")}
-
- - Series resistance
- -
- {activity.device[0].seriesResistance.value
- .map((item) => formatQuant(item))
- .join(", ")}
-
- - Holding potential
- -
- {activity.device[0].holdingPotential.value
- .map((item) => formatQuant(item))
- .join(", ")}
-
-
- - Bath solution (more details to come)
- - {activity.tissueBathSolution.name}
- - Bath temperature
- - {formatQuant(activity.bathTemperature)}
- - Description
- - {activity.description}
- - Type
- - {activity.variation}
-
+
>
);
diff --git a/apps/nar-v3/src/components/DataFileCard.jsx b/apps/nar-v3/src/components/DataFileCard.jsx
index 5fe8f99..78c99e0 100644
--- a/apps/nar-v3/src/components/DataFileCard.jsx
+++ b/apps/nar-v3/src/components/DataFileCard.jsx
@@ -21,33 +21,35 @@ import Paper from "@mui/material/Paper";
import { formatQuant } from "../utility";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
function DataFileCard(props) {
const fileObj = props.fileObj;
+ const data = {
+ "Data type": fileObj.dataType ? fileObj.dataType.name : "unknown",
+ Format: fileObj.format ? fileObj.format.name : "unknown",
+ Hash: (
+ <>
+ {fileObj.hash.map((item) => (
+
+ {item.algorithm}: {item.digest}
+
+ ))}
+ >
+ ),
+ Size: formatQuant(fileObj.storageSize),
+ };
+
if (fileObj) {
return (
<>
File {fileObj.name}
-
- - Data type
- - {fileObj.dataType ? fileObj.dataType.name : "unknown"}
- - Format
- - {fileObj.format ? fileObj.format.name : "unknown"}
- - Hash
- -
- {fileObj.hash.map((item) => (
-
- {item.algorithm}: {item.digest}
-
- ))}
-
- - Size
- - {formatQuant(fileObj.storageSize)}
-
+
+
>
);
diff --git a/apps/nar-v3/src/components/KeyValueTable.jsx b/apps/nar-v3/src/components/KeyValueTable.jsx
new file mode 100644
index 0000000..e7d6415
--- /dev/null
+++ b/apps/nar-v3/src/components/KeyValueTable.jsx
@@ -0,0 +1,42 @@
+import { isValidElement } from "react";
+import { Table, TableBody, TableRow, TableCell } from "@mui/material";
+
+function KeyValueTable(props) {
+ let formatKey = (key) => {
+ return key;
+ };
+ if (props.boldKeys) {
+ formatKey = (key) => {
+ return {key};
+ };
+ }
+
+ let rows = [];
+ if (props.data) {
+ for (const [key, value] of Object.entries(props.data)) {
+ let valueStr = value;
+ if (!isValidElement(value)) {
+ // allow passing JSX as values
+ valueStr = String(value);
+ if (Array.isArray(value)) {
+ valueStr = value.join(", ");
+ }
+ }
+
+ rows.push(
+
+ {formatKey(key)}
+ {valueStr}
+
+ );
+ }
+ }
+
+ return (
+
+ );
+}
+
+export default KeyValueTable;
diff --git a/apps/nar-v3/src/components/PatchedCellCard.jsx b/apps/nar-v3/src/components/PatchedCellCard.jsx
index f6634dc..4fb75c3 100644
--- a/apps/nar-v3/src/components/PatchedCellCard.jsx
+++ b/apps/nar-v3/src/components/PatchedCellCard.jsx
@@ -20,6 +20,7 @@ import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
function PatchedCellCard(props) {
@@ -27,15 +28,15 @@ function PatchedCellCard(props) {
const cell = props.cell.cell;
if (cell) {
+ const data = {
+ Location: cell.anatomicalLocation.map((item) => item.name).join(", "),
+ };
return (
<>
Patched cell #{cell.internalIdentifier}
-
- - Location
- - {cell.anatomicalLocation.map((item) => item.name).join(", ")}
-
+
>
);
diff --git a/apps/nar-v3/src/components/RecordingCard.jsx b/apps/nar-v3/src/components/RecordingCard.jsx
index 4beef45..9c50a38 100644
--- a/apps/nar-v3/src/components/RecordingCard.jsx
+++ b/apps/nar-v3/src/components/RecordingCard.jsx
@@ -17,11 +17,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import { Fragment } from "react";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
import { formatQuant, formatUnits } from "../utility";
@@ -30,6 +30,26 @@ function RecordingCard(props) {
const stimulation = props.stimulation;
if (recording) {
+ const recordingData = {
+ Description: recording.description,
+ "Additional remarks": recording.device.metadata.additionalRemarks,
+ "Sampling frequency": formatQuant(recording.device.metadata.samplingFrequency),
+ Channels: (
+
+ {recording.device.metadata.channel.map((item) => (
+ -
+ {item.internalIdentifier} ({formatUnits(item.unit)})
+
+ ))}
+
+ ),
+ };
+ const stimulationData = {
+ Type: "Current injection",
+ Description: stimulation.stimulus[0].lookupLabel,
+ "Epoch duration": formatQuant(stimulation.stimulus[0].epoch),
+ Identifier: stimulation.stimulus[0].internalIdentifier,
+ };
const stimulusSpec = JSON.parse(stimulation.stimulus[0].specification.configuration);
return (
@@ -38,46 +58,14 @@ function RecordingCard(props) {
Recording
{recording.label}
-
- - Description
- - {recording.description}
- - Additional remarks
- - {recording.device.metadata.additionalRemarks}
- - Sampling frequency
- - {formatQuant(recording.device.metadata.samplingFrequency)}
- - Channels
- -
-
- {recording.device.metadata.channel.map((item) => (
- -
- {item.internalIdentifier} ({formatUnits(item.unit)})
-
- ))}
-
-
-
+
Stimulation
{stimulation.label}
-
- - Type
- - Current injection
- - Description
- - {stimulation.stimulus[0].lookupLabel}
- - Epoch duration
- - {formatQuant(stimulation.stimulus[0].epoch)}
- - Identifier
- - {stimulation.stimulus[0].internalIdentifier}
-
+
+
Specification
-
- {Object.entries(stimulusSpec).map((item, index) => (
-
- - {item[0]}
- - {item[1]}
-
- ))}
-
+
>
);
diff --git a/apps/nar-v3/src/components/SliceCard.jsx b/apps/nar-v3/src/components/SliceCard.jsx
index 1ef2375..49e2e87 100644
--- a/apps/nar-v3/src/components/SliceCard.jsx
+++ b/apps/nar-v3/src/components/SliceCard.jsx
@@ -21,6 +21,7 @@ import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import { NavigateNext, NavigatePrevious } from "./Navigation";
import styles from "../styles";
@@ -29,6 +30,11 @@ function SliceCard(props) {
const slice = props.slices[props.index].slice;
if (slice) {
+ const data = {
+ "Location (todo: add link outs)": slice.anatomicalLocation
+ .map((item) => item.name)
+ .join(", "),
+ };
return (
<>
@@ -45,10 +51,7 @@ function SliceCard(props) {
({props.index + 1} of {props.slices.length})
-
- - Location (todo: add link outs)
- - {slice.anatomicalLocation.map((item) => item.name).join(", ")}
-
+
{props.index < props.slices.length - 1 ? (
diff --git a/apps/nar-v3/src/components/SlicePreparationCard.jsx b/apps/nar-v3/src/components/SlicePreparationCard.jsx
index 44f8c86..5a19cfb 100644
--- a/apps/nar-v3/src/components/SlicePreparationCard.jsx
+++ b/apps/nar-v3/src/components/SlicePreparationCard.jsx
@@ -22,39 +22,32 @@ import Paper from "@mui/material/Paper";
import { formatQuant } from "../utility";
import Connection from "./Connection";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
function SlicePreparationCard(props) {
const activity = props.activity;
if (activity) {
+ const data = {
+ "Device name": activity.device[0].device.name,
+ "Device type": activity.device[0].device.deviceType,
+ Manufacturer:
+ activity.device[0].device.manufacturer.fullName ||
+ activity.device[0].device.manufacturer.shortName,
+ "Slice thickness": formatQuant(activity.device[0].sliceThickness),
+ "Slicing plane": activity.device[0].slicingPlane,
+ "Study targets": activity.studyTarget.join(", "),
+ Temperature: formatQuant(activity.temperature),
+ "Dissecting solution (full details to come)": activity.tissueBathSolution.name,
+ };
return (
<>
Slice preparation
{activity.label}
-
- - Device name
- - {activity.device[0].device.name}
- - Device type
- - {activity.device[0].device.deviceType}
- - Manufacturer
- -
- {activity.device[0].device.manufacturer.fullName ||
- activity.device[0].device.manufacturer.shortName}
-
- - Slice thickness
- - {formatQuant(activity.device[0].sliceThickness)}
- - Slicing plane
- - {activity.device[0].slicingPlane}
- - Study targets
- - {activity.studyTarget.join(", ")}
- - Temperature
- - {formatQuant(activity.temperature)}
- - Dissecting solution (full details to come)
- - {activity.tissueBathSolution.name}
-
+
>
);
diff --git a/apps/nar-v3/src/components/SubjectCard.jsx b/apps/nar-v3/src/components/SubjectCard.jsx
index 6b247d8..e9a676b 100644
--- a/apps/nar-v3/src/components/SubjectCard.jsx
+++ b/apps/nar-v3/src/components/SubjectCard.jsx
@@ -22,6 +22,7 @@ import Stack from "@mui/material/Stack";
import { formatUnits } from "../utility";
import { NavigateNext, NavigatePrevious } from "./Navigation";
+import KeyValueTable from "./KeyValueTable";
import styles from "../styles";
function AgeDisplay(props) {
@@ -60,6 +61,20 @@ function SubjectCard(props) {
}
}
+ const data = {
+ Species: species,
+ Strain: strain,
+ Age: ,
+ "Age category": subject.studiedState[0].ageCategory,
+ Pathologies:
+ subject.studiedState[0].pathology.length > 0
+ ? subject.studiedState[0].pathology[0].name
+ : "none",
+ };
+ if (!strain) {
+ delete data.Strain;
+ }
+
return (
@@ -75,30 +90,7 @@ function SubjectCard(props) {
({props.index + 1} of {props.subjects.length})
{/* todo: add subject group information */}
-
- - Species
- - {species}
- {strain ? (
- <>
- - Strain
- - {strain}
- >
- ) : (
- ""
- )}
- - Age
- -
-
-
- - Age category
- - {subject.studiedState[0].ageCategory}
- - Pathologies
- -
- {subject.studiedState[0].pathology.length > 0
- ? subject.studiedState[0].pathology[0].name
- : "none"}
-
-
+
{props.index < props.subjects.length - 1 ? (