From cf359651fe606e37c21be6e009df6a8efcc0cefe Mon Sep 17 00:00:00 2001 From: Ramu Nerella Date: Mon, 10 Oct 2022 10:09:26 -0700 Subject: [PATCH 1/8] updated dicom viewer icon --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 64 ++++++++++++------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index 70df1fa9a8..50d8e81814 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -65,7 +65,7 @@ class ExplorerTable extends React.Component { */ buildColumnConfig = (field, isNestedTableColumn, isDetailedColumn) => { const fieldMappingEntry = this.props.guppyConfig.fieldMapping - && this.props.guppyConfig.fieldMapping.find((i) => i.field === field); + && this.props.guppyConfig.fieldMapping.find((i) => i.field === field); const overrideName = fieldMappingEntry ? fieldMappingEntry.name : undefined; const fieldStringsArray = field.split('.'); // for nested table, we only display the children names in column header @@ -132,7 +132,25 @@ class ExplorerTable extends React.Component { if (this.props.tableConfig.dicomViewerId && this.props.tableConfig.dicomViewerId === field && valueStr) { const dicomViewerLink = `${hostname}dicom-viewer/viewer/${valueStr}`; if (this.props.tableConfig.linkFields.includes(field)) { // link button - valueStr = dicomViewerLink; + //valueStr = dicomViewerLink; + const dicomServerLink = `${hostname}dicom-server/dicom-web/studies/${valueStr}/series`; + async function fetchDicomViewer() { + const res = await fetch(dicomServerLink, { + method: 'GET' + }); + return res.headers.get("content-length"); + } + //let len = fetchDicomViewer(); + async function getData() { + let len = await fetchDicomViewer(); + if (len === "22") { + + return null; + } else { + return dicomViewerLink; + } + } + getData().then((data) => valueStr = data); } else { // direct link return (
{valueStr}
); } @@ -140,27 +158,27 @@ class ExplorerTable extends React.Component { // handling some special field types switch (field) { - case this.props.guppyConfig.downloadAccessor: - return (
{valueStr}
); - case 'file_size': - return (
{humanFileSize(valueStr)}
); - case this.props.tableConfig.linkFields.includes(field) && field: - return valueStr - ? ( - - ) - : null; - default: - return (
{valueStr}
); + case this.props.guppyConfig.downloadAccessor: + return (
{valueStr}
); + case 'file_size': + return (
{humanFileSize(valueStr)}
); + case this.props.tableConfig.linkFields.includes(field) && field: + return valueStr + ? ( + + ) + : null; + default: + return (
{valueStr}
); } }, }; From 7b0531d1396a590ebad92923cbb83191788ef5e6 Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Wed, 16 Nov 2022 17:01:40 -0600 Subject: [PATCH 2/8] add promise to fetch data --- src/GuppyDataExplorer/ExplorerVisualization/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GuppyDataExplorer/ExplorerVisualization/index.jsx b/src/GuppyDataExplorer/ExplorerVisualization/index.jsx index ed38a6bf0b..c749b5740e 100644 --- a/src/GuppyDataExplorer/ExplorerVisualization/index.jsx +++ b/src/GuppyDataExplorer/ExplorerVisualization/index.jsx @@ -231,6 +231,7 @@ class ExplorerVisualization extends React.Component { ) } + {console.log('ExplorerTable', this.props)} { this.props.tableConfig.enabled && ( Date: Thu, 17 Nov 2022 17:52:09 -0600 Subject: [PATCH 3/8] add tableData date to ExplorerTable for dicom images --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 104 ++++++++++-------- .../ExplorerVisualization/index.jsx | 6 +- 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index 50d8e81814..ab5d4ac423 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, ReactNode } from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; import pluralize from 'pluralize'; @@ -21,6 +21,7 @@ class ExplorerTable extends React.Component { pageSize: props.defaultPageSize, currentPage: 0, showEmptyColumns: false, + tableData: this.props.rawData, }; } @@ -56,7 +57,7 @@ class ExplorerTable extends React.Component { /** * Build column configs for each table according to their locations and fields - * @param field: the full field name, if it is a nested field, it would contains at least 1 '.' + * @param field: the full field name, if it is a nested field, it would contain at least 1 '.' * @param isNestedTableColumn: control flag to determine if it is building column config for * the root table or inner nested tables * @param isDetailedColumn: control flag to determine if it is building column config for inner @@ -130,27 +131,12 @@ class ExplorerTable extends React.Component { // if this field is the `dicomViewerId`, convert the value to a link to the DICOM viewer if (this.props.tableConfig.dicomViewerId && this.props.tableConfig.dicomViewerId === field && valueStr) { - const dicomViewerLink = `${hostname}dicom-viewer/viewer/${valueStr}`; + let dicomViewerLink = `${hostname}dicom-viewer/viewer/${valueStr}`; + if (row.original.has_dicom_images !== undefined && !row.original.has_dicom_images) { + dicomViewerLink = undefined; + } if (this.props.tableConfig.linkFields.includes(field)) { // link button - //valueStr = dicomViewerLink; - const dicomServerLink = `${hostname}dicom-server/dicom-web/studies/${valueStr}/series`; - async function fetchDicomViewer() { - const res = await fetch(dicomServerLink, { - method: 'GET' - }); - return res.headers.get("content-length"); - } - //let len = fetchDicomViewer(); - async function getData() { - let len = await fetchDicomViewer(); - if (len === "22") { - - return null; - } else { - return dicomViewerLink; - } - } - getData().then((data) => valueStr = data); + valueStr = dicomViewerLink; } else { // direct link return (); } @@ -158,27 +144,27 @@ class ExplorerTable extends React.Component { // handling some special field types switch (field) { - case this.props.guppyConfig.downloadAccessor: - return (); - case 'file_size': - return (
{humanFileSize(valueStr)}
); - case this.props.tableConfig.linkFields.includes(field) && field: - return valueStr - ? ( - - ) - : null; - default: - return (
{valueStr}
); + case this.props.guppyConfig.downloadAccessor: + return (); + case 'file_size': + return (
{humanFileSize(valueStr)}
); + case this.props.tableConfig.linkFields.includes(field) && field: + return valueStr + ? ( + + ) + : null; + default: + return (
{valueStr}
); } }, }; @@ -266,10 +252,40 @@ class ExplorerTable extends React.Component { this.setState({ showEmptyColumns: checked }); }; + augmentData = () => { + const haveField = this.props.rawData.filter((x) => Object.keys(x).includes(this.props.tableConfig.dicomViewerId)); + if (haveField.length === this.props.rawData.length) { + this.setState({ loading: true }); + // eslint-disable-next-line array-callback-return + Promise.all(this.props.rawData.map((x) => { + const dicomServerLink = `${hostname}dicom-server/dicom-web/studies/${x[this.props.tableConfig.dicomViewerId]}/series`; + return fetch(dicomServerLink, { + method: 'GET', + }) + .then((resp) => ({ ...x, has_dicom_images: resp.headers.get('content-length') !== '22' }), + // Object.defineProperty(this.props.rawData[index], 'has_dicom_images', { + // value: resp.headers.get('content-length') !== '22', + // enumerable: true, + // }); + ); + })).then((x) => { + this.setState({ tableData: x }); + this.setState({ loading: false }); + }); + } + } + + componentDidUpdate(prevProps) { + if (this.props.tableConfig.dicomViewerId && this.props.rawData !== prevProps.rawData) { + this.augmentData(); + } else if (this.props.rawData !== prevProps.rawData) this.setState({ tableData: this.props.rawData }); + } + render() { if (!this.props.tableConfig.fields || this.props.tableConfig.fields.length === 0) { return null; } + // build column configs for root table first const rootColumnsConfig = this.props.tableConfig.fields.map((field) => { const tempColumnConfig = this.buildColumnConfig(field, false, false); @@ -386,7 +402,7 @@ class ExplorerTable extends React.Component { ) } - {console.log('ExplorerTable', this.props)} { this.props.tableConfig.enabled && ( Date: Thu, 17 Nov 2022 17:56:54 -0600 Subject: [PATCH 4/8] remove commented out code --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index ab5d4ac423..564da9731a 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -263,13 +263,9 @@ class ExplorerTable extends React.Component { method: 'GET', }) .then((resp) => ({ ...x, has_dicom_images: resp.headers.get('content-length') !== '22' }), - // Object.defineProperty(this.props.rawData[index], 'has_dicom_images', { - // value: resp.headers.get('content-length') !== '22', - // enumerable: true, - // }); ); - })).then((x) => { - this.setState({ tableData: x }); + })).then((data) => { + this.setState({ tableData: data }); this.setState({ loading: false }); }); } From 4b78c5525e487e618dd0d5cbb135904859a3e641 Mon Sep 17 00:00:00 2001 From: Craig Barnes Date: Tue, 22 Nov 2022 10:32:57 -0600 Subject: [PATCH 5/8] document augmentData and componentDidUpdate, change to use isEqual --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index 564da9731a..e05dfe6d91 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -1,6 +1,6 @@ import React, { useEffect, ReactNode } from 'react'; import PropTypes from 'prop-types'; -import _ from 'lodash'; +import _, { isEqual } from 'lodash'; import pluralize from 'pluralize'; import ReactTable from 'react-table'; import { Switch } from 'antd'; @@ -252,6 +252,10 @@ class ExplorerTable extends React.Component { this.setState({ showEmptyColumns: checked }); }; + /** + * processes the table data if this is a dicom table. This will determine if the table row + * has image data and will then esure that the lick icon is shown + */ augmentData = () => { const haveField = this.props.rawData.filter((x) => Object.keys(x).includes(this.props.tableConfig.dicomViewerId)); if (haveField.length === this.props.rawData.length) { @@ -271,8 +275,14 @@ class ExplorerTable extends React.Component { } } + /** + * Used to process the table data when needed. + * THis is used primarily to check for the existence + * of a Dicom images to show the link icon to the dicom viewer + * @param prevProps + */ componentDidUpdate(prevProps) { - if (this.props.tableConfig.dicomViewerId && this.props.rawData !== prevProps.rawData) { + if (this.props.tableConfig.dicomViewerId && !isEqual(this.props.rawData, prevProps.rawData)) { this.augmentData(); } else if (this.props.rawData !== prevProps.rawData) this.setState({ tableData: this.props.rawData }); } From f9c7426b66b7c9fed4aa4a6944ad30e1d14e583b Mon Sep 17 00:00:00 2001 From: Andrew Prokhorenkov Date: Thu, 15 Dec 2022 18:55:09 -0600 Subject: [PATCH 6/8] fix: consistency for the statement Co-authored-by: Mingfei Shao <2475897+mfshao@users.noreply.github.com> --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index e05dfe6d91..7ae62a8322 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -408,7 +408,7 @@ class ExplorerTable extends React.Component { Date: Thu, 15 Dec 2022 18:57:26 -0600 Subject: [PATCH 7/8] feat: addressing PR comments --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 2 +- src/GuppyDataExplorer/ExplorerVisualization/index.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index 7ae62a8322..5a5be42c35 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, ReactNode } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import _, { isEqual } from 'lodash'; import pluralize from 'pluralize'; diff --git a/src/GuppyDataExplorer/ExplorerVisualization/index.jsx b/src/GuppyDataExplorer/ExplorerVisualization/index.jsx index f2c07e1f57..9edcc5894a 100644 --- a/src/GuppyDataExplorer/ExplorerVisualization/index.jsx +++ b/src/GuppyDataExplorer/ExplorerVisualization/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import GuppyWrapper from '@gen3/guppy/dist/components/GuppyWrapper'; import ConnectedFilter from '@gen3/guppy/dist/components/ConnectedFilter'; @@ -8,7 +8,7 @@ import { components } from '../../params'; import { guppyUrl, tierAccessLevel, tierAccessLimit } from '../../localconf'; import DataSummaryCardGroup from '../../components/cards/DataSummaryCardGroup'; import ExplorerHeatMap from '../ExplorerHeatMap'; -import ExplorerTable, {DicomHasImageLinkObserver} from '../ExplorerTable'; +import ExplorerTable from '../ExplorerTable'; import ReduxExplorerButtonGroup from '../ExplorerButtonGroup/ReduxExplorerButtonGroup'; import { TableConfigType, From 252d41d4a07b46840c8e15ccdd934fa9d19484e0 Mon Sep 17 00:00:00 2001 From: Andrew Prokhorenkov Date: Thu, 15 Dec 2022 19:04:41 -0600 Subject: [PATCH 8/8] feat: addressing eslint comments, "getWidthForColumn" should be placed after "componentDidUpdate" --- src/GuppyDataExplorer/ExplorerTable/index.jsx | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/GuppyDataExplorer/ExplorerTable/index.jsx b/src/GuppyDataExplorer/ExplorerTable/index.jsx index 5a5be42c35..55d8692132 100644 --- a/src/GuppyDataExplorer/ExplorerTable/index.jsx +++ b/src/GuppyDataExplorer/ExplorerTable/index.jsx @@ -25,36 +25,6 @@ class ExplorerTable extends React.Component { }; } - getWidthForColumn = (field, columnName) => { - if (this.props.tableConfig.linkFields.includes(field)) { - return 80; - } - - // some magic numbers that work fine for table columns width - const minWidth = 100; - const maxWidth = 400; - const letterWidth = 8; - const spacing = 20; - if (!this.props.rawData || this.props.rawData.length === 0) { - return minWidth; - } - let maxLetterLen = columnName.length; - const fieldStringsArray = field.split('.'); - this.props.rawData.forEach((d) => { - if (d[fieldStringsArray[0]] === null || typeof d[fieldStringsArray[0]] === 'undefined') { - return; - } - // the calculation logic here is a bit wild if it is a nested array field - // it would convert the whole array to string and calculate - // which in most cases would exceed the maxWidth so just use maxWidth - const str = d[fieldStringsArray[0]].toString && d[fieldStringsArray[0]].toString(); - const len = str ? str.length : 0; - maxLetterLen = len > maxLetterLen ? len : maxLetterLen; - }); - const resWidth = Math.min((maxLetterLen * letterWidth) + spacing, maxWidth); - return resWidth; - } - /** * Build column configs for each table according to their locations and fields * @param field: the full field name, if it is a nested field, it would contain at least 1 '.' @@ -287,6 +257,36 @@ class ExplorerTable extends React.Component { } else if (this.props.rawData !== prevProps.rawData) this.setState({ tableData: this.props.rawData }); } + getWidthForColumn = (field, columnName) => { + if (this.props.tableConfig.linkFields.includes(field)) { + return 80; + } + + // some magic numbers that work fine for table columns width + const minWidth = 100; + const maxWidth = 400; + const letterWidth = 8; + const spacing = 20; + if (!this.props.rawData || this.props.rawData.length === 0) { + return minWidth; + } + let maxLetterLen = columnName.length; + const fieldStringsArray = field.split('.'); + this.props.rawData.forEach((d) => { + if (d[fieldStringsArray[0]] === null || typeof d[fieldStringsArray[0]] === 'undefined') { + return; + } + // the calculation logic here is a bit wild if it is a nested array field + // it would convert the whole array to string and calculate + // which in most cases would exceed the maxWidth so just use maxWidth + const str = d[fieldStringsArray[0]].toString && d[fieldStringsArray[0]].toString(); + const len = str ? str.length : 0; + maxLetterLen = len > maxLetterLen ? len : maxLetterLen; + }); + const resWidth = Math.min((maxLetterLen * letterWidth) + spacing, maxWidth); + return resWidth; + } + render() { if (!this.props.tableConfig.fields || this.props.tableConfig.fields.length === 0) { return null;