[ARVADOS-WORKBENCH2] updated: 2.1.0-253-g6c915029

Git user git at public.arvados.org
Fri Mar 12 22:42:57 UTC 2021


Summary of changes:
 src/plugins.tsx                                    |   7 +-
 src/plugins/sample-tracker/index.tsx               |  82 +++++++--
 src/plugins/sample-tracker/patient.tsx             |  34 ++++
 .../sample-tracker/{study.tsx => patientList.tsx}  | 148 ++++++++-------
 src/plugins/sample-tracker/study.tsx               | 199 +++------------------
 .../sample-tracker/{study.tsx => studyList.tsx}    |  61 +++----
 6 files changed, 249 insertions(+), 282 deletions(-)
 create mode 100644 src/plugins/sample-tracker/patient.tsx
 copy src/plugins/sample-tracker/{study.tsx => patientList.tsx} (54%)
 copy src/plugins/sample-tracker/{study.tsx => studyList.tsx} (81%)

       via  6c9150296ea85b9bba0fe151b552a687748b8141 (commit)
       via  c1efd6eecdd77692a1c170201f9871edfecac0c8 (commit)
       via  e3fdfaefcda0ed9cca8de597d302da248fa10597 (commit)
       via  c1a961408a3c590e6ff246cd4de4734d5c84d23c (commit)
      from  2f72968731d9a1f54a23022fd3bb13c29a7049f0 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 6c9150296ea85b9bba0fe151b552a687748b8141
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Mar 12 17:42:47 2021 -0500

    Add new file
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/src/plugins/sample-tracker/patient.tsx b/src/plugins/sample-tracker/patient.tsx
new file mode 100644
index 00000000..84273a97
--- /dev/null
+++ b/src/plugins/sample-tracker/patient.tsx
@@ -0,0 +1,34 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from "redux";
+import { propertiesActions } from "~/store/properties/properties-actions";
+import { getProperty } from '~/store/properties/properties';
+import { RootState } from '~/store/store';
+// import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
+// import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
+
+import { PATIENT_PANEL_CURRENT_UUID } from './patientList';
+
+export const openPatientPanel = (projectUuid: string) =>
+    (dispatch: Dispatch) => {
+        dispatch(propertiesActions.SET_PROPERTY({ key: PATIENT_PANEL_CURRENT_UUID, value: projectUuid }));
+        // dispatch(patientListPanelActions.REQUEST_ITEMS());
+    };
+
+interface PatientProps {
+    patientUuid: string;
+}
+
+export const patientMapStateToProps = (state: RootState) => ({
+    patientUuid: getProperty(PATIENT_PANEL_CURRENT_UUID)(state.properties),
+});
+
+export const PatientMainPanel = connect(patientMapStateToProps)(
+    ({ patientUuid }: PatientProps) =>
+        <div>
+            <h1>Samples</h1>
+        </div>);

commit c1efd6eecdd77692a1c170201f9871edfecac0c8
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Mar 12 17:41:32 2021 -0500

    Skeleton patient page, work on breadcrumbs
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/src/plugins/sample-tracker/index.tsx b/src/plugins/sample-tracker/index.tsx
index 8bcea3d9..bd6faa97 100644
--- a/src/plugins/sample-tracker/index.tsx
+++ b/src/plugins/sample-tracker/index.tsx
@@ -12,7 +12,7 @@ import { push } from "react-router-redux";
 import { Route, matchPath } from "react-router";
 import { RootStore } from '~/store/store';
 import { activateSidePanelTreeItem } from '~/store/side-panel-tree/side-panel-tree-actions';
-import { setSidePanelBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
+import { setBreadcrumbs, setSidePanelBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
 import { Location } from 'history';
 import { handleFirstTimeLoad } from '~/store/workbench/workbench-actions';
 import {
@@ -24,13 +24,17 @@ import {
 import {
     AddPatientMenuComponent, CreatePatientDialog, PATIENT_LIST_PANEL_ID, StudyPathId,
     PatientListPanelMiddlewareService,
-    patientListPanelColumns, patientListPanelActions,
-
+    patientListPanelColumns, patientListPanelActions, patientRoutePath, patientBaseRoutePath
 } from './patientList';
 import {
     openStudyPanel, StudyMainPanel
 } from './study';
+import {
+    openPatientPanel, PatientMainPanel
+} from './patient';
 import { dataExplorerMiddleware } from "~/store/data-explorer/data-explorer-middleware";
+import { getResource } from "~/store/resources/resources";
+import { GroupResource } from "~/models/group";
 
 const categoryName = "Studies";
 
@@ -39,6 +43,7 @@ export const register = (pluginConfig: PluginConfig) => {
     pluginConfig.centerPanelList.push((elms) => {
         elms.push(<Route path={studyListRoutePath} component={StudyListMainPanel} exact={true} />);
         elms.push(<Route path={studyRoutePath} component={StudyMainPanel} exact={true} />);
+        elms.push(<Route path={patientRoutePath} component={PatientMainPanel} exact={true} />);
         return elms;
     });
 
@@ -57,6 +62,10 @@ export const register = (pluginConfig: PluginConfig) => {
             dispatch(push(uuid));
             return true;
         }
+        if (uuid.startsWith(patientBaseRoutePath)) {
+            dispatch(push(uuid));
+            return true;
+        }
         return false;
     });
 
@@ -80,10 +89,29 @@ export const register = (pluginConfig: PluginConfig) => {
                     dispatch(patientListPanelActions.SET_COLUMNS({ columns: patientListPanelColumns }));
                     dispatch<any>(openStudyPanel(studyid.params.uuid));
                     // dispatch<any>(activateSidePanelTreeItem(categoryName));
-                    // dispatch<any>(setSidePanelBreadcrumbs(categoryName));
+                    // const name = getProperty(PATIENT_PANEL_CURRENT_UUID)(state.properties),
+                    const rsc = getResource<GroupResource>(pathname)(store.getState().resources);
+                    if (rsc) {
+                        dispatch<any>(setBreadcrumbs([{ label: categoryName, uuid: categoryName }, { label: rsc.name, uuid: pathname }]));
+                    }
+                }));
+            return true;
+        }
+        const patientid = matchPath<StudyPathId>(pathname, { path: patientRoutePath, exact: true });
+        if (patientid) {
+            store.dispatch(handleFirstTimeLoad(
+                (dispatch: Dispatch) => {
+                    // dispatch(patientListPanelActions.SET_COLUMNS({ columns: patientListPanelColumns }));
+                    dispatch<any>(openPatientPanel(patientid.params.uuid));
+                    // dispatch<any>(activateSidePanelTreeItem(categoryName));
+                    const patientrsc = getResource<GroupResource>(pathname)(store.getState().resources);
+                    if (patientrsc) {
+                        dispatch<any>(setBreadcrumbs([{ label: categoryName, uuid: categoryName }, { label: patientrsc.name, uuid: pathname }]));
+                    }
                 }));
             return true;
         }
+
         return false;
     });
 
diff --git a/src/plugins/sample-tracker/patientList.tsx b/src/plugins/sample-tracker/patientList.tsx
index 332c4321..51e3c38e 100644
--- a/src/plugins/sample-tracker/patientList.tsx
+++ b/src/plugins/sample-tracker/patientList.tsx
@@ -46,7 +46,9 @@ export const PATIENT_LIST_PANEL_ID = "patientListPanel";
 export const patientListPanelActions = bindDataExplorerActions(PATIENT_LIST_PANEL_ID);
 export const sampleTrackerPatientType = "sample_tracker:patient";
 export const STUDY_PANEL_CURRENT_UUID = "StudyPanelCurrentUUID";
-export const patientRoutePath = "/SampleTracker/Patient";
+export const PATIENT_PANEL_CURRENT_UUID = "PatientPanelCurrentUUID";
+export const patientBaseRoutePath = "/SampleTracker/Patient";
+export const patientRoutePath = patientBaseRoutePath + "/:uuid";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;
@@ -147,13 +149,6 @@ const setItems = (listResults: ListResults<GroupResource>) =>
     });
 
 const getFilters = (dataExplorer: DataExplorerState, studyUuid: string) => {
-    //    const columns = dataExplorer.columns as DataColumns<string>;
-    //    const typeFilters = serializeResourceTypeFilters(getDataExplorerColumnFilters(columns, ProjectPanelColumnNames.TYPE));
-    //    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
-    //    const activeStatusFilter = Object.keys(statusColumnFilters).find(
-    //        filterName => statusColumnFilters[filterName].selected
-    //    );
-
     const fb = new FilterBuilder();
     fb.addEqual("owner_uuid", studyUuid);
     fb.addEqual("properties.type", sampleTrackerPatientType);
@@ -193,7 +188,7 @@ export class PatientListPanelMiddlewareService extends DataExplorerMiddlewareSer
             const response = await this.services.groupsService.list(getParams(dataExplorer, studyUuid));
             api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
             for (const i of response.items) {
-                i.uuid = patientRoutePath + "/" + i.uuid;
+                i.uuid = patientBaseRoutePath + "/" + i.uuid;
             }
             api.dispatch(updateResources(response.items));
             api.dispatch(setItems(response));
diff --git a/src/plugins/sample-tracker/studyList.tsx b/src/plugins/sample-tracker/studyList.tsx
index 324d30b9..4180a9ee 100644
--- a/src/plugins/sample-tracker/studyList.tsx
+++ b/src/plugins/sample-tracker/studyList.tsx
@@ -97,33 +97,6 @@ enum StudyPanelColumnNames {
     NAME = "Name"
 }
 
-/* const renderName = (dispatch: Dispatch, item: GroupContentsResource) =>
- *     <Grid container alignItems="center" wrap="nowrap" spacing={16}>
- *         <Grid item>
- *             {renderIcon(item)}
- *         </Grid>
- *         <Grid item>
- *             <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} onClick={() => dispatch<any>(navigateTo(item.uuid))}>
- *                 {item.kind === ResourceKind.PROJECT || item.kind === ResourceKind.COLLECTION
- *                     ? <IllegalNamingWarning name={item.name} />
- *                     : null}
- *                 {item.name}
- *             </Typography>
- *         </Grid>
- *         <Grid item>
- *             <Typography variant="caption">
- *                 <FavoriteStar resourceUuid={item.uuid} />
- *                 <PublicFavoriteStar resourceUuid={item.uuid} />
- *             </Typography>
- *         </Grid>
- *     </Grid>;
- *
- * const ResourceName = connect(
- *     (state: RootState, props: { uuid: string }) => {
- *         const resource = getResource<GroupResource>(props.uuid)(state.resources);
- *         return resource;
- *     })((resource: GroupResource & DispatchProp<any>) => renderName(resource.dispatch, resource));
- *  */
 export const studyListPanelColumns: DataColumns<string> = [
     {
         name: StudyPanelColumnNames.NAME,

commit e3fdfaefcda0ed9cca8de597d302da248fa10597
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Mar 12 17:02:26 2021 -0500

    Add add patients to studies.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/src/plugins/sample-tracker/index.tsx b/src/plugins/sample-tracker/index.tsx
index ee6f0c58..8bcea3d9 100644
--- a/src/plugins/sample-tracker/index.tsx
+++ b/src/plugins/sample-tracker/index.tsx
@@ -19,15 +19,16 @@ import {
     AddStudyMenuComponent, StudyListMainPanel, CreateStudyDialog,
     studyListPanelColumns, studyListPanelActions, openStudyListPanel,
     StudyListPanelMiddlewareService, STUDY_LIST_PANEL_ID,
-    studyListRoutePath
+    studyListRoutePath, studyRoutePath
 } from './studyList';
 import {
-    AddPatientMenuComponent, CreatePatientDialog, PATIENT_LIST_PANEL_ID, StudyPathId
-    //    PatientListPanelColumns, patientListPanelActions,
-    //    PatientListPanelMiddlewareService,
+    AddPatientMenuComponent, CreatePatientDialog, PATIENT_LIST_PANEL_ID, StudyPathId,
+    PatientListPanelMiddlewareService,
+    patientListPanelColumns, patientListPanelActions,
+
 } from './patientList';
 import {
-    studyRoutePath, openStudyPanel, StudyMainPanel
+    openStudyPanel, StudyMainPanel
 } from './study';
 import { dataExplorerMiddleware } from "~/store/data-explorer/data-explorer-middleware";
 
@@ -76,7 +77,7 @@ export const register = (pluginConfig: PluginConfig) => {
         if (studyid) {
             store.dispatch(handleFirstTimeLoad(
                 (dispatch: Dispatch) => {
-                    // dispatch(studyListPanelActions.SET_COLUMNS({ columns: studyListPanelColumns }));
+                    dispatch(patientListPanelActions.SET_COLUMNS({ columns: patientListPanelColumns }));
                     dispatch<any>(openStudyPanel(studyid.params.uuid));
                     // dispatch<any>(activateSidePanelTreeItem(categoryName));
                     // dispatch<any>(setSidePanelBreadcrumbs(categoryName));
@@ -96,7 +97,7 @@ export const register = (pluginConfig: PluginConfig) => {
             new StudyListPanelMiddlewareService(services, STUDY_LIST_PANEL_ID)
         ));
         elms.push(dataExplorerMiddleware(
-            new StudyListPanelMiddlewareService(services, PATIENT_LIST_PANEL_ID)
+            new PatientListPanelMiddlewareService(services, PATIENT_LIST_PANEL_ID)
         ));
         return elms;
     });
diff --git a/src/plugins/sample-tracker/patientList.tsx b/src/plugins/sample-tracker/patientList.tsx
index 93975ee1..332c4321 100644
--- a/src/plugins/sample-tracker/patientList.tsx
+++ b/src/plugins/sample-tracker/patientList.tsx
@@ -7,7 +7,7 @@ import { InjectedFormProps } from 'redux-form';
 import { WithDialogProps } from '~/store/dialog/with-dialog';
 import { ProjectCreateFormDialogData } from '~/store/projects/project-create-actions';
 import { FormDialog } from '~/components/form-dialog/form-dialog';
-import { ProjectNameField, ProjectDescriptionField } from '~/views-components/form-fields/project-form-fields';
+import { ProjectNameField } from '~/views-components/form-fields/project-form-fields';
 import { dialogActions } from "~/store/dialog/dialog-actions";
 import { ServiceRepository } from "~/services/services";
 import { compose, MiddlewareAPI, Dispatch } from "redux";
@@ -37,13 +37,16 @@ import { FilterBuilder, joinFilters } from "~/services/api/filter-builder";
 import { updateResources } from "~/store/resources/resources-actions";
 import {
     studyRoutePath
-} from './study';
+} from './studyList';
 import { matchPath } from "react-router";
+import { getProperty } from '~/store/properties/properties';
 
 const PATIENT_CREATE_FORM_NAME = "patientCreateFormName";
 export const PATIENT_LIST_PANEL_ID = "patientListPanel";
 export const patientListPanelActions = bindDataExplorerActions(PATIENT_LIST_PANEL_ID);
 export const sampleTrackerPatientType = "sample_tracker:patient";
+export const STUDY_PANEL_CURRENT_UUID = "StudyPanelCurrentUUID";
+export const patientRoutePath = "/SampleTracker/Patient";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;
@@ -54,8 +57,7 @@ export interface ProjectCreateFormDialogData {
 type DialogProjectProps = WithDialogProps<{}> & InjectedFormProps<ProjectCreateFormDialogData>;
 
 const PatientAddFields = () => <span>
-    <ProjectNameField label="Patient name" />
-    <ProjectDescriptionField />
+    <ProjectNameField label="Patient anonymized identifier" />
 </span>;
 
 const DialogPatientCreate = (props: DialogProjectProps) =>
@@ -111,7 +113,7 @@ enum PatientPanelColumnNames {
     NAME = "Name"
 }
 
-export const PatientListPanelColumns: DataColumns<string> = [
+export const patientListPanelColumns: DataColumns<string> = [
     {
         name: PatientPanelColumnNames.NAME,
         selected: true,
@@ -122,11 +124,6 @@ export const PatientListPanelColumns: DataColumns<string> = [
     }
 ];
 
-export const openPatientListPanel = (dispatch: Dispatch) => {
-    // dispatch(propertiesActions.SET_PROPERTY({ key: PROJECT_PANEL_CURRENT_UUID, value: projectUuid }));
-    dispatch(patientListPanelActions.REQUEST_ITEMS());
-};
-
 export interface TrackerProps {
     className?: string;
 }
@@ -149,14 +146,16 @@ const setItems = (listResults: ListResults<GroupResource>) =>
         items: listResults.items.map(resource => resource.uuid),
     });
 
-const getFilters = (dataExplorer: DataExplorerState) => {
+const getFilters = (dataExplorer: DataExplorerState, studyUuid: string) => {
     //    const columns = dataExplorer.columns as DataColumns<string>;
     //    const typeFilters = serializeResourceTypeFilters(getDataExplorerColumnFilters(columns, ProjectPanelColumnNames.TYPE));
     //    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
     //    const activeStatusFilter = Object.keys(statusColumnFilters).find(
     //        filterName => statusColumnFilters[filterName].selected
     //    );
+
     const fb = new FilterBuilder();
+    fb.addEqual("owner_uuid", studyUuid);
     fb.addEqual("properties.type", sampleTrackerPatientType);
 
     const nameFilters = new FilterBuilder()
@@ -169,9 +168,9 @@ const getFilters = (dataExplorer: DataExplorerState) => {
     );
 };
 
-const getParams = (dataExplorer: DataExplorerState) => ({
+const getParams = (dataExplorer: DataExplorerState, studyUuid: string) => ({
     ...dataExplorerToListParams(dataExplorer),
-    filters: getFilters(dataExplorer),
+    filters: getFilters(dataExplorer, studyUuid),
 });
 
 export class PatientListPanelMiddlewareService extends DataExplorerMiddlewareService {
@@ -183,10 +182,19 @@ export class PatientListPanelMiddlewareService extends DataExplorerMiddlewareSer
         const state = api.getState();
         const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
 
+        const studyUuid = getProperty<string>(STUDY_PANEL_CURRENT_UUID)(state.properties);
+
+        if (!studyUuid) {
+            return;
+        }
+
         try {
             api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
-            const response = await this.services.groupsService.list(getParams(dataExplorer));
+            const response = await this.services.groupsService.list(getParams(dataExplorer, studyUuid));
             api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+            for (const i of response.items) {
+                i.uuid = patientRoutePath + "/" + i.uuid;
+            }
             api.dispatch(updateResources(response.items));
             api.dispatch(setItems(response));
         } catch (e) {
diff --git a/src/plugins/sample-tracker/study.tsx b/src/plugins/sample-tracker/study.tsx
index 1b330920..4accdb65 100644
--- a/src/plugins/sample-tracker/study.tsx
+++ b/src/plugins/sample-tracker/study.tsx
@@ -4,19 +4,19 @@
 
 import * as React from 'react';
 import { connect } from 'react-redux';
-import { studyListRoutePath } from './studyList';
 import { Dispatch } from "redux";
 import { propertiesActions } from "~/store/properties/properties-actions";
 import { getProperty } from '~/store/properties/properties';
 import { RootState } from '~/store/store';
+import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
+import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
 
-export const studyRoutePath = studyListRoutePath + "/:uuid";
-const STUDY_PANEL_CURRENT_UUID = "StudyPanelCurrentUUID";
+import { PATIENT_LIST_PANEL_ID, STUDY_PANEL_CURRENT_UUID, patientListPanelActions } from './patientList';
 
 export const openStudyPanel = (projectUuid: string) =>
     (dispatch: Dispatch) => {
         dispatch(propertiesActions.SET_PROPERTY({ key: STUDY_PANEL_CURRENT_UUID, value: projectUuid }));
-        // dispatch(studyListPanelActions.REQUEST_ITEMS());
+        dispatch(patientListPanelActions.REQUEST_ITEMS());
     };
 
 interface StudyProps {
@@ -29,4 +29,15 @@ export const studyMapStateToProps = (state: RootState) => ({
 
 export const StudyMainPanel = connect(studyMapStateToProps)(
     ({ studyUuid }: StudyProps) =>
-        <p>Main panel for study {studyUuid}</p>);
+        <div>
+            <h1>Patients</h1>
+            <DataExplorer
+                id={PATIENT_LIST_PANEL_ID}
+                onRowClick={(uuid: string) => { }}
+                onRowDoubleClick={(uuid: string) => { }}
+                onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
+                contextMenuColumn={true}
+                dataTableDefaultView={
+                    <DataTableDefaultView />
+                } />
+        </div>);
diff --git a/src/plugins/sample-tracker/studyList.tsx b/src/plugins/sample-tracker/studyList.tsx
index 00ded8dd..324d30b9 100644
--- a/src/plugins/sample-tracker/studyList.tsx
+++ b/src/plugins/sample-tracker/studyList.tsx
@@ -40,7 +40,8 @@ const STUDY_CREATE_FORM_NAME = "studyCreateFormName";
 export const STUDY_LIST_PANEL_ID = "studyPanel";
 export const studyListPanelActions = bindDataExplorerActions(STUDY_LIST_PANEL_ID);
 export const sampleTrackerStudyType = "sample_tracker:study";
-export const studyListRoutePath = "/sample_tracker_Studies";
+export const studyListRoutePath = "/sampleTracker/Studies";
+export const studyRoutePath = studyListRoutePath + "/:uuid";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;

commit c1a961408a3c590e6ff246cd4de4734d5c84d23c
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Mar 12 16:36:55 2021 -0500

    Patient/Study UI WIP
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/src/plugins.tsx b/src/plugins.tsx
index 4fad335d..1880e62d 100644
--- a/src/plugins.tsx
+++ b/src/plugins.tsx
@@ -22,10 +22,11 @@ export const pluginConfig: PluginConfig = {
 // Starting here, import and register your Workbench 2 plugins. //
 
 // import { register as blankUIPluginRegister } from '~/plugins/blank/index';
-import { register as examplePluginRegister, routePath as trackerRoutePath } from '~/plugins/sample-tracker/index';
+import { register as sampleTrackerPluginRegister } from '~/plugins/sample-tracker/index';
+import { studyListRoutePath } from '~/plugins/sample-tracker/studyList';
 // import { register as examplePluginRegister, routePath as exampleRoutePath } from '~/plugins/example/index';
 import { register as rootRedirectRegister } from '~/plugins/root-redirect/index';
 
 // blankUIPluginRegister(pluginConfig);
-examplePluginRegister(pluginConfig);
-rootRedirectRegister(pluginConfig, trackerRoutePath);
+sampleTrackerPluginRegister(pluginConfig);
+rootRedirectRegister(pluginConfig, studyListRoutePath);
diff --git a/src/plugins/sample-tracker/index.tsx b/src/plugins/sample-tracker/index.tsx
index 69c90e0a..ee6f0c58 100644
--- a/src/plugins/sample-tracker/index.tsx
+++ b/src/plugins/sample-tracker/index.tsx
@@ -16,30 +16,44 @@ import { setSidePanelBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions
 import { Location } from 'history';
 import { handleFirstTimeLoad } from '~/store/workbench/workbench-actions';
 import {
-    AddStudyMenuComponent, StudiesMainPanel, CreateStudyDialog,
-    studyPanelColumns, studyPanelActions, openStudiesPanel,
-    StudiesPanelMiddlewareService, STUDY_PANEL_ID
+    AddStudyMenuComponent, StudyListMainPanel, CreateStudyDialog,
+    studyListPanelColumns, studyListPanelActions, openStudyListPanel,
+    StudyListPanelMiddlewareService, STUDY_LIST_PANEL_ID,
+    studyListRoutePath
+} from './studyList';
+import {
+    AddPatientMenuComponent, CreatePatientDialog, PATIENT_LIST_PANEL_ID, StudyPathId
+    //    PatientListPanelColumns, patientListPanelActions,
+    //    PatientListPanelMiddlewareService,
+} from './patientList';
+import {
+    studyRoutePath, openStudyPanel, StudyMainPanel
 } from './study';
 import { dataExplorerMiddleware } from "~/store/data-explorer/data-explorer-middleware";
 
 const categoryName = "Studies";
-export const routePath = "/sample_tracker_Studies";
 
 export const register = (pluginConfig: PluginConfig) => {
 
     pluginConfig.centerPanelList.push((elms) => {
-        elms.push(<Route path={routePath} component={StudiesMainPanel} />);
+        elms.push(<Route path={studyListRoutePath} component={StudyListMainPanel} exact={true} />);
+        elms.push(<Route path={studyRoutePath} component={StudyMainPanel} exact={true} />);
         return elms;
     });
 
     pluginConfig.newButtonMenuList.push((elms, menuItemClass) => {
         elms.push(<AddStudyMenuComponent className={menuItemClass} />);
+        elms.push(<AddPatientMenuComponent className={menuItemClass} />);
         return elms;
     });
 
     pluginConfig.navigateToHandlers.push((dispatch: Dispatch, getState: () => RootState, uuid: string) => {
         if (uuid === categoryName) {
-            dispatch(push(routePath));
+            dispatch(push(studyListRoutePath));
+            return true;
+        }
+        if (uuid.startsWith(studyListRoutePath)) {
+            dispatch(push(uuid));
             return true;
         }
         return false;
@@ -48,26 +62,41 @@ export const register = (pluginConfig: PluginConfig) => {
     pluginConfig.sidePanelCategories.push((cats: string[]): string[] => { cats.push(categoryName); return cats; });
 
     pluginConfig.locationChangeHandlers.push((store: RootStore, pathname: string): boolean => {
-        if (matchPath(pathname, { path: routePath, exact: true })) {
+        if (matchPath(pathname, { path: studyListRoutePath, exact: true })) {
             store.dispatch(handleFirstTimeLoad(
                 (dispatch: Dispatch) => {
-                    dispatch(studyPanelActions.SET_COLUMNS({ columns: studyPanelColumns }));
-                    dispatch<any>(openStudiesPanel);
+                    dispatch(studyListPanelActions.SET_COLUMNS({ columns: studyListPanelColumns }));
+                    dispatch<any>(openStudyListPanel);
                     dispatch<any>(activateSidePanelTreeItem(categoryName));
                     dispatch<any>(setSidePanelBreadcrumbs(categoryName));
                 }));
             return true;
         }
+        const studyid = matchPath<StudyPathId>(pathname, { path: studyRoutePath, exact: true });
+        if (studyid) {
+            store.dispatch(handleFirstTimeLoad(
+                (dispatch: Dispatch) => {
+                    // dispatch(studyListPanelActions.SET_COLUMNS({ columns: studyListPanelColumns }));
+                    dispatch<any>(openStudyPanel(studyid.params.uuid));
+                    // dispatch<any>(activateSidePanelTreeItem(categoryName));
+                    // dispatch<any>(setSidePanelBreadcrumbs(categoryName));
+                }));
+            return true;
+        }
         return false;
     });
 
-    pluginConfig.enableNewButtonMatchers.push((location: Location) => (!!matchPath(location.pathname, { path: routePath, exact: true })));
+    pluginConfig.enableNewButtonMatchers.push((location: Location) => (!!matchPath(location.pathname, { path: studyListRoutePath, exact: false })));
 
     pluginConfig.dialogs.push(<CreateStudyDialog />);
+    pluginConfig.dialogs.push(<CreatePatientDialog />);
 
     pluginConfig.middlewares.push((elms, services) => {
         elms.push(dataExplorerMiddleware(
-            new StudiesPanelMiddlewareService(services, STUDY_PANEL_ID)
+            new StudyListPanelMiddlewareService(services, STUDY_LIST_PANEL_ID)
+        ));
+        elms.push(dataExplorerMiddleware(
+            new StudyListPanelMiddlewareService(services, PATIENT_LIST_PANEL_ID)
         ));
         return elms;
     });
diff --git a/src/plugins/sample-tracker/study.tsx b/src/plugins/sample-tracker/patientList.tsx
similarity index 63%
copy from src/plugins/sample-tracker/study.tsx
copy to src/plugins/sample-tracker/patientList.tsx
index 326a2434..93975ee1 100644
--- a/src/plugins/sample-tracker/study.tsx
+++ b/src/plugins/sample-tracker/patientList.tsx
@@ -11,7 +11,6 @@ import { ProjectNameField, ProjectDescriptionField } from '~/views-components/fo
 import { dialogActions } from "~/store/dialog/dialog-actions";
 import { ServiceRepository } from "~/services/services";
 import { compose, MiddlewareAPI, Dispatch } from "redux";
-import { Card, CardContent } from "@material-ui/core";
 import { reduxForm, initialize } from 'redux-form';
 import { withDialog } from "~/store/dialog/with-dialog";
 import { RootState } from '~/store/store';
@@ -36,11 +35,15 @@ import { progressIndicatorActions } from '~/store/progress-indicator/progress-in
 import { DataExplorer as DataExplorerState, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer';
 import { FilterBuilder, joinFilters } from "~/services/api/filter-builder";
 import { updateResources } from "~/store/resources/resources-actions";
+import {
+    studyRoutePath
+} from './study';
+import { matchPath } from "react-router";
 
-const STUDY_CREATE_FORM_NAME = "studyCreateFormName";
-export const STUDY_PANEL_ID = "studyPanel";
-export const studyPanelActions = bindDataExplorerActions(STUDY_PANEL_ID);
-export const sampleTrackerStudyType = "sample_tracker:study";
+const PATIENT_CREATE_FORM_NAME = "patientCreateFormName";
+export const PATIENT_LIST_PANEL_ID = "patientListPanel";
+export const patientListPanelActions = bindDataExplorerActions(PATIENT_LIST_PANEL_ID);
+export const sampleTrackerPatientType = "sample_tracker:patient";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;
@@ -50,55 +53,67 @@ export interface ProjectCreateFormDialogData {
 
 type DialogProjectProps = WithDialogProps<{}> & InjectedFormProps<ProjectCreateFormDialogData>;
 
-const StudyAddFields = () => <span>
-    <ProjectNameField label="Study name" />
+const PatientAddFields = () => <span>
+    <ProjectNameField label="Patient name" />
     <ProjectDescriptionField />
 </span>;
 
-const DialogStudyCreate = (props: DialogProjectProps) =>
+const DialogPatientCreate = (props: DialogProjectProps) =>
     <FormDialog
-        dialogTitle='New study'
-        formFields={StudyAddFields}
-        submitLabel='Create a Study'
+        dialogTitle='Add patient'
+        formFields={PatientAddFields}
+        submitLabel='Add a patient'
         {...props}
     />;
 
-export const CreateStudyDialog = compose(
-    withDialog(STUDY_CREATE_FORM_NAME),
+export const CreatePatientDialog = compose(
+    withDialog(PATIENT_CREATE_FORM_NAME),
     reduxForm<ProjectCreateFormDialogData>({
-        form: STUDY_CREATE_FORM_NAME,
+        form: PATIENT_CREATE_FORM_NAME,
         onSubmit: (data, dispatch) => {
-            data.properties = { type: sampleTrackerStudyType };
+            data.properties = { type: sampleTrackerPatientType };
             dispatch(createProject(data));
         }
     })
-)(DialogStudyCreate);
-
+)(DialogPatientCreate);
 
-interface TrackerProps {
+export interface MenuItemProps {
     className?: string;
+    studyUuid?: string;
 }
 
-const studiesMapStateToProps = (state: RootState) => ({});
+export interface StudyPathId {
+    uuid: string;
+}
+
+export const patientsMapStateToProps = (state: RootState) => {
+    const props: MenuItemProps = {};
+    const studyid = matchPath<StudyPathId>(state.router.location!.pathname, { path: studyRoutePath, exact: true });
+    if (studyid) {
+        props.studyUuid = studyid.params.uuid;
+    }
+    return props;
+};
 
-export const openStudyCreateDialog = () =>
+const openPatientCreateDialog = (studyUuid: string) =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(initialize(STUDY_CREATE_FORM_NAME, {}));
-        dispatch(dialogActions.OPEN_DIALOG({ id: STUDY_CREATE_FORM_NAME, data: {} }));
+        dispatch(initialize(PATIENT_CREATE_FORM_NAME, { ownerUuid: studyUuid }));
+        dispatch(dialogActions.OPEN_DIALOG({ id: PATIENT_CREATE_FORM_NAME, data: {} }));
     };
 
-export const AddStudyMenuComponent = connect(studiesMapStateToProps)(
-    ({ dispatch, className }: TrackerProps & DispatchProp<any>) =>
-        <MenuItem className={className} onClick={() => dispatch(openStudyCreateDialog())}>Add Study</MenuItem >
+export const AddPatientMenuComponent = connect<{}, {}, MenuItemProps>(patientsMapStateToProps)(
+    ({ studyUuid, dispatch, className }: MenuItemProps & DispatchProp<any>) =>
+        <MenuItem className={className} onClick={() => dispatch(openPatientCreateDialog(studyUuid!))} disabled={!studyUuid}>Add Patient</MenuItem >
 );
 
-export enum StudyPanelColumnNames {
+
+enum PatientPanelColumnNames {
     NAME = "Name"
 }
 
-export const studyPanelColumns: DataColumns<string> = [
+export const PatientListPanelColumns: DataColumns<string> = [
     {
-        name: StudyPanelColumnNames.NAME,
+        name: PatientPanelColumnNames.NAME,
         selected: true,
         configurable: true,
         sortDirection: SortDirection.NONE,
@@ -107,34 +122,34 @@ export const studyPanelColumns: DataColumns<string> = [
     }
 ];
 
-export const openStudiesPanel = (dispatch: Dispatch) => {
+export const openPatientListPanel = (dispatch: Dispatch) => {
     // dispatch(propertiesActions.SET_PROPERTY({ key: PROJECT_PANEL_CURRENT_UUID, value: projectUuid }));
-    dispatch(studyPanelActions.REQUEST_ITEMS());
+    dispatch(patientListPanelActions.REQUEST_ITEMS());
 };
 
-export const StudiesMainPanel = connect(studiesMapStateToProps)(
+export interface TrackerProps {
+    className?: string;
+}
+
+export const PatientListPanel = connect(patientsMapStateToProps)(
     ({ }: TrackerProps) =>
-        <Card>
-            <CardContent>
-                <DataExplorer
-                    id={STUDY_PANEL_ID}
-                    onRowClick={(uuid: string) => { }}
-                    onRowDoubleClick={(uuid: string) => { }}
-                    onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
-                    contextMenuColumn={true}
-                    dataTableDefaultView={
-                        <DataTableDefaultView />
-                    } />
-            </CardContent>
-        </Card>);
-
-export const setItems = (listResults: ListResults<GroupResource>) =>
-    studyPanelActions.SET_ITEMS({
+        <DataExplorer
+            id={PATIENT_LIST_PANEL_ID}
+            onRowClick={(uuid: string) => { }}
+            onRowDoubleClick={(uuid: string) => { }}
+            onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
+            contextMenuColumn={true}
+            dataTableDefaultView={
+                <DataTableDefaultView />
+            } />);
+
+const setItems = (listResults: ListResults<GroupResource>) =>
+    patientListPanelActions.SET_ITEMS({
         ...listResultsToDataExplorerItemsMeta(listResults),
         items: listResults.items.map(resource => resource.uuid),
     });
 
-export const getFilters = (dataExplorer: DataExplorerState) => {
+const getFilters = (dataExplorer: DataExplorerState) => {
     //    const columns = dataExplorer.columns as DataColumns<string>;
     //    const typeFilters = serializeResourceTypeFilters(getDataExplorerColumnFilters(columns, ProjectPanelColumnNames.TYPE));
     //    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
@@ -142,7 +157,7 @@ export const getFilters = (dataExplorer: DataExplorerState) => {
     //        filterName => statusColumnFilters[filterName].selected
     //    );
     const fb = new FilterBuilder();
-    fb.addEqual("properties.type", sampleTrackerStudyType);
+    fb.addEqual("properties.type", sampleTrackerPatientType);
 
     const nameFilters = new FilterBuilder()
         .addILike("name", dataExplorer.searchValue)
@@ -154,12 +169,12 @@ export const getFilters = (dataExplorer: DataExplorerState) => {
     );
 };
 
-export const getParams = (dataExplorer: DataExplorerState) => ({
+const getParams = (dataExplorer: DataExplorerState) => ({
     ...dataExplorerToListParams(dataExplorer),
     filters: getFilters(dataExplorer),
 });
 
-export class StudiesPanelMiddlewareService extends DataExplorerMiddlewareService {
+export class PatientListPanelMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
         super(id);
     }
@@ -176,7 +191,7 @@ export class StudiesPanelMiddlewareService extends DataExplorerMiddlewareService
             api.dispatch(setItems(response));
         } catch (e) {
             api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
-            api.dispatch(studyPanelActions.SET_ITEMS({
+            api.dispatch(patientListPanelActions.SET_ITEMS({
                 items: [],
                 itemsAvailable: 0,
                 page: 0,
diff --git a/src/plugins/sample-tracker/study.tsx b/src/plugins/sample-tracker/study.tsx
index 326a2434..1b330920 100644
--- a/src/plugins/sample-tracker/study.tsx
+++ b/src/plugins/sample-tracker/study.tsx
@@ -3,186 +3,30 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import { InjectedFormProps } from 'redux-form';
-import { WithDialogProps } from '~/store/dialog/with-dialog';
-import { ProjectCreateFormDialogData } from '~/store/projects/project-create-actions';
-import { FormDialog } from '~/components/form-dialog/form-dialog';
-import { ProjectNameField, ProjectDescriptionField } from '~/views-components/form-fields/project-form-fields';
-import { dialogActions } from "~/store/dialog/dialog-actions";
-import { ServiceRepository } from "~/services/services";
-import { compose, MiddlewareAPI, Dispatch } from "redux";
-import { Card, CardContent } from "@material-ui/core";
-import { reduxForm, initialize } from 'redux-form';
-import { withDialog } from "~/store/dialog/with-dialog";
+import { connect } from 'react-redux';
+import { studyListRoutePath } from './studyList';
+import { Dispatch } from "redux";
+import { propertiesActions } from "~/store/properties/properties-actions";
+import { getProperty } from '~/store/properties/properties';
 import { RootState } from '~/store/store';
-import { DispatchProp, connect } from 'react-redux';
-import { MenuItem } from "@material-ui/core";
-import { createProject } from "~/store/workbench/workbench-actions";
-import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
-import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
-import { DataColumns } from '~/components/data-table/data-table';
-import { createTree } from '~/models/tree';
-import { ResourceName } from '~/views-components/data-explorer/renderers';
-import { SortDirection } from '~/components/data-table/data-column';
-import { bindDataExplorerActions } from "~/store/data-explorer/data-explorer-action";
-import {
-    DataExplorerMiddlewareService,
-    listResultsToDataExplorerItemsMeta,
-    dataExplorerToListParams
-} from '~/store/data-explorer/data-explorer-middleware-service';
-import { GroupResource } from "~/models/group";
-import { ListResults } from '~/services/common-service/common-service';
-import { progressIndicatorActions } from '~/store/progress-indicator/progress-indicator-actions.ts';
-import { DataExplorer as DataExplorerState, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer';
-import { FilterBuilder, joinFilters } from "~/services/api/filter-builder";
-import { updateResources } from "~/store/resources/resources-actions";
 
-const STUDY_CREATE_FORM_NAME = "studyCreateFormName";
-export const STUDY_PANEL_ID = "studyPanel";
-export const studyPanelActions = bindDataExplorerActions(STUDY_PANEL_ID);
-export const sampleTrackerStudyType = "sample_tracker:study";
+export const studyRoutePath = studyListRoutePath + "/:uuid";
+const STUDY_PANEL_CURRENT_UUID = "StudyPanelCurrentUUID";
 
-export interface ProjectCreateFormDialogData {
-    ownerUuid: string;
-    name: string;
-    description: string;
-}
-
-type DialogProjectProps = WithDialogProps<{}> & InjectedFormProps<ProjectCreateFormDialogData>;
-
-const StudyAddFields = () => <span>
-    <ProjectNameField label="Study name" />
-    <ProjectDescriptionField />
-</span>;
-
-const DialogStudyCreate = (props: DialogProjectProps) =>
-    <FormDialog
-        dialogTitle='New study'
-        formFields={StudyAddFields}
-        submitLabel='Create a Study'
-        {...props}
-    />;
-
-export const CreateStudyDialog = compose(
-    withDialog(STUDY_CREATE_FORM_NAME),
-    reduxForm<ProjectCreateFormDialogData>({
-        form: STUDY_CREATE_FORM_NAME,
-        onSubmit: (data, dispatch) => {
-            data.properties = { type: sampleTrackerStudyType };
-            dispatch(createProject(data));
-        }
-    })
-)(DialogStudyCreate);
-
-
-interface TrackerProps {
-    className?: string;
-}
-
-const studiesMapStateToProps = (state: RootState) => ({});
-
-export const openStudyCreateDialog = () =>
-    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(initialize(STUDY_CREATE_FORM_NAME, {}));
-        dispatch(dialogActions.OPEN_DIALOG({ id: STUDY_CREATE_FORM_NAME, data: {} }));
+export const openStudyPanel = (projectUuid: string) =>
+    (dispatch: Dispatch) => {
+        dispatch(propertiesActions.SET_PROPERTY({ key: STUDY_PANEL_CURRENT_UUID, value: projectUuid }));
+        // dispatch(studyListPanelActions.REQUEST_ITEMS());
     };
 
-export const AddStudyMenuComponent = connect(studiesMapStateToProps)(
-    ({ dispatch, className }: TrackerProps & DispatchProp<any>) =>
-        <MenuItem className={className} onClick={() => dispatch(openStudyCreateDialog())}>Add Study</MenuItem >
-);
-
-export enum StudyPanelColumnNames {
-    NAME = "Name"
+interface StudyProps {
+    studyUuid: string;
 }
 
-export const studyPanelColumns: DataColumns<string> = [
-    {
-        name: StudyPanelColumnNames.NAME,
-        selected: true,
-        configurable: true,
-        sortDirection: SortDirection.NONE,
-        filters: createTree(),
-        render: uuid => <ResourceName uuid={uuid} />
-    }
-];
-
-export const openStudiesPanel = (dispatch: Dispatch) => {
-    // dispatch(propertiesActions.SET_PROPERTY({ key: PROJECT_PANEL_CURRENT_UUID, value: projectUuid }));
-    dispatch(studyPanelActions.REQUEST_ITEMS());
-};
-
-export const StudiesMainPanel = connect(studiesMapStateToProps)(
-    ({ }: TrackerProps) =>
-        <Card>
-            <CardContent>
-                <DataExplorer
-                    id={STUDY_PANEL_ID}
-                    onRowClick={(uuid: string) => { }}
-                    onRowDoubleClick={(uuid: string) => { }}
-                    onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
-                    contextMenuColumn={true}
-                    dataTableDefaultView={
-                        <DataTableDefaultView />
-                    } />
-            </CardContent>
-        </Card>);
-
-export const setItems = (listResults: ListResults<GroupResource>) =>
-    studyPanelActions.SET_ITEMS({
-        ...listResultsToDataExplorerItemsMeta(listResults),
-        items: listResults.items.map(resource => resource.uuid),
-    });
-
-export const getFilters = (dataExplorer: DataExplorerState) => {
-    //    const columns = dataExplorer.columns as DataColumns<string>;
-    //    const typeFilters = serializeResourceTypeFilters(getDataExplorerColumnFilters(columns, ProjectPanelColumnNames.TYPE));
-    //    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
-    //    const activeStatusFilter = Object.keys(statusColumnFilters).find(
-    //        filterName => statusColumnFilters[filterName].selected
-    //    );
-    const fb = new FilterBuilder();
-    fb.addEqual("properties.type", sampleTrackerStudyType);
-
-    const nameFilters = new FilterBuilder()
-        .addILike("name", dataExplorer.searchValue)
-        .getFilters();
-
-    return joinFilters(
-        fb.getFilters(),
-        nameFilters,
-    );
-};
-
-export const getParams = (dataExplorer: DataExplorerState) => ({
-    ...dataExplorerToListParams(dataExplorer),
-    filters: getFilters(dataExplorer),
+export const studyMapStateToProps = (state: RootState) => ({
+    studyUuid: getProperty(STUDY_PANEL_CURRENT_UUID)(state.properties),
 });
 
-export class StudiesPanelMiddlewareService extends DataExplorerMiddlewareService {
-    constructor(private services: ServiceRepository, id: string) {
-        super(id);
-    }
-
-    async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
-        const state = api.getState();
-        const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
-
-        try {
-            api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
-            const response = await this.services.groupsService.list(getParams(dataExplorer));
-            api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
-            api.dispatch(updateResources(response.items));
-            api.dispatch(setItems(response));
-        } catch (e) {
-            api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
-            api.dispatch(studyPanelActions.SET_ITEMS({
-                items: [],
-                itemsAvailable: 0,
-                page: 0,
-                rowsPerPage: dataExplorer.rowsPerPage
-            }));
-            // api.dispatch(couldNotFetchProjectContents());
-        }
-    }
-}
+export const StudyMainPanel = connect(studyMapStateToProps)(
+    ({ studyUuid }: StudyProps) =>
+        <p>Main panel for study {studyUuid}</p>);
diff --git a/src/plugins/sample-tracker/study.tsx b/src/plugins/sample-tracker/studyList.tsx
similarity index 70%
copy from src/plugins/sample-tracker/study.tsx
copy to src/plugins/sample-tracker/studyList.tsx
index 326a2434..00ded8dd 100644
--- a/src/plugins/sample-tracker/study.tsx
+++ b/src/plugins/sample-tracker/studyList.tsx
@@ -11,7 +11,6 @@ import { ProjectNameField, ProjectDescriptionField } from '~/views-components/fo
 import { dialogActions } from "~/store/dialog/dialog-actions";
 import { ServiceRepository } from "~/services/services";
 import { compose, MiddlewareAPI, Dispatch } from "redux";
-import { Card, CardContent } from "@material-ui/core";
 import { reduxForm, initialize } from 'redux-form';
 import { withDialog } from "~/store/dialog/with-dialog";
 import { RootState } from '~/store/store';
@@ -22,7 +21,6 @@ import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
 import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
 import { DataColumns } from '~/components/data-table/data-table';
 import { createTree } from '~/models/tree';
-import { ResourceName } from '~/views-components/data-explorer/renderers';
 import { SortDirection } from '~/components/data-table/data-column';
 import { bindDataExplorerActions } from "~/store/data-explorer/data-explorer-action";
 import {
@@ -36,11 +34,13 @@ import { progressIndicatorActions } from '~/store/progress-indicator/progress-in
 import { DataExplorer as DataExplorerState, getDataExplorer } from '~/store/data-explorer/data-explorer-reducer';
 import { FilterBuilder, joinFilters } from "~/services/api/filter-builder";
 import { updateResources } from "~/store/resources/resources-actions";
+import { ResourceName } from '~/views-components/data-explorer/renderers';
 
 const STUDY_CREATE_FORM_NAME = "studyCreateFormName";
-export const STUDY_PANEL_ID = "studyPanel";
-export const studyPanelActions = bindDataExplorerActions(STUDY_PANEL_ID);
+export const STUDY_LIST_PANEL_ID = "studyPanel";
+export const studyListPanelActions = bindDataExplorerActions(STUDY_LIST_PANEL_ID);
 export const sampleTrackerStudyType = "sample_tracker:study";
+export const studyListRoutePath = "/sample_tracker_Studies";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;
@@ -81,7 +81,7 @@ interface TrackerProps {
 
 const studiesMapStateToProps = (state: RootState) => ({});
 
-export const openStudyCreateDialog = () =>
+const openStudyCreateDialog = () =>
     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(initialize(STUDY_CREATE_FORM_NAME, {}));
         dispatch(dialogActions.OPEN_DIALOG({ id: STUDY_CREATE_FORM_NAME, data: {} }));
@@ -92,11 +92,38 @@ export const AddStudyMenuComponent = connect(studiesMapStateToProps)(
         <MenuItem className={className} onClick={() => dispatch(openStudyCreateDialog())}>Add Study</MenuItem >
 );
 
-export enum StudyPanelColumnNames {
+enum StudyPanelColumnNames {
     NAME = "Name"
 }
 
-export const studyPanelColumns: DataColumns<string> = [
+/* const renderName = (dispatch: Dispatch, item: GroupContentsResource) =>
+ *     <Grid container alignItems="center" wrap="nowrap" spacing={16}>
+ *         <Grid item>
+ *             {renderIcon(item)}
+ *         </Grid>
+ *         <Grid item>
+ *             <Typography color="primary" style={{ width: 'auto', cursor: 'pointer' }} onClick={() => dispatch<any>(navigateTo(item.uuid))}>
+ *                 {item.kind === ResourceKind.PROJECT || item.kind === ResourceKind.COLLECTION
+ *                     ? <IllegalNamingWarning name={item.name} />
+ *                     : null}
+ *                 {item.name}
+ *             </Typography>
+ *         </Grid>
+ *         <Grid item>
+ *             <Typography variant="caption">
+ *                 <FavoriteStar resourceUuid={item.uuid} />
+ *                 <PublicFavoriteStar resourceUuid={item.uuid} />
+ *             </Typography>
+ *         </Grid>
+ *     </Grid>;
+ *
+ * const ResourceName = connect(
+ *     (state: RootState, props: { uuid: string }) => {
+ *         const resource = getResource<GroupResource>(props.uuid)(state.resources);
+ *         return resource;
+ *     })((resource: GroupResource & DispatchProp<any>) => renderName(resource.dispatch, resource));
+ *  */
+export const studyListPanelColumns: DataColumns<string> = [
     {
         name: StudyPanelColumnNames.NAME,
         selected: true,
@@ -107,34 +134,31 @@ export const studyPanelColumns: DataColumns<string> = [
     }
 ];
 
-export const openStudiesPanel = (dispatch: Dispatch) => {
+export const openStudyListPanel = (dispatch: Dispatch) => {
     // dispatch(propertiesActions.SET_PROPERTY({ key: PROJECT_PANEL_CURRENT_UUID, value: projectUuid }));
-    dispatch(studyPanelActions.REQUEST_ITEMS());
+    dispatch(studyListPanelActions.REQUEST_ITEMS());
 };
 
-export const StudiesMainPanel = connect(studiesMapStateToProps)(
+export const StudyListMainPanel = connect(studiesMapStateToProps)(
     ({ }: TrackerProps) =>
-        <Card>
-            <CardContent>
-                <DataExplorer
-                    id={STUDY_PANEL_ID}
-                    onRowClick={(uuid: string) => { }}
-                    onRowDoubleClick={(uuid: string) => { }}
-                    onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
-                    contextMenuColumn={true}
-                    dataTableDefaultView={
-                        <DataTableDefaultView />
-                    } />
-            </CardContent>
-        </Card>);
-
-export const setItems = (listResults: ListResults<GroupResource>) =>
-    studyPanelActions.SET_ITEMS({
+        <DataExplorer
+            id={STUDY_LIST_PANEL_ID}
+            onRowClick={(uuid: string) => { }}
+            onRowDoubleClick={(uuid: string) => { }}
+            onContextMenu={(event: React.MouseEvent<HTMLElement>, resourceUuid: string) => { }}
+            contextMenuColumn={true}
+            dataTableDefaultView={
+                <DataTableDefaultView />
+            } />);
+
+
+const setItems = (listResults: ListResults<GroupResource>) =>
+    studyListPanelActions.SET_ITEMS({
         ...listResultsToDataExplorerItemsMeta(listResults),
         items: listResults.items.map(resource => resource.uuid),
     });
 
-export const getFilters = (dataExplorer: DataExplorerState) => {
+const getFilters = (dataExplorer: DataExplorerState) => {
     //    const columns = dataExplorer.columns as DataColumns<string>;
     //    const typeFilters = serializeResourceTypeFilters(getDataExplorerColumnFilters(columns, ProjectPanelColumnNames.TYPE));
     //    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
@@ -154,12 +178,12 @@ export const getFilters = (dataExplorer: DataExplorerState) => {
     );
 };
 
-export const getParams = (dataExplorer: DataExplorerState) => ({
+const getParams = (dataExplorer: DataExplorerState) => ({
     ...dataExplorerToListParams(dataExplorer),
     filters: getFilters(dataExplorer),
 });
 
-export class StudiesPanelMiddlewareService extends DataExplorerMiddlewareService {
+export class StudyListPanelMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
         super(id);
     }
@@ -172,11 +196,14 @@ export class StudiesPanelMiddlewareService extends DataExplorerMiddlewareService
             api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
             const response = await this.services.groupsService.list(getParams(dataExplorer));
             api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+            for (const i of response.items) {
+                i.uuid = studyListRoutePath + "/" + i.uuid;
+            }
             api.dispatch(updateResources(response.items));
             api.dispatch(setItems(response));
         } catch (e) {
             api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
-            api.dispatch(studyPanelActions.SET_ITEMS({
+            api.dispatch(studyListPanelActions.SET_ITEMS({
                 items: [],
                 itemsAvailable: 0,
                 page: 0,

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list