Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions src/Components/Catalog/DatasetDetailPage/DatasetDetailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Text on this page has inline styling for font color because ag-grid's theme classes override mui classes when a dialog is opened
// from inside the grid

import React, { useEffect } from 'react';
import React, { useEffect, useLayoutEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { Grid, Link, Typography, withStyles } from '@material-ui/core';
Expand All @@ -23,7 +23,7 @@ import NewsSection from './NewsSection';
import SectionHeader from './SectionHeader';
import SubscribeButton from '../../User/Subscriptions/SubscribeButton';
import { DownloadButtonOutlined } from '../DownloadDialog/DownloadButtons';
import styles from './datasetFullPageStyles';
import styles from './DatasetDetailPage.style';

import SkeletonWrapper from '../../UI/SkeletonWrapper';
import ErrorCard from '../../Common/ErrorCard';
Expand Down Expand Up @@ -174,6 +174,44 @@ const DatasetFullPage = (props) => {
};
}, [longName]);

// Scroll to the top of the description content when the page loads to hint at scrollability
// (macOS won't show scrollbar unless scrolling). Copied from Stories.js.
let [ref, setRef] = useState(null);
let [intervalId, setIntervalId] = useState(null);
useLayoutEffect(() => {
if (ref) {
const s = () =>
ref.scroll({
top: 1,
left: 0,
behavior: 'instant',
});
const id = setInterval(s, 100);
setIntervalId(id);
}
}, [ref]);

const handleScroll = () => {
if (ref) {
const pos = ref.scrollTop;
if (pos < 1) {
const scrollBack = () => {
if (ref) {
ref.scroll({
top: 1,
left: 0,
behavior: 'instant',
});
}
};
setTimeout(scrollBack, 200);
}
}
if (intervalId) {
clearInterval(intervalId);
}
};

if (failed) {
let details = `You requested to view "${props.match.params.dataset}".`;
return (
Expand Down Expand Up @@ -215,7 +253,11 @@ const DatasetFullPage = (props) => {
<div className={classes.horizontalFlex}>
<div className={classes.descriptionContainer}>
<SectionHeader title={'Description'} />
<div className={classes.descriptionContent}>
<div
className={classes.descriptionContent}
ref={setRef}
onScroll={handleScroll}
>
<ReactMarkdown
source={description}
className={classes.markdown}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const styles = (theme) => ({
textAlign: 'justify',
fontWeight: 400,
lineHeight: 1.5,
whiteSpace: 'pre-line',
},
},
downloadLink: {
Expand Down
95 changes: 43 additions & 52 deletions src/Components/Catalog/VariablesTable/CommentToolPanel.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,49 @@
import React, { useState, useEffect } from 'react';
import { withStyles } from '@material-ui/core';
// import { withStyles } from '@material-ui/core';
import { Close } from '@material-ui/icons';
import CheckBoxTwoToneIcon from '@material-ui/icons/CheckBoxTwoTone';
// import colors from '../../../enums/colors';
import { toolPanelStyles } from './gridStyles';
import copyTextToClipboard from '../../../Utility/Clipboard/copyTextToClipboard';
import dispatchCustomWindowEvent from '../../../Utility/Events/dispatchCustomWindowEvent';

export const VariableRowRender = withStyles(toolPanelStyles)(
React.memo(function BlobRenderFC({
comment,
longName,
classes,
handleVariableLink,
}) {
let handler = handleVariableLink || (() => {});

if (!comment) {
return '';
}
export const VariableRowRender = React.memo(function BlobRenderFC({
comment,
longName,
handleVariableLink,
}) {
const classes = toolPanelStyles();
let handler = handleVariableLink || (() => {});

return (
<div className={classes.vumListRow}>
<div className={classes.variableName}>
<div>
<a onClick={() => handler(longName)}>{longName || 'no name'}</a>
</div>
<div>
<div className={classes.longNameChip}>Variable</div>
</div>
if (!comment) {
return '';
}
return (
<div
style={classes.vumListRow}
data-testid="variable-comment-row"
id="variable-comment-row"
>
<div style={classes.variableName} data-testid="variable-name-container">
<div>
<a onClick={() => handler(longName)}>{longName || 'no name'}</a>
</div>
<div>
<div style={classes.longNameChip}>Variable</div>
</div>
{comment}
</div>
);
}),
);
<div style={{ marginTop: '10px' }}>{comment}</div>
</div>
);
});

export const ListRender = ({ rows, handleVariableLink }) => {
const classes = toolPanelStyles();

export const ListRender = withStyles(toolPanelStyles)(({
rows,
classes,
handleVariableLink,
}) => {
if (!rows) {
return '';
}

return (
<div className={classes.vumListContainer}>
<div className={classes.allCommentsLabel}>
<div style={classes.vumListContainer}>
<div style={classes.allCommentsLabel}>
Comments <span>({rows.length} matching variables with comments)</span>
</div>
{rows.map((r, i) => {
Expand All @@ -64,7 +60,7 @@ export const ListRender = withStyles(toolPanelStyles)(({
})}
</div>
);
});
};

const CommentList = ({ shouldDisplay }) => {
let [isLoaded, setIsLoaded] = useState(false);
Expand Down Expand Up @@ -113,8 +109,8 @@ const CommentList = ({ shouldDisplay }) => {
);
};

const SidebarCommentToolPanel = withStyles(toolPanelStyles)((props) => {
let { classes } = props;
const SidebarCommentToolPanel = () => {
const classes = toolPanelStyles();
let [focusedVariableData, setFocusedVariableData] = useState(null);
let [isFocusView, setIsFocusView] = useState(false);

Expand Down Expand Up @@ -173,22 +169,17 @@ const SidebarCommentToolPanel = withStyles(toolPanelStyles)((props) => {
// if render comment, render single comment from event payload
// else render all comments
return (
<div className={classes.toolPanelContainer}>
<div className={classes.title}>
<div>
<span>Comment Tool Panel</span>
</div>
<div onClick={handleExit} className={classes.toolBarClose}>
<span>Exit Tool Panel</span>
<Close />
</div>
<div style={classes.toolPanelContainer}>
<div onClick={handleExit} style={classes.toolBarClose}>
<Close />
</div>
<div style={classes.title}>Comment Tool Panel</div>

{isFocusView && focusedVariableData && (
<div>
<div className={classes.variableFocusLabelContainer}>
<div className={classes.variableLabel}>{/* removed */}</div>
<div onClick={handleClose} className={classes.closeBox}>
<div style={classes.variableFocusLabelContainer}>
<div style={classes.variableLabel}>{/* removed */}</div>
<div onClick={handleClose} style={classes.closeBox}>
<span>Deselect Variable</span>
<Close />
</div>
Expand All @@ -202,6 +193,6 @@ const SidebarCommentToolPanel = withStyles(toolPanelStyles)((props) => {
<CommentList shouldDisplay={!isFocusView} />
</div>
);
});
};

export default SidebarCommentToolPanel;
138 changes: 65 additions & 73 deletions src/Components/Catalog/VariablesTable/DatasetPageAGGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,11 @@ const DatasetPageAGGrid = (props) => {
// The default label if `labelKey` is missing or does not map to valid text through localisation.
labelDefault: 'Additional Variable Metadata',
// The min width of the tool panel. Default: `100`
minWidth: 300,
minWidth: 225,
// The max width of the tool panel. Default: `undefined`
// maxWidth: number,
// The initial width of the tool panel. Default: `$side-bar-panel-width (theme variable)`
width: 500,
width: 225,
// The key of the icon to be used as a graphical aid beside the label in the side bar.
iconKey: 'grip',
// The tool panel component to use as the panel.
Expand All @@ -281,26 +281,17 @@ const DatasetPageAGGrid = (props) => {
// toolPanelParams?: any;
},
{
// The unique ID for this panel. Used in the API and elsewhere to refer to the panel.
id: 'comments',
// The key used for localisation for displaying the label. The label is displayed in the tab button.
labelKey: 'comments',
// The default label if `labelKey` is missing or does not map to valid text through localisation.
labelDefault: 'Comments',
// The min width of the tool panel. Default: `100`
minWidth: 300,
// The max width of the tool panel. Default: `undefined`
// maxWidth: number,
// The initial width of the tool panel. Default: `$side-bar-panel-width (theme variable)`
width: 500,
// The key of the icon to be used as a graphical aid beside the label in the side bar.
minWidth: 225,
width: 225,
iconKey: 'grip',
// The tool panel component to use as the panel.
// The provided panels use components `agColumnsToolPanel` and `agFiltersToolPanel`.
// To provide your own custom panel component, you reference it here.
toolPanelFramework: CommentToolPanel,
// Customise the parameters provided to the `toolPanel` component.
// toolPanelParams?: any;
toolPanelParams: {
currentFocus,
setCurrentFocus,
},
},
],
}}
Expand All @@ -321,67 +312,68 @@ const mapStateToProps = (state) => ({
metadata: state.datasetDetailsPage.unstructuredVariableMetadata,
});

const DatasetVariablesTableWithLoadingState = connect(mapStateToProps)((
props,
) => {
let { loadingState, metadataLoadingState, dataset, variables, metadata } =
props;
const DatasetVariablesTableWithLoadingState = connect(mapStateToProps)(
(props) => {
let { loadingState, metadataLoadingState, dataset, variables, metadata } =
props;

let eitherHasFailed = [loadingState, metadataLoadingState].some(
(s) => s === states.failed,
);
let eitherIsPending = [loadingState, metadataLoadingState].some(
(s) => s === states.inProgress,
);
let bothHaveSucceeded = [loadingState, metadataLoadingState].every(
(s) => s === states.succeeded,
);
let eitherHasFailed = [loadingState, metadataLoadingState].some(
(s) => s === states.failed,
);
let eitherIsPending = [loadingState, metadataLoadingState].some(
(s) => s === states.inProgress,
);
let bothHaveSucceeded = [loadingState, metadataLoadingState].every(
(s) => s === states.succeeded,
);

if (bothHaveSucceeded && dataset) {
let datasetStats = {
Time_Min: dataset.Time_Min,
Time_Max: dataset.Time_Max,
Lat_Min: dataset.Lat_Min,
Lat_Max: dataset.Lat_Max,
Lon_Min: dataset.Lon_Min,
Lon_Max: dataset.Lon_Max,
Depth_Min: dataset.Depth_Min,
Depth_Max: dataset.Depth_Max,
};
if (bothHaveSucceeded && dataset) {
let datasetStats = {
Time_Min: dataset.Time_Min,
Time_Max: dataset.Time_Max,
Lat_Min: dataset.Lat_Min,
Lat_Max: dataset.Lat_Max,
Lon_Min: dataset.Lon_Min,
Lon_Max: dataset.Lon_Max,
Depth_Min: dataset.Depth_Min,
Depth_Max: dataset.Depth_Max,
};

let ammendedVariables = variables.map((variable) => {
return Object.assign({}, variable, datasetStats, {
Unstructured_Variable_Metadata: metadata[variable.Variable] || null,
let ammendedVariables = variables.map((variable) => {
return Object.assign({}, variable, datasetStats, {
Unstructured_Variable_Metadata: metadata[variable.Variable] || null,
});
});
});

return <DatasetVariables variables={ammendedVariables} />;
} else if (eitherHasFailed) {
return (
<Typography>
Oops! There was an error loading the dataset variables.
</Typography>
);
} else if (eitherIsPending) {
return (
<div id="DatasetAGGrid">
<div
className={'ag-theme-material'}
style={{
height: '400px',
border: '1px solid black',
lineHeight: '400px',
}}
>
<div style={{ margin: '0 auto' }}>
<Spinner />

return <DatasetVariables variables={ammendedVariables} />;
} else if (eitherHasFailed) {
return (
<Typography>
Oops! There was an error loading the dataset variables.
</Typography>
);
} else if (eitherIsPending) {
return (
<div id="DatasetAGGrid">
<div
className={'ag-theme-material'}
style={{
height: '400px',
border: '1px solid black',
lineHeight: '400px',
}}
>
Doopie Doopie Doopie
<div style={{ margin: '0 auto' }}>
<Spinner />
</div>
</div>
</div>
</div>
);
} else {
return '';
}
});
);
} else {
return '';
}
},
);

export default DatasetVariablesTableWithLoadingState;
Loading