Merge branch 'feat/v2-main' into dannyrb/ohif-154/restore-command-functionality-for-toolbar

This commit is contained in:
Danny Brown authored and GitHub committed 2020-06-26 14:26:35 -04:00
commit 1931d45450
45 files changed
+1055 -197

No files matched your search

+19 -16
View File
@@ -1,12 +1,13 @@
// External
import React from 'react';
import PropTypes from 'prop-types';
import i18n from '@ohif/i18n';
import { I18nextProvider } from 'react-i18next';
import { BrowserRouter, HashRouter } from 'react-router-dom';
import {
DialogProvider,
Modal,
ModalProvider,
Notification,
SnackbarProvider,
ThemeWrapper,
ViewportDialogProvider,
@@ -59,21 +60,23 @@ function App({ config, defaultExtensions }) {
return (
<AppConfigProvider value={appConfigState}>
<Router basename={routerBasename}>
<ThemeWrapper>
<ViewportGridProvider service={ViewportGridService}>
<ViewportDialogProvider service={UIViewportDialogService}>
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={Modal} service={UIModalService}>
{appRoutes}
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</ViewportDialogProvider>
</ViewportGridProvider>
</ThemeWrapper>
</Router>
<I18nextProvider i18n={i18n}>
<Router basename={routerBasename}>
<ThemeWrapper>
<ViewportGridProvider service={ViewportGridService}>
<ViewportDialogProvider service={UIViewportDialogService}>
<SnackbarProvider service={UINotificationService}>
<DialogProvider service={UIDialogService}>
<ModalProvider modal={Modal} service={UIModalService}>
{appRoutes}
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</ViewportDialogProvider>
</ViewportGridProvider>
</ThemeWrapper>
</Router>
</I18nextProvider>
</AppConfigProvider>
);
}
@@ -0,0 +1,57 @@
import React from 'react';
import { Dropdown, IconButton, Icon, useModal } from '@ohif/ui';
const PreferencesDropdown = () => {
const { show } = useModal();
const showAboutModal = () => {
const modalComponent = () => <div>About modal</div>;
show({
content: modalComponent,
title: 'About',
});
};
const showPreferencesModal = () => {
const modalComponent = () => <div>Preferences modal</div>;
show({
content: modalComponent,
title: 'Preferences',
});
};
return (
<Dropdown
showDropdownIcon={false}
list={[
{ title: 'About', icon: 'info', onClick: showAboutModal },
{
title: 'Preferences',
icon: 'settings',
onClick: showPreferencesModal,
},
]}
>
<IconButton
variant="text"
color="inherit"
size="initial"
className="text-primary-active"
>
<Icon name="settings" />
</IconButton>
<IconButton
variant="text"
color="inherit"
size="initial"
className="text-primary-active"
onClick={() => {}}
>
<Icon name="chevron-down" />
</IconButton>
</Dropdown>
);
};
export default PreferencesDropdown;
@@ -0,0 +1 @@
export { default } from './PreferencesDropdown';
@@ -1,10 +1,12 @@
/**
* CSS Grid Reference: http://grid.malven.co/
*/
import React from 'react';
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
import EmptyViewport from './EmptyViewport';
import { classes } from '@ohif/core';
const { ImageSet } = classes;
function ViewerViewportGrid(props) {
const { servicesManager, viewportComponents, dataSource } = props;
@@ -20,6 +22,29 @@ function ViewerViewportGrid(props) {
// TODO -> Need some way of selecting which displaySets hit the viewports.
const { DisplaySetService } = servicesManager.services;
useEffect(() => {
const { unsubscribe } = DisplaySetService.subscribe(
DisplaySetService.EVENTS.DISPLAY_SETS_CHANGED,
displaySets => {
displaySets.sort((a, b) => {
const isImageSet = x => x instanceof ImageSet;
return (isImageSet(a) === isImageSet(b)) ? 0 : isImageSet(a) ? -1 : 1;
});
dispatch({
type: 'SET_DISPLAYSET_FOR_VIEWPORT',
payload: {
viewportIndex: 0,
displaySetInstanceUID: displaySets[0].displaySetInstanceUID,
},
});
},
);
return () => {
unsubscribe();
};
}, []);
// TODO -> Make a HangingProtocolService
const HangingProtocolService = displaySets => {
let displaySetInstanceUID;
@@ -46,14 +46,17 @@ function DataSourceWrapper(props) {
// studies.processResults --> <LayoutTemplate studies={} />
// But only for LayoutTemplate type of 'list'?
// Or no data fetching here, and just hand down my source
const [data, setData] = useState();
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
// 204: no content
async function getData() {
setIsLoading(true);
const searchResults = await dataSource.query.studies.search(
queryFilterValues
);
setData(searchResults);
setIsLoading(false);
}
try {
@@ -61,23 +64,19 @@ function DataSourceWrapper(props) {
} catch (ex) {
console.warn(ex);
}
console.log('DataSourceWrapper: useEffect');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [history.location.search]);
// queryFilterValues
// TODO: Better way to pass DataSource?
return (
<React.Fragment>
{data && (
<LayoutTemplate
{...rest}
history={history}
data={data}
dataSource={dataSource}
/>
)}
</React.Fragment>
<LayoutTemplate
{...rest}
history={history}
data={data}
dataSource={dataSource}
isLoadingData={isLoading}
/>
);
}
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { Suspense, useState, useEffect } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
@@ -9,13 +9,14 @@ import filtersMeta from './filtersMeta.js';
import { useAppConfig } from '@state';
import { useDebounce, useQuery } from '@hooks';
import PreferencesDropdown from '../../components/PreferencesDropdown';
import {
Icon,
StudyListExpandedRow,
Button,
NavBar,
Svg,
IconButton,
EmptyStudies,
StudyListTable,
StudyListPagination,
@@ -28,15 +29,16 @@ const seriesInStudiesMap = new Map();
* TODO:
* - debounce `setFilterValues` (150ms?)
*/
function WorkList({ history, data: studies, dataSource }) {
function WorkList({ history, data: studies, isLoadingData, dataSource }) {
// ~ Modes
const [appConfig] = useAppConfig();
// ~ Filters
const query = useQuery();
const queryFilterValues = _getQueryFilterValues(query);
const [filterValues, _setFilterValues] = useState(
Object.assign({}, defaultFilterValues, queryFilterValues)
);
const [filterValues, _setFilterValues] = useState({
...defaultFilterValues,
...queryFilterValues,
});
const debouncedFilterValues = useDebounce(filterValues, 200);
const { resultsPerPage, pageNumber, sortBy, sortDirection } = filterValues;
@@ -80,6 +82,7 @@ function WorkList({ history, data: studies, dataSource }) {
return 0;
});
// ~ Rows & Studies
const [expandedRows, setExpandedRows] = useState([]);
const [studiesWithSeriesData, setStudiesWithSeriesData] = useState([]);
@@ -190,6 +193,7 @@ function WorkList({ history, data: studies, dataSource }) {
return filterValues[name] !== defaultFilterValues[name];
});
};
const tableDataSource = sortedStudies.map((study, key) => {
const rowKey = key + 1;
const isExpanded = expandedRows.some(k => k === rowKey);
@@ -364,17 +368,7 @@ function WorkList({ history, data: studies, dataSource }) {
<span className="mr-3 text-lg text-common-light">
FOR INVESTIGATIONAL USE ONLY
</span>
<IconButton
variant="text"
color="inherit"
className="text-primary-active"
onClick={() => {}}
>
<React.Fragment>
<Icon name="settings" />
<Icon name="chevron-down" />
</React.Fragment>
</IconButton>
<PreferencesDropdown />
</div>
</NavBar>
<StudyListFilter
@@ -404,7 +398,7 @@ function WorkList({ history, data: studies, dataSource }) {
</>
) : (
<div className="flex flex-col items-center justify-center pt-48">
<EmptyStudies />
<EmptyStudies isLoading={isLoadingData} />
</div>
)}
</div>