Adjust for new code structure II
authorDaniel Kos <daniel.kos@contractors.roche.com>
Sun, 2 Sep 2018 09:13:19 +0000 (11:13 +0200)
committerDaniel Kos <daniel.kos@contractors.roche.com>
Sun, 2 Sep 2018 17:13:58 +0000 (19:13 +0200)
Feature #13828

Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos@contractors.roche.com>

src/store/data-explorer/data-explorer-middleware-service.ts
src/store/trash-panel/trash-panel-middleware-service.ts
src/store/trash/trash-actions.ts
src/store/workbench/workbench-actions.ts
src/views-components/data-explorer/renderers.tsx
src/views/project-panel/project-panel.tsx
src/views/trash-panel/trash-panel-item.ts [deleted file]
src/views/trash-panel/trash-panel.tsx

index 059c078429833487c553aeb744eaf75ab8a771c7..7ad74f2f32449dbb78b0fa766c665a142c73cd74 100644 (file)
@@ -7,7 +7,7 @@ import { RootState } from "../store";
 import { DataColumns } from "~/components/data-table/data-table";
 import { DataTableFilterItem } from "~/components/data-table-filters/data-table-filters";
 import { DataExplorer } from './data-explorer-reducer';
-import { ListArguments, ListResults } from '~/common/api/common-resource-service';
+import { ListResults } from '~/common/api/common-resource-service';
 
 export abstract class DataExplorerMiddlewareService {
     protected readonly id: string;
@@ -42,4 +42,4 @@ export const listResultsToDataExplorerItemsMeta = <R>({ itemsAvailable, offset,
     itemsAvailable,
     page: Math.floor(offset / limit),
     rowsPerPage: limit
-});
\ No newline at end of file
+});
index 85bc0ad7739c73a5ac1066835685d3d178b3197e..d81b1b085902e5ad84fb902fa81c2799d5357f71 100644 (file)
@@ -2,7 +2,10 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { DataExplorerMiddlewareService } from "../data-explorer/data-explorer-middleware-service";
+import {
+    DataExplorerMiddlewareService, dataExplorerToListParams,
+    listResultsToDataExplorerItemsMeta
+} from "../data-explorer/data-explorer-middleware-service";
 import { RootState } from "../store";
 import { DataColumns } from "~/components/data-table/data-table";
 import { ServiceRepository } from "~/services/services";
@@ -11,12 +14,15 @@ import { FilterBuilder } from "~/common/api/filter-builder";
 import { trashPanelActions } from "./trash-panel-action";
 import { Dispatch, MiddlewareAPI } from "redux";
 import { OrderBuilder, OrderDirection } from "~/common/api/order-builder";
-import { GroupContentsResourcePrefix } from "~/services/groups-service/groups-service";
-import { resourceToDataItem, TrashPanelItem } from "~/views/trash-panel/trash-panel-item";
+import { GroupContentsResource, GroupContentsResourcePrefix } from "~/services/groups-service/groups-service";
 import { TrashPanelColumnNames, TrashPanelFilter } from "~/views/trash-panel/trash-panel";
 import { ProjectResource } from "~/models/project";
 import { ProjectPanelColumnNames } from "~/views/project-panel/project-panel";
 import { updateFavorites } from "~/store/favorites/favorites-actions";
+import { TrashResource } from "~/models/resource";
+import { ListResults } from "~/common/api/common-resource-service";
+import { snackbarActions } from "~/store/snackbar/snackbar-actions";
+import { updateResources } from "~/store/resources/resources-actions";
 
 export class TrashPanelMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
@@ -25,7 +31,7 @@ export class TrashPanelMiddlewareService extends DataExplorerMiddlewareService {
 
     requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
         const dataExplorer = api.getState().dataExplorer[this.getId()];
-        const columns = dataExplorer.columns as DataColumns<TrashPanelItem, TrashPanelFilter>;
+        const columns = dataExplorer.columns as DataColumns<string, TrashPanelFilter>;
         const sortColumn = dataExplorer.columns.find(c => c.sortDirection !== SortDirection.NONE);
         const typeFilters = this.getColumnFilters(columns, TrashPanelColumnNames.TYPE);
 
@@ -46,8 +52,7 @@ export class TrashPanelMiddlewareService extends DataExplorerMiddlewareService {
 
         this.services.groupsService
             .contents(userUuid, {
-                limit: dataExplorer.rowsPerPage,
-                offset: dataExplorer.page * dataExplorer.rowsPerPage,
+                ...dataExplorerToListParams(dataExplorer),
                 order: order.getOrder(),
                 filters: new FilterBuilder()
                     .addIsA("uuid", typeFilters.map(f => f.type))
@@ -57,22 +62,25 @@ export class TrashPanelMiddlewareService extends DataExplorerMiddlewareService {
                 recursive: true,
                 includeTrash: true
             })
-            .then(response => {
+            .then((listResults: ListResults<GroupContentsResource>) => {
+                const items = listResults.items
+                    .filter(it => (it as TrashResource).isTrashed)
+                    .map(it => it.uuid);
+
                 api.dispatch(trashPanelActions.SET_ITEMS({
-                    items: response.items.map(resourceToDataItem).filter(it => it.isTrashed),
-                    itemsAvailable: response.itemsAvailable,
-                    page: Math.floor(response.offset / response.limit),
-                    rowsPerPage: response.limit
+                    ...listResultsToDataExplorerItemsMeta(listResults),
+                    items
                 }));
-                api.dispatch<any>(updateFavorites(response.items.map(item => item.uuid)));
+                api.dispatch<any>(updateFavorites(items));
+                api.dispatch(updateResources(listResults.items));
             })
             .catch(() => {
-                api.dispatch(trashPanelActions.SET_ITEMS({
-                    items: [],
-                    itemsAvailable: 0,
-                    page: 0,
-                    rowsPerPage: dataExplorer.rowsPerPage
-                }));
+                api.dispatch(couldNotFetchTrashContents());
             });
     }
 }
+
+const couldNotFetchTrashContents = () =>
+    snackbarActions.OPEN_SNACKBAR({
+        message: 'Could not fetch trash contents.'
+    });
index 97d81853d0a6a5eb740548c4290787d37a3f2514..d102f242554bdb4f1016ff5b23fd76d72a2707cf 100644 (file)
@@ -7,12 +7,14 @@ import { RootState } from "~/store/store";
 import { ServiceRepository } from "~/services/services";
 import { snackbarActions } from "~/store/snackbar/snackbar-actions";
 import { trashPanelActions } from "~/store/trash-panel/trash-panel-action";
+import { reloadProjectMatchingUuid } from "~/store/workbench/workbench-actions";
 
 export const toggleProjectTrashed = (resource: { uuid: string; name: string, isTrashed?: boolean, ownerUuid?: string }) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<any> => {
         dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Working..." }));
         if (resource.isTrashed) {
             return services.groupsService.untrash(resource.uuid).then(() => {
+                dispatch<any>(reloadProjectMatchingUuid([resource.uuid]));
                 // dispatch<any>(getProjectList(resource.ownerUuid)).then(() => {
                 //     dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(SidePanelId.PROJECTS));
                 //     dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: resource.ownerUuid!!, open: true, recursive: true }));
@@ -26,6 +28,7 @@ export const toggleProjectTrashed = (resource: { uuid: string; name: string, isT
             });
         } else {
             return services.groupsService.trash(resource.uuid).then(() => {
+                dispatch<any>(reloadProjectMatchingUuid([resource.uuid]));
                 // dispatch<any>(getProjectList(resource.ownerUuid)).then(() => {
                 //     dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: resource.ownerUuid!!, open: true, recursive: true }));
                 // });
@@ -43,6 +46,7 @@ export const toggleCollectionTrashed = (resource: { uuid: string; name: string,
         dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Working..." }));
         if (resource.isTrashed) {
             return services.collectionService.untrash(resource.uuid).then(() => {
+                dispatch<any>(reloadProjectMatchingUuid([resource.uuid]));
                 // dispatch<any>(getProjectList(resource.ownerUuid)).then(() => {
                 //     dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(SidePanelId.PROJECTS));
                 //     dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: resource.ownerUuid!!, open: true, recursive: true }));
index 012ef90fa7d87bf712167be2eb86d2ec30297abd..1ff3a5b56b1297d8e9fa66ba2003ade21656b723 100644 (file)
@@ -207,7 +207,7 @@ export const couldNotLoadUser = snackbarActions.OPEN_SNACKBAR({
     message: 'Could not load user'
 });
 
-const reloadProjectMatchingUuid = (matchingUuids: string[]) =>
+export const reloadProjectMatchingUuid = (matchingUuids: string[]) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const currentProjectPanelUuid = getProjectPanelCurrentUuid(getState());
         if (currentProjectPanelUuid && matchingUuids.some(uuid => uuid === currentProjectPanelUuid)) {
index 390e601f9dbd8bac5e74967f316db3211c35163f..2e1d608c20d75d97f758692ebd4e97ad880a0133 100644 (file)
@@ -5,13 +5,13 @@
 import * as React from 'react';
 import { Grid, Typography } from '@material-ui/core';
 import { FavoriteStar } from '../favorite-star/favorite-star';
-import { ResourceKind } from '~/models/resource';
+import { ResourceKind, TrashResource } from '~/models/resource';
 import { ProjectIcon, CollectionIcon, ProcessIcon, DefaultIcon } from '~/components/icon/icon';
 import { formatDate, formatFileSize } from '~/common/formatters';
 import { resourceLabel } from '~/common/labels';
 import { connect } from 'react-redux';
 import { RootState } from '~/store/store';
-import { getResource } from '../../store/resources/resources';
+import { getResource } from '~/store/resources/resources';
 import { GroupContentsResource } from '~/services/groups-service/groups-service';
 import { ProcessResource } from '~/models/process';
 
@@ -62,6 +62,18 @@ export const ResourceLastModifiedDate = connect(
         return { date: resource ? resource.modifiedAt : '' };
     })((props: { date: string }) => renderDate(props.date));
 
+export const ResourceTrashDate = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource(props.uuid)(state.resources) as TrashResource | undefined;
+        return { date: resource ? resource.trashAt : '' };
+    })((props: { date: string }) => renderDate(props.date));
+
+export const ResourceDeleteDate = connect(
+    (state: RootState, props: { uuid: string }) => {
+        const resource = getResource(props.uuid)(state.resources) as TrashResource | undefined;
+        return { date: resource ? resource.deleteAt : '' };
+    })((props: { date: string }) => renderDate(props.date));
+
 export const renderFileSize = (fileSize?: number) =>
     <Typography noWrap>
         {formatFileSize(fileSize)}
index 622c5d8264cd1a3e548ecb40f5b0ff9e0f115b80..ebaba83947753340d564bcef80e948994cd9b7b0 100644 (file)
@@ -10,6 +10,7 @@ import { DataColumns } from '~/components/data-table/data-table';
 import { RouteComponentProps } from 'react-router';
 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 } from '~/models/resource';
 import { resourceLabel } from '~/common/labels';
@@ -17,16 +18,15 @@ import { ArvadosTheme } from '~/common/custom-theme';
 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 } from '~/store/resources/resources';
+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 { openCollectionCreateDialog } from '../../store/collections/collection-create-actions';
 import { openProjectCreateDialog } from '~/store/projects/project-create-actions';
-import { ContainerRequestState } from "~/models/container-request";
-import { ProjectResource } from "~/models/project";
 
 type CssRules = 'root' | "toolbar" | "button";
 
@@ -58,14 +58,14 @@ export interface ProjectPanelFilter extends DataTableFilterItem {
     type: ResourceKind | ContainerRequestState;
 }
 
-export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilter> = [
+export const projectPanelColumns: DataColumns<string, ProjectPanelFilter> = [
     {
         name: ProjectPanelColumnNames.NAME,
         selected: true,
         configurable: true,
         sortDirection: SortDirection.ASC,
         filters: [],
-        render: res => <ResourceName uuid={res.uuid} />,
+        render: uuid => <ResourceName uuid={uuid} />,
         width: "450px"
     },
     {
@@ -90,7 +90,7 @@ export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilte
                 type: ContainerRequestState.UNCOMMITTED
             }
         ],
-        render: res => <ProcessStatus uuid={res.uuid} />,
+        render: uuid => <ProcessStatus uuid={uuid} />,
         width: "75px"
     },
     {
@@ -115,7 +115,7 @@ export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilte
                 type: ResourceKind.PROJECT
             }
         ],
-        render: res => <ResourceType uuid={res.uuid} />,
+        render: uuid => <ResourceType uuid={uuid} />,
         width: "125px"
     },
     {
@@ -124,7 +124,7 @@ export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilte
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: res => <ResourceOwner uuid={res.uuid} />,
+        render: uuid => <ResourceOwner uuid={uuid} />,
         width: "200px"
     },
     {
@@ -133,7 +133,7 @@ export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilte
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: res => <ResourceFileSize uuid={res.uuid} />,
+        render: uuid => <ResourceFileSize uuid={uuid} />,
         width: "50px"
     },
     {
@@ -142,7 +142,7 @@ export const projectPanelColumns: DataColumns<ProjectResource, ProjectPanelFilte
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: res => <ResourceLastModifiedDate uuid={res.uuid} />,
+        render: uuid => <ResourceLastModifiedDate uuid={uuid} />,
         width: "150px"
     }
 ];
@@ -195,9 +195,10 @@ export const ProjectPanel = withStyles(styles)(
                 this.props.dispatch<any>(openCollectionCreateDialog(this.props.currentItemId));
             }
 
-            handleContextMenu = (event: React.MouseEvent<HTMLElement>, resource: ProjectResource) => {
-                const kind = resourceKindToContextMenuKind(resource.uuid);
-                if (kind) {
+            handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
+                const kind = resourceKindToContextMenuKind(resourceUuid);
+                const resource = getResource(resourceUuid)(this.props.resources) as ProjectResource;
+                if (kind && resource) {
                     this.props.dispatch<any>(openContextMenu(event, {
                         name: resource.name,
                         uuid: resource.uuid,
diff --git a/src/views/trash-panel/trash-panel-item.ts b/src/views/trash-panel/trash-panel-item.ts
deleted file mode 100644 (file)
index a2f59ac..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { GroupContentsResource } from "~/services/groups-service/groups-service";
-import { TrashResource } from "~/models/resource";
-
-export interface TrashPanelItem {
-    uuid: string;
-    name: string;
-    kind: string;
-    owner: string;
-    fileSize?: number;
-    trashAt?: string;
-    deleteAt?: string;
-    isTrashed?: boolean;
-}
-
-export function resourceToDataItem(r: GroupContentsResource): TrashPanelItem {
-    return {
-        uuid: r.uuid,
-        name: r.name,
-        kind: r.kind,
-        owner: r.ownerUuid,
-        trashAt: (r as TrashResource).trashAt,
-        deleteAt: (r as TrashResource).deleteAt,
-        isTrashed: (r as TrashResource).isTrashed
-    };
-}
index 3c25a3e1cf92e703fc40f64cfce691551c55abf6..5aa45594b2749972e24833c6a78838e2596c6f93 100644 (file)
@@ -3,24 +3,31 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from 'react';
-import { TrashPanelItem } from './trash-panel-item';
 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
 import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
 import { DispatchProp, connect } from 'react-redux';
 import { DataColumns } from '~/components/data-table/data-table';
-import { RouteComponentProps } from 'react-router';
 import { RootState } from '~/store/store';
 import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
 import { SortDirection } from '~/components/data-table/data-column';
-import { ResourceKind } from '~/models/resource';
+import { ResourceKind, TrashResource } from '~/models/resource';
 import { resourceLabel } from '~/common/labels';
 import { ArvadosTheme } from '~/common/custom-theme';
-import { renderName, renderType, renderFileSize, renderDate } from '~/views-components/data-explorer/renderers';
 import { TrashIcon } from '~/components/icon/icon';
 import { TRASH_PANEL_ID } from "~/store/trash-panel/trash-panel-action";
 import { getProperty } from "~/store/properties/properties";
 import { PROJECT_PANEL_CURRENT_UUID } from "~/store/project-panel/project-panel-action";
 import { openContextMenu, resourceKindToContextMenuKind } from "~/store/context-menu/context-menu-actions";
+import { getResource, ResourcesState } from "~/store/resources/resources";
+import {
+    ResourceDeleteDate,
+    ResourceFileSize,
+    ResourceName,
+    ResourceTrashDate,
+    ResourceType
+} from "~/views-components/data-explorer/renderers";
+import { navigateTo } from "~/store/navigation/navigation-action";
+import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
 
 type CssRules = "toolbar" | "button";
 
@@ -46,14 +53,17 @@ export interface TrashPanelFilter extends DataTableFilterItem {
     type: ResourceKind;
 }
 
-export const trashPanelColumns: DataColumns<TrashPanelItem, TrashPanelFilter> = [
+export const trashPanelColumns: DataColumns<string, TrashPanelFilter> = [
     {
         name: TrashPanelColumnNames.NAME,
         selected: true,
         configurable: true,
         sortDirection: SortDirection.ASC,
         filters: [],
-        render: renderName,
+        render: uuid => {
+            console.log(uuid);
+            return <ResourceName uuid={uuid}/>;
+        },
         width: "450px"
     },
     {
@@ -78,7 +88,7 @@ export const trashPanelColumns: DataColumns<TrashPanelItem, TrashPanelFilter> =
                 type: ResourceKind.PROJECT
             }
         ],
-        render: item => renderType(item.kind),
+        render: uuid => <ResourceType uuid={uuid}/>,
         width: "125px"
     },
     {
@@ -87,7 +97,7 @@ export const trashPanelColumns: DataColumns<TrashPanelItem, TrashPanelFilter> =
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: item => renderFileSize(item.fileSize),
+        render: uuid => <ResourceFileSize uuid={uuid} />,
         width: "50px"
     },
     {
@@ -96,7 +106,7 @@ export const trashPanelColumns: DataColumns<TrashPanelItem, TrashPanelFilter> =
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: item => renderDate(item.trashAt),
+        render: uuid => <ResourceTrashDate uuid={uuid} />,
         width: "50px"
     },
     {
@@ -105,24 +115,17 @@ export const trashPanelColumns: DataColumns<TrashPanelItem, TrashPanelFilter> =
         configurable: true,
         sortDirection: SortDirection.NONE,
         filters: [],
-        render: item => renderDate(item.deleteAt),
+        render: uuid => <ResourceDeleteDate uuid={uuid} />,
         width: "50px"
     },
 ];
 
 interface TrashPanelDataProps {
     currentItemId: string;
+    resources: ResourcesState;
 }
 
-interface TrashPanelActionProps {
-    onItemClick: (item: TrashPanelItem) => void;
-    onContextMenu: (event: React.MouseEvent<HTMLElement>, item: TrashPanelItem) => void;
-    onDialogOpen: (ownerUuid: string) => void;
-    onItemDoubleClick: (item: TrashPanelItem) => void;
-    onItemRouteChange: (itemId: string) => void;
-}
-
-type TrashPanelProps = TrashPanelDataProps & TrashPanelActionProps & DispatchProp & WithStyles<CssRules>;
+type TrashPanelProps = TrashPanelDataProps & DispatchProp & WithStyles<CssRules>;
 
 export const TrashPanel = withStyles(styles)(
     connect((state: RootState) => ({
@@ -133,10 +136,9 @@ export const TrashPanel = withStyles(styles)(
             render() {
                 return <DataExplorer
                     id={TRASH_PANEL_ID}
-                    onRowClick={this.props.onItemClick}
-                    onRowDoubleClick={this.props.onItemDoubleClick}
-                    onContextMenu={this.props.onContextMenu}
-                    extractKey={(item: TrashPanelItem) => item.uuid}
+                    onRowClick={this.handleRowClick}
+                    onRowDoubleClick={this.handleRowDoubleClick}
+                    onContextMenu={this.handleContextMenu}
                     defaultIcon={TrashIcon}
                     defaultMessages={['Your trash list is empty.']}/>
                 ;
@@ -144,10 +146,25 @@ export const TrashPanel = withStyles(styles)(
 
             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
                 const kind = resourceKindToContextMenuKind(resourceUuid);
-                if (kind) {
-                    this.props.dispatch<any>(openContextMenu(event, { name: '', uuid: resourceUuid, kind }));
+                const resource = getResource(resourceUuid)(this.props.resources) as TrashResource;
+                if (kind && resource) {
+                    this.props.dispatch<any>(openContextMenu(event, {
+                        name: '',
+                        uuid: resource.uuid,
+                        ownerUuid: resource.ownerUuid,
+                        isTrashed: resource.isTrashed,
+                        kind
+                    }));
                 }
             }
+
+            handleRowDoubleClick = (uuid: string) => {
+                this.props.dispatch<any>(navigateTo(uuid));
+            }
+
+            handleRowClick = (uuid: string) => {
+                this.props.dispatch(loadDetailsPanel(uuid));
+            }
         }
     )
 );