feat: New @ohif/viewer project structure + routes (#1674)
* fix pagination size * clean up, start a very basic route configuration * quick navigation between routes * configure webpack to read .env variables * Move container components to Routes directory * Fix naming of recipe file * Clean up source folder * update yarn.lock * ci: update netlify deploy preview to build viewer project * update PWA entrypoint to pass configuration on window to App as props * fix: for missing key * Pass routerBasename to our React Router component * Simplify config for meow Co-authored-by: dannyrb <danny.ri.brown@gmail.com>
This commit is contained in:
1 parent
9a8bede80e
commit
01b314522d
116 files changed
+22080
-4971
No files matched your search
@@ -1,104 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { CineDialog } from '@ohif/ui';
|
||||
import OHIF from '@ohif/core';
|
||||
import csTools from 'cornerstone-tools';
|
||||
import { commandsManager } from './../App.js';
|
||||
// Our target output kills the `as` and "import" throws a keyword error
|
||||
// import { import as toolImport, getToolState } from 'cornerstone-tools';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
|
||||
const toolImport = csTools.import;
|
||||
const scrollToIndex = toolImport('util/scrollToIndex');
|
||||
const { setViewportSpecificData } = OHIF.redux.actions;
|
||||
|
||||
// Why do I need or care about any of this info?
|
||||
// A dispatch action should be able to pull this at the time of an event?
|
||||
// `isPlaying` and `cineFrameRate` might matter, but I think we can prop pass for those.
|
||||
const mapStateToProps = state => {
|
||||
// Get activeViewport's `cine` and `stack`
|
||||
const { viewportSpecificData, activeViewportIndex } = state.viewports;
|
||||
const { cine } = viewportSpecificData[activeViewportIndex] || {};
|
||||
const dom = commandsManager.runCommand('getActiveViewportEnabledElement');
|
||||
|
||||
const cineData = cine || {
|
||||
isPlaying: false,
|
||||
cineFrameRate: 24,
|
||||
};
|
||||
|
||||
// New props we're creating?
|
||||
return {
|
||||
activeEnabledElement: dom,
|
||||
activeViewportCineData: cineData,
|
||||
activeViewportIndex: state.viewports.activeViewportIndex,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
dispatchSetViewportSpecificData: (viewportIndex, data) => {
|
||||
dispatch(setViewportSpecificData(viewportIndex, data));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
|
||||
const {
|
||||
activeEnabledElement,
|
||||
activeViewportCineData,
|
||||
activeViewportIndex,
|
||||
} = propsFromState;
|
||||
|
||||
return {
|
||||
cineFrameRate: activeViewportCineData.cineFrameRate,
|
||||
isPlaying: activeViewportCineData.isPlaying,
|
||||
onPlayPauseChanged: isPlaying => {
|
||||
const cine = cloneDeep(activeViewportCineData);
|
||||
cine.isPlaying = !cine.isPlaying;
|
||||
|
||||
propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {
|
||||
cine,
|
||||
});
|
||||
},
|
||||
onFrameRateChanged: frameRate => {
|
||||
const cine = cloneDeep(activeViewportCineData);
|
||||
cine.cineFrameRate = frameRate;
|
||||
|
||||
propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {
|
||||
cine,
|
||||
});
|
||||
},
|
||||
onClickNextButton: () => {
|
||||
const stackData = csTools.getToolState(activeEnabledElement, 'stack');
|
||||
if (!stackData || !stackData.data || !stackData.data.length) return;
|
||||
const { currentImageIdIndex, imageIds } = stackData.data[0];
|
||||
if (currentImageIdIndex >= imageIds.length - 1) return;
|
||||
scrollToIndex(activeEnabledElement, currentImageIdIndex + 1);
|
||||
},
|
||||
onClickBackButton: () => {
|
||||
const stackData = csTools.getToolState(activeEnabledElement, 'stack');
|
||||
if (!stackData || !stackData.data || !stackData.data.length) return;
|
||||
const { currentImageIdIndex } = stackData.data[0];
|
||||
if (currentImageIdIndex === 0) return;
|
||||
scrollToIndex(activeEnabledElement, currentImageIdIndex - 1);
|
||||
},
|
||||
onClickSkipToStart: () => {
|
||||
const stackData = csTools.getToolState(activeEnabledElement, 'stack');
|
||||
if (!stackData || !stackData.data || !stackData.data.length) return;
|
||||
scrollToIndex(activeEnabledElement, 0);
|
||||
},
|
||||
onClickSkipToEnd: () => {
|
||||
const stackData = csTools.getToolState(activeEnabledElement, 'stack');
|
||||
if (!stackData || !stackData.data || !stackData.data.length) return;
|
||||
const lastIndex = stackData.data[0].imageIds.length - 1;
|
||||
scrollToIndex(activeEnabledElement, lastIndex);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedCineDialog = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(CineDialog);
|
||||
|
||||
export default ConnectedCineDialog;
|
||||
@@ -1,12 +0,0 @@
|
||||
import Header from '../components/Header/Header.js';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
user: state.oidc && state.oidc.user,
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedHeader = connect(mapStateToProps)(Header);
|
||||
|
||||
export default ConnectedHeader;
|
||||
@@ -1,67 +0,0 @@
|
||||
import { LayoutButton } from '@ohif/ui';
|
||||
import OHIF from '@ohif/core';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const { setLayout, setViewportActive } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
currentLayout: state.viewports.layout,
|
||||
activeViewportIndex: state.viewports.activeViewportIndex,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
// TODO: Change if layout switched becomes more complex
|
||||
onChange: (selectedCell, currentLayout, activeViewportIndex) => {
|
||||
const viewports = [];
|
||||
const numRows = selectedCell.row + 1;
|
||||
const numColumns = selectedCell.col + 1;
|
||||
const numViewports = numRows * numColumns;
|
||||
|
||||
for (let i = 0; i < numViewports; i++) {
|
||||
// Hacky way to allow users to exit MPR "mode"
|
||||
const viewport = currentLayout.viewports[i];
|
||||
let plugin = viewport && viewport.plugin;
|
||||
if (viewport && viewport.vtk) {
|
||||
plugin = 'cornerstone';
|
||||
}
|
||||
|
||||
viewports.push({
|
||||
plugin,
|
||||
});
|
||||
}
|
||||
const layout = {
|
||||
numRows,
|
||||
numColumns,
|
||||
viewports,
|
||||
};
|
||||
|
||||
const maxActiveIndex = numViewports - 1;
|
||||
if (activeViewportIndex > maxActiveIndex) {
|
||||
dispatch(setViewportActive(0));
|
||||
}
|
||||
|
||||
dispatch(setLayout(layout));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const mergeProps = (propsFromState, propsFromDispatch) => {
|
||||
const onChangeFromDispatch = propsFromDispatch.onChange;
|
||||
const { currentLayout, activeViewportIndex } = propsFromState;
|
||||
|
||||
return {
|
||||
onChange: selectedCell =>
|
||||
onChangeFromDispatch(selectedCell, currentLayout, activeViewportIndex),
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedLayoutButton = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(LayoutButton);
|
||||
|
||||
export default ConnectedLayoutButton;
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import StandaloneRouting from '../routes/StandaloneRouting';
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
activateServer: server => {
|
||||
const action = {
|
||||
type: 'ACTIVATE_SERVER',
|
||||
server,
|
||||
};
|
||||
dispatch(action);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedStandaloneRouting = connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(StandaloneRouting);
|
||||
|
||||
export default ConnectedStandaloneRouting;
|
||||
@@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import { StudyList } from '@ohif/ui';
|
||||
|
||||
const ConnectedStudyList = () => {
|
||||
return (
|
||||
/** Temporary using StudyList -- We should mount it by using the created
|
||||
* components such as NavBar, InputGroup, StudyListTable, etc...
|
||||
* Check "Views > StudyList" in @ohif/ui for reference
|
||||
*/
|
||||
<StudyList />
|
||||
);
|
||||
};
|
||||
|
||||
export default ConnectedStudyList;
|
||||
@@ -1,26 +0,0 @@
|
||||
import { connect } from "react-redux";
|
||||
import StudyLoadingMonitor from "../components/StudyLoadingMonitor.js";
|
||||
import OHIF from "@ohif/core";
|
||||
|
||||
const {
|
||||
setStudyLoadingProgress,
|
||||
clearStudyLoadingProgress
|
||||
} = OHIF.redux.actions;
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setStudyLoadingProgress: (progressId, progressData) => {
|
||||
dispatch(setStudyLoadingProgress(progressId, progressData));
|
||||
},
|
||||
clearStudyLoadingProgress: progressId => {
|
||||
dispatch(clearStudyLoadingProgress(progressId));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedStudyLoadingMonitor = connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(StudyLoadingMonitor);
|
||||
|
||||
export default ConnectedStudyLoadingMonitor;
|
||||
@@ -1,37 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import Viewer from './Viewer.js';
|
||||
import OHIF from '@ohif/core';
|
||||
|
||||
const { setTimepoints, setMeasurements } = OHIF.redux.actions;
|
||||
|
||||
const getActiveServer = servers => {
|
||||
const isActive = a => a.active === true;
|
||||
return servers.servers.find(isActive);
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { viewports, servers } = state;
|
||||
return {
|
||||
viewports: viewports.viewportSpecificData,
|
||||
activeViewportIndex: viewports.activeViewportIndex,
|
||||
activeServer: getActiveServer(servers),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onTimepointsUpdated: timepoints => {
|
||||
dispatch(setTimepoints(timepoints));
|
||||
},
|
||||
onMeasurementsUpdated: measurements => {
|
||||
dispatch(setMeasurements(measurements));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedViewer = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Viewer);
|
||||
|
||||
export default ConnectedViewer;
|
||||
@@ -1,17 +0,0 @@
|
||||
.ToolbarRow {
|
||||
border-bottom: var(--ui-border-thickness) solid var(--ui-border-color);
|
||||
flex: 0 0 auto;
|
||||
height: var(--toolbar-height);
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
position: relative;
|
||||
transition: height 300ms ease;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
ToolbarRow.expanded {
|
||||
height: calc(var(--toolbar-height) + var(--toolbar-drawer-height));
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#viewer {
|
||||
background-color: black;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.loadingTextDiv {
|
||||
color: var(--text-secondary-color);
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
.drag-drop-instructions {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.drag-drop-instructions h3 {
|
||||
color: var(--active-color);
|
||||
}
|
||||
|
||||
.drag-drop-instructions h4 {
|
||||
color: var(--text-secondary-color);
|
||||
}
|
||||
|
||||
.link-dialog {
|
||||
color: var(--active-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#viewer {
|
||||
height: calc(100% - var(--top-bar-height));
|
||||
}
|
||||
|
||||
#viewer > .loadingTextDiv {
|
||||
color: var(--text-secondary-color);
|
||||
font-size: 30px;
|
||||
height: 100%;
|
||||
line-height: calc(100% - var(--top-bar-height));
|
||||
}
|
||||
|
||||
.ViewerMain {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.ViewerMain > div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
Reference in new issue
Block a user