diff --git a/platform/viewer/src/routes/ModeRoute.js b/platform/viewer/src/routes/ModeRoute.js new file mode 100644 index 000000000..d206ef440 --- /dev/null +++ b/platform/viewer/src/routes/ModeRoute.js @@ -0,0 +1,68 @@ +export default function ModeRoute(mode, dataSourceId) { + const [displaySets, setDisplaySets] = useState([]); + const { routes, sopClassHandlers, extensions } = getMode(modeId); + + // Deal with toolbar. + + // Only handling one route per mode for now + const LayoutComponent = routes[0].layoutTemplate; + + // Add SOPClassHandlers to a new SOPClassManager. + const manager = new SOPClassHandlerManager(sopClassHandlers); + + const dataSource = getDataSource(dataSourceId); + const queryParams = location.search; + + // Call the data source to start building the view model? + dataSource(queryParams); + + metadataStore.onModified(); + + const onUpdatedCallback = () => { + // TODO: This should append, not create from scratch so we don't nuke existing display sets + // when e.g. a new series arrives + manager.createDisplaySets.then(setDisplaySets); + }; + + // TODO: Should extensions provide an array of these or one nested context? + const contextModules = extensions.getContextModules(); + const ExtensionContexts = contextModules => {}; + + /* + TODO: How are contexts provided by extensions passed into the mode? + + return ( + + + + );*/ + + return ; +} + +/*const ViewModelContext = React.createContext( + displaySets: [], + setDisplaySets: () => {} +); + + +class ViewModelProvider extends Component { + state = { + displaySets: [] + }; + + const setDisplaySets = displaySets => { + this.setState({displaySets}); + }; + + render() { + return ( + + {this.props.children} + + ); + } +}*/ diff --git a/platform/viewer/src/routes/SOPClassHandlerManager.js b/platform/viewer/src/routes/SOPClassHandlerManager.js new file mode 100644 index 000000000..359551f6f --- /dev/null +++ b/platform/viewer/src/routes/SOPClassHandlerManager.js @@ -0,0 +1,27 @@ +export default class SOPClassHandlerManager { + constructor(sopClassHandlerIds) { + this.SOPClassHandlers = sopClassHandlerIds.map(getSOPClassHandler); + } + + async createDisplaySets() { + const SOPClassHandlers = this.SOPClassHandlers; + + const displaySets = []; + + // TODO + StudyMetadata.forEachSeries(series => { + for (let i = 0; i < SOPClassHandlers.length; i++) { + const handler = SOPClassHandlers[i]; + + // TODO: This step is still unclear to me + const displaySet = handler(series); + + if (displaySet) { + displaySets.push(displaySet); + } + } + }); + + return displaySets; + } +} diff --git a/platform/viewer/src/routes/buildModeRoutes.js b/platform/viewer/src/routes/buildModeRoutes.js new file mode 100644 index 000000000..c43476bc8 --- /dev/null +++ b/platform/viewer/src/routes/buildModeRoutes.js @@ -0,0 +1,46 @@ +import { React } from 'react'; +import ModeRoute from './ModeRoute'; + +/* + Routes uniquely define an entry point to: + - A mode + - Linked to a data source + - With a specified data set. + + The full route template is: + + /:modeId/:modeRoute/:sourceType/?queryParameters=example + + Where: + :modeId - Is the mode selected. + :modeRoute - Is the route within the mode to select. + :sourceType - Is the data source identifier, which specifies which DataSource to use. + ?queryParameters - Are query parameters as defined by data source. + + A default source can be specified at the app level configuration, and then that source is used if :sourceType is omitted: + + /:modeId/:modeRoute/?queryParameters=example + */ +export default function buildModeRoutes(modes, extensionManager) { + const routes = []; + + // TODO: Build api for this. + const dataSources = extensionManager.getDataSources(); + + modes.forEach(mode => { + dataSources.forEach(dataSource => { + const dataSourceId = dataSource.id; + const path = `/${mode.id}/${dataSourceId}`; + + const component = ; + + routes.push({ + path, + component, + exact: true, + }); + }); + }); + + return routes; +}