Initialize groups panel store and view component
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Mon, 10 Dec 2018 16:34:32 +0000 (17:34 +0100)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Mon, 10 Dec 2018 16:34:32 +0000 (17:34 +0100)
Feature #14505

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/store/groups-panel/groups-panel-actions.ts [new file with mode: 0644]
src/store/groups-panel/groups-panel-middleware-service.ts [new file with mode: 0644]
src/store/store.ts
src/store/workbench/workbench-actions.ts
src/views/groups-panel/groups-panel.tsx [new file with mode: 0644]
src/views/workbench/workbench.tsx

diff --git a/src/store/groups-panel/groups-panel-actions.ts b/src/store/groups-panel/groups-panel-actions.ts
new file mode 100644 (file)
index 0000000..5adce5c
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { bindDataExplorerActions } from "~/store/data-explorer/data-explorer-action";
+
+export const GROUPS_PANEL_ID = "groupsPanel";
+export const GroupsPanelActions = bindDataExplorerActions(GROUPS_PANEL_ID);
+
+export const loadGroupsPanel = () => GroupsPanelActions.REQUEST_ITEMS();
diff --git a/src/store/groups-panel/groups-panel-middleware-service.ts b/src/store/groups-panel/groups-panel-middleware-service.ts
new file mode 100644 (file)
index 0000000..9d43b11
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch, MiddlewareAPI } from "redux";
+import { DataExplorerMiddlewareService, listResultsToDataExplorerItemsMeta, dataExplorerToListParams } from "~/store/data-explorer/data-explorer-middleware-service";
+import { RootState } from "~/store/store";
+import { ServiceRepository } from "~/services/services";
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
+import { getDataExplorer } from "~/store/data-explorer/data-explorer-reducer";
+import { GroupsPanelActions } from '~/store/groups-panel/groups-panel-actions';
+import { FilterBuilder } from '~/services/api/filter-builder';
+import { updateResources } from '~/store/resources/resources-actions';
+
+export class GroupsPanelMiddlewareService extends DataExplorerMiddlewareService {
+
+    constructor(private services: ServiceRepository, id: string) {
+        super(id);
+    }
+
+    async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+
+        const dataExplorer = getDataExplorer(api.getState().dataExplorer, this.getId());
+
+        if (!dataExplorer) {
+
+            api.dispatch(groupsPanelDataExplorerIsNotSet());
+
+        } else {
+
+            try {
+
+                const filters = new FilterBuilder()
+                    .addEqual('groupClass', null)
+                    .getFilters();
+
+                const response = await this.services.groupsService
+                    .list({
+                        ...dataExplorerToListParams(dataExplorer),
+                        filters,
+                    });
+
+                api.dispatch(updateResources(response.items));
+
+                api.dispatch(GroupsPanelActions.SET_ITEMS({
+                    ...listResultsToDataExplorerItemsMeta(response),
+                    items: response.items.map(item => item.uuid),
+                }));
+
+
+            } catch (e) {
+
+                api.dispatch(couldNotFetchFavoritesContents());
+
+            }
+        }
+    }
+}
+
+const groupsPanelDataExplorerIsNotSet = () =>
+    snackbarActions.OPEN_SNACKBAR({
+        message: 'Groups panel is not ready.'
+    });
+
+const couldNotFetchFavoritesContents = () =>
+    snackbarActions.OPEN_SNACKBAR({
+        message: 'Could not fetch groups.',
+        kind: SnackbarKind.ERROR
+    });
index 2b0ada81afec1a8869a7629ccf89546a20982172..c04789d7723992ddb9b34c2b2d740a9782e179f9 100644 (file)
@@ -50,6 +50,8 @@ import { UserMiddlewareService } from '~/store/users/user-panel-middleware-servi
 import { USERS_PANEL_ID } from '~/store/users/users-actions';
 import { computeNodesReducer } from '~/store/compute-nodes/compute-nodes-reducer';
 import { apiClientAuthorizationsReducer } from '~/store/api-client-authorizations/api-client-authorizations-reducer';
+import { GroupsPanelMiddlewareService } from '~/store/groups-panel/groups-panel-middleware-service';
+import { GROUPS_PANEL_ID } from '~/store/groups-panel/groups-panel-actions';
 
 const composeEnhancers =
     (process.env.NODE_ENV === 'development' &&
@@ -84,6 +86,9 @@ export function configureStore(history: History, services: ServiceRepository): R
     const userPanelMiddleware = dataExplorerMiddleware(
         new UserMiddlewareService(services, USERS_PANEL_ID)
     );
+    const groupsPanelMiddleware = dataExplorerMiddleware(
+        new GroupsPanelMiddlewareService(services, GROUPS_PANEL_ID)
+    );
 
     const middlewares: Middleware[] = [
         routerMiddleware(history),
@@ -94,7 +99,8 @@ export function configureStore(history: History, services: ServiceRepository): R
         searchResultsPanelMiddleware,
         sharedWithMePanelMiddleware,
         workflowPanelMiddleware,
-        userPanelMiddleware
+        userPanelMiddleware,
+        groupsPanelMiddleware,
     ];
     const enhancer = composeEnhancers(applyMiddleware(...middlewares));
     return createStore(rootReducer, enhancer);
index e0195f9409925f88de46241c4ab058920d2497e8..2ae590295412a10aec01855e01994c30c8b2a0d2 100644 (file)
@@ -62,6 +62,8 @@ import { loadUsersPanel, userBindedActions } from '~/store/users/users-actions';
 import { userPanelColumns } from '~/views/user-panel/user-panel';
 import { loadComputeNodesPanel } from '~/store/compute-nodes/compute-nodes-actions';
 import { loadApiClientAuthorizationsPanel } from '~/store/api-client-authorizations/api-client-authorizations-actions';
+import * as groupPanelActions from '~/store/groups-panel/groups-panel-actions';
+import { groupsPanelColumns } from '~/views/groups-panel/groups-panel';
 
 export const WORKBENCH_LOADING_SCREEN = 'workbenchLoadingScreen';
 
@@ -96,6 +98,7 @@ export const loadWorkbench = () =>
                 dispatch(workflowPanelActions.SET_COLUMNS({ columns: workflowPanelColumns }));
                 dispatch(searchResultsPanelActions.SET_COLUMNS({ columns: searchResultsPanelColumns }));
                 dispatch(userBindedActions.SET_COLUMNS({ columns: userPanelColumns }));
+                dispatch(groupPanelActions.GroupsPanelActions.SET_COLUMNS({ columns: groupsPanelColumns }));
                 dispatch<any>(initSidePanelTree());
                 if (router.location) {
                     const match = matchRootRoute(router.location.pathname);
@@ -448,6 +451,7 @@ export const loadApiClientAuthorizations = handleFirstTimeLoad(
 export const loadGroupsPanel = handleFirstTimeLoad(
     (dispatch: Dispatch<any>) => {
         dispatch(setBreadcrumbs([{ label: 'Groups' }]));
+        dispatch(groupPanelActions.loadGroupsPanel());
     });
 
 const finishLoadingProject = (project: GroupContentsResource | string) =>
diff --git a/src/views/groups-panel/groups-panel.tsx b/src/views/groups-panel/groups-panel.tsx
new file mode 100644 (file)
index 0000000..c404f1e
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import withStyles from "@material-ui/core/styles/withStyles";
+import { DispatchProp, connect } from 'react-redux';
+import { RouteComponentProps } from 'react-router';
+import { StyleRulesCallback, WithStyles, Typography } from "@material-ui/core";
+
+import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
+import { DataColumns } from '~/components/data-table/data-table';
+import { RootState } from '~/store/store';
+import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
+import { ContainerRequestState } from '~/models/container-request';
+import { SortDirection } from '~/components/data-table/data-column';
+import { ResourceKind, Resource } from '~/models/resource';
+import { ResourceFileSize, ResourceLastModifiedDate, ProcessStatus, ResourceType, ResourceOwner } from '~/views-components/data-explorer/renderers';
+import { ProjectIcon } from '~/components/icon/icon';
+import { ResourceName } from '~/views-components/data-explorer/renderers';
+import { ResourcesState, getResource } from '~/store/resources/resources';
+import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
+import { resourceKindToContextMenuKind, openContextMenu } from '~/store/context-menu/context-menu-actions';
+import { ProjectResource } from '~/models/project';
+import { navigateTo } from '~/store/navigation/navigation-action';
+import { getProperty } from '~/store/properties/properties';
+import { PROJECT_PANEL_CURRENT_UUID } from '~/store/project-panel/project-panel-action';
+import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
+import { ArvadosTheme } from "~/common/custom-theme";
+import { createTree } from '~/models/tree';
+import { getInitialResourceTypeFilters } from '~/store/resource-type-filters/resource-type-filters';
+import { GROUPS_PANEL_ID } from '~/store/groups-panel/groups-panel-actions';
+import { noop } from 'lodash/fp';
+import { GroupResource } from '~/models/group';
+
+export enum ProjectPanelColumnNames {
+    GROUP = "Name",
+    OWNER = "Owner",
+    MEMBERS = "Members",
+}
+
+export const groupsPanelColumns: DataColumns<string> = [
+    {
+        name: ProjectPanelColumnNames.GROUP,
+        selected: true,
+        configurable: true,
+        sortDirection: SortDirection.ASC,
+        filters: createTree(),
+        render: uuid => <ResourceName uuid={uuid} />
+    },
+    {
+        name: ProjectPanelColumnNames.OWNER,
+        selected: true,
+        configurable: true,
+        filters: createTree(),
+        render: uuid => <ResourceOwner uuid={uuid} />,
+    },
+    {
+        name: ProjectPanelColumnNames.MEMBERS,
+        selected: true,
+        configurable: true,
+        filters: createTree(),
+        render: uuid => <span>0</span>,
+    },
+];
+
+export class GroupsPanel extends React.Component {
+
+    render() {
+        return (
+            <DataExplorer
+                id={GROUPS_PANEL_ID}
+                onRowClick={noop}
+                onRowDoubleClick={noop}
+                onContextMenu={noop}
+                contextMenuColumn={true} />
+        );
+    }
+}
index f4124e26d33829f17561e5af1792174c17fb483b..468797eb622bd4548b4ef6eb43b870344dde68fd 100644 (file)
@@ -75,6 +75,7 @@ import { UserPanel } from '~/views/user-panel/user-panel';
 import { UserAttributesDialog } from '~/views-components/user-dialog/attributes-dialog';
 import { CreateUserDialog } from '~/views-components/dialog-forms/create-user-dialog';
 import { HelpApiClientAuthorizationDialog } from '~/views-components/api-client-authorizations-dialog/help-dialog';
+import { GroupsPanel } from '~/views/groups-panel/groups-panel';
 
 type CssRules = 'root' | 'container' | 'splitter' | 'asidePanel' | 'contentWrapper' | 'content';
 
@@ -152,7 +153,7 @@ export const WorkbenchPanel =
                                 <Route path={Routes.COMPUTE_NODES} component={ComputeNodePanel} />
                                 <Route path={Routes.API_CLIENT_AUTHORIZATIONS} component={ApiClientAuthorizationPanel} />
                                 <Route path={Routes.MY_ACCOUNT} component={MyAccountPanel} />
-                                <Route path={Routes.GROUPS} component={() => <h1>Groups panel</h1>} />
+                                <Route path={Routes.GROUPS} component={GroupsPanel} />
                             </Switch>
                         </Grid>
                     </Grid>