+ );
+};
+export default Loading;
diff --git a/src/lib/CohortBuilder/CustomCellRenderers.tsx b/src/lib/CohortBuilder/CustomCellRenderers.tsx
index 01e3c9b4..e7aee087 100644
--- a/src/lib/CohortBuilder/CustomCellRenderers.tsx
+++ b/src/lib/CohortBuilder/CustomCellRenderers.tsx
@@ -1,28 +1,127 @@
+import React, { ReactNode } from 'react';
import {
ExplorerTableCellRendererFactory,
type CellRendererFunctionProps,
} from '@gen3/frontend';
-import { ActionIcon } from '@mantine/core';
-import React from 'react';
+import { ActionIcon, Text, Tooltip } from '@mantine/core';
import { FaExternalLinkAlt } from 'react-icons/fa';
-
-const RenderDiacomLink = ({ cell }: CellRendererFunctionProps) => {
- if (cell.getValue() === undefined || cell.getValue() === '') {
+const RenderDicomLink = ({ cell }: CellRendererFunctionProps) => {
+ if (!cell?.getValue() || cell?.getValue() === '') {
return ;
} else
return (
-
-
-
-
-
+
+
+
+
+
);
};
+const JoinFields = (
+ { cell, row }: CellRendererFunctionProps,
+ ...args: Array>
+) => {
+ if (!cell?.getValue() || cell?.getValue() === '') {
+ return ;
+ } else {
+ if (
+ typeof args[0] === 'object' &&
+ Object.keys(args[0]).includes('otherFields')
+ ) {
+ const otherFields = args[0].otherFields as Array;
+ const labels = otherFields.map((field) => {
+ return row.getValue(field);
+ });
+ return {labels.join(' ')};
+ }
+ }
+ return Not configured;
+};
+
+const RenderLinkCell = ({ cell }: CellRendererFunctionProps) => {
+ return (
+
+
+ {' '}
+ {cell.getValue() as ReactNode}{' '}
+
+
+ );
+};
+
+interface LinkCellOptions {
+ icon: string;
+ color: string;
+ variant: string;
+ size: string;
+ tooltip: boolean;
+}
+
+const RenderLinkIconDefaultParameters : LinkCellOptions = {
+ icon: 'gen3:external-link', // TODO
+ color: 'accent.5',
+ variant: 'filled',
+ size: 'md',
+ tooltip: false,
+}
+
+/**
+ * RenderLinkWithIcon is a functional component that renders a hyperlink with an associated icon inside a tooltip.
+ *
+ * This component primarily checks if a value exists in the `cell` object provided as a property. If there is no
+ * value or the value is an empty string, it returns an empty span. Otherwise, a link is rendered with customizable
+ * icon appearance and tooltip functionality.
+ *
+ * Parameters for styling and behavior can be passed through `params`, which override the default configurations.
+ *
+ * @param {Object} props - The component props.
+ * @param {CellRendererFunctionProps} props.cell - Contains the value for the hyperlink.
+ * @param {...Array>} params - Additional configuration parameters for the rendered link and its icon. Defaults are defined in `RenderLinkIconDefaultParameters`.
+ * @returns {React.ReactNode} A React element representing a tooltip-wrapped link with an icon, or an empty span if no value is present in `cell`.
+ */
+const RenderLinkWithIcon = ({ cell }: CellRendererFunctionProps,
+ ...params: Array>) => {
+ if (!cell?.getValue() || cell?.getValue() === '') {
+ return ;
+ } else {
+ const mergedParams = { ...RenderLinkIconDefaultParameters, ...(params ? params[0] : {}) };
+ const { variant, color, size, tooltip } = mergedParams;
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+};
+
+
export const registerCohortTableCustomCellRenderers = () => {
ExplorerTableCellRendererFactory().registerRenderer(
- 'link', 'DiacomLink' ,
- RenderDiacomLink,
+ 'link',
+ 'DicomLink',
+ RenderDicomLink,
+ );
+ ExplorerTableCellRendererFactory().registerRenderer(
+ 'string',
+ 'JoinFields',
+ JoinFields,
+ );
+ ExplorerTableCellRendererFactory().registerRenderer(
+ 'link',
+ 'linkURL',
+ RenderLinkCell,
+ );
+ ExplorerTableCellRendererFactory().registerRenderer(
+ 'link',
+ 'linkWithIconAndTooltip',
+ RenderLinkWithIcon,
);
};
diff --git a/src/lib/CohortBuilder/FileDetailsPanel.tsx b/src/lib/CohortBuilder/FileDetailsPanel.tsx
new file mode 100644
index 00000000..ddc4ccc1
--- /dev/null
+++ b/src/lib/CohortBuilder/FileDetailsPanel.tsx
@@ -0,0 +1,171 @@
+import React from 'react';
+import {
+ Anchor,
+ Group,
+ LoadingOverlay,
+ Stack,
+ Table,
+ Text,
+ CopyButton,
+ ActionIcon,
+ Tooltip,
+ Button,
+} from '@mantine/core';
+import { useGeneralGQLQuery, GEN3_FENCE_API } from '@gen3/core';
+import {
+ ErrorCard,
+ type TableDetailsPanelProps,
+ ExplorerTableDetailsPanelFactory,
+} from '@gen3/frontend';
+import {
+ MdContentCopy as IconCopy,
+ MdCheck as IconCheck,
+} from 'react-icons/md';
+
+// a definition of the query response
+interface QueryResponse {
+ data?: Record>;
+}
+
+/**
+ * Checks if the given object is a QueryResponse.
+ *
+ * @param {any} obj - The object to be checked.
+ * @returns {boolean} Returns true if the object is a QueryResponse, false otherwise.
+ */
+const isQueryResponse = (obj: any): obj is QueryResponse => {
+ // Considering that the data property can be optional
+ return (
+ typeof obj === 'object' &&
+ (obj.data === undefined || typeof obj.data === 'object')
+ );
+};
+
+/**
+ * Extracts data from a QueryResponse object based on an index.
+ *
+ * @param {QueryResponse} data - The QueryResponse object containing the data.
+ * @param {string} index - The index to extract the data from.
+ * @returns {Record} - The extracted data as a key-value pair object.
+ */
+const extractData = (
+ data: QueryResponse,
+ index: string,
+): Record => {
+ if (data === undefined || data === null) return {};
+ if (data.data === undefined || data.data === null) return {};
+
+ return Array.isArray(data.data[index]) && data.data[index].length > 0
+ ? data.data[index][0]
+ : {};
+};
+
+export const FileDetailsPanel = ({
+ id,
+ index,
+ tableConfig,
+ onClose,
+}: TableDetailsPanelProps) => {
+ // get the idField from the configuration
+ const idField = tableConfig.detailsConfig?.idField;
+ // call the general Guppy GQL which takes an object { query: string, variables: object }
+ const { data, isLoading, isError } = useGeneralGQLQuery({
+ query: `query ($filter: JSON) {
+ ${index} (filter: $filter, accessibility: all) {
+ ${tableConfig.fields}
+ }
+ }`,
+ variables: {
+ filter: {
+ AND: [
+ {
+ IN: {
+ [idField ?? 0]: [id],
+ },
+ },
+ ],
+ },
+ },
+ });
+
+ // handle misconfiguration
+ if (!idField) {
+ return (
+
+ );
+ }
+ // show data error if graphql fails
+ if (isError) {
+ return ;
+ }
+
+ // process guppy response
+ const queryData = isQueryResponse(data) ? extractData(data, index) : {};
+
+ // create the rows for the table
+ const rows = Object.entries(queryData).map(([field, value]) => (
+
+
+ {field}
+
+
+ {/*
+ if field is one that we want a link for make it an Anchor otherwise
+ render as text.
+ */}
+ {field === 'object_id' ? (
+
+ {value ? (value as string) : ''}
+
+ ) : (
+ {value ? (value as string) : ''}
+ )}
+
+
+ ));
+ return (
+
+
+ Results for {id}
+
+
+
+
Field
+
Value
+
+
+ {rows}
+
+
+
+ {({ copied, copy }) => (
+
+
+ {copied ? : }
+
+
+ )}
+
+
+
+
+ );
+};
+
+export const registerCustomExplorerDetailsPanels = () => {
+ ExplorerTableDetailsPanelFactory().registerRendererCatalog({
+ // NOTE: The catalog name must be tableDetails
+ tableDetails: { fileDetails: FileDetailsPanel }, // TODO: add simpler registration function that ensures the catalog name is tableDetails
+ });
+};
diff --git a/src/lib/Discovery/CustomCellRenderers.tsx b/src/lib/Discovery/CustomCellRenderers.tsx
index 312297da..4a302248 100644
--- a/src/lib/Discovery/CustomCellRenderers.tsx
+++ b/src/lib/Discovery/CustomCellRenderers.tsx
@@ -11,55 +11,56 @@ import {
import { isArray } from 'lodash';
import { JSONObject } from '@gen3/core';
import { toString } from 'lodash';
+import { FilemapPopup, FilemapInline } from '@/lib/Discovery/Filemap';
/**
- * Custom cell renderer for the linked study column
+ * Custom cell renderer for the linked study column for HEAL
* @param cell
*/
export const LinkedStudyCell = ({
- value: cellValue,
- }: CellRenderFunctionProps) => {
+ value: cellValue,
+}: CellRenderFunctionProps) => {
const value = cellValue as boolean;
return value ? (
- }
- color="green"
- >
- Linked
-
+ }
+ color="green"
+ >
+ Linked
+
) : (
- } color="primary">
- Not Linked
-
+ } color="primary">
+ Not Linked
+
);
};
const WrappedStringCell = (
- { value }: CellRenderFunctionProps,
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- params?: JSONObject,
+ { value }: CellRenderFunctionProps,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ params?: JSONObject,
) => {
if (value === undefined || value === null || toString(value) === '') {
return (
-
- {`${
- params && params?.valueIfNotAvailable
- ? params?.valueIfNotAvailable
- : ''
- }`}{' '}
-
+
+ {`${
+ params && params?.valueIfNotAvailable
+ ? params?.valueIfNotAvailable
+ : ''
+ }`}{' '}
+
);
}
const content = value as string | string[];
return (
-
-
- This is a example custom page in Gen3
-
- You can add your own content here, and add a link to this page in
- the navigation bar by editing the config file in{' '}
- COMMONSNAME/navigation.json
-
-
+
+
+
+
+ This is a example custom page in Gen3
+
+ You can add your own content here, and add a link to this page in
+ the navigation bar by editing the config file in navigation.json
+
+
+