[ARVADOS-WORKBENCH2] created: 1.1.4-640-gefe0283
Git user
git at public.curoverse.com
Tue Aug 21 04:17:53 EDT 2018
at efe0283919eb18e60ad876eaf6edef03c6cf04b3 (commit)
commit efe0283919eb18e60ad876eaf6edef03c6cf04b3
Author: Daniel Kos <daniel.kos at contractors.roche.com>
Date: Tue Aug 21 10:17:44 2018 +0200
Add trash view
Feature #13828
Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos at contractors.roche.com>
diff --git a/src/common/formatters.ts b/src/common/formatters.ts
index 49e0690..b1baee7 100644
--- a/src/common/formatters.ts
+++ b/src/common/formatters.ts
@@ -2,10 +2,13 @@
//
// SPDX-License-Identifier: AGPL-3.0
-export const formatDate = (isoDate: string) => {
- const date = new Date(isoDate);
- const text = date.toLocaleString();
- return text === 'Invalid Date' ? "" : text;
+export const formatDate = (isoDate?: string) => {
+ if (isoDate) {
+ const date = new Date(isoDate);
+ const text = date.toLocaleString();
+ return text === 'Invalid Date' ? "" : text;
+ }
+ return "";
};
export const formatFileSize = (size?: number) => {
diff --git a/src/components/data-table/data-table.tsx b/src/components/data-table/data-table.tsx
index 34f8168..5a6f9e5 100644
--- a/src/components/data-table/data-table.tsx
+++ b/src/components/data-table/data-table.tsx
@@ -63,7 +63,7 @@ export const DataTable = withStyles(styles)(
return <TableCell key={key || index} style={{ width: column.width, minWidth: column.width }}>
{renderHeader ?
renderHeader() :
- filters
+ filters.length > 0
? <DataTableFilters
name={`${name} filters`}
onChange={filters =>
diff --git a/src/models/collection.ts b/src/models/collection.ts
index 0e96f7f..5215998 100644
--- a/src/models/collection.ts
+++ b/src/models/collection.ts
@@ -2,9 +2,9 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { Resource, ResourceKind } from "./resource";
+import { ResourceKind, TrashResource } from "./resource";
-export interface CollectionResource extends Resource {
+export interface CollectionResource extends TrashResource {
kind: ResourceKind.COLLECTION;
name: string;
description: string;
@@ -14,11 +14,8 @@ export interface CollectionResource extends Resource {
replicationDesired: number;
replicationConfirmed: number;
replicationConfirmedAt: string;
- trashAt: string;
- deleteAt: string;
- isTrashed: boolean;
}
export const getCollectionUrl = (uuid: string) => {
return `/collections/${uuid}`;
-};
\ No newline at end of file
+};
diff --git a/src/models/container-request.ts b/src/models/container-request.ts
deleted file mode 100644
index d1bcc36..0000000
--- a/src/models/container-request.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { Resource, ResourceKind } from "./resource";
-
-export enum ContainerRequestState {
- UNCOMMITTED = "Uncommitted",
- COMMITTED = "Committed",
- FINAL = "Final"
-}
-
-export interface ContainerRequestResource extends Resource {
- kind: ResourceKind.CONTAINER_REQUEST;
- name: string;
- description: string;
- properties: any;
- state: ContainerRequestState;
- requestingContainerUuid: string;
- containerUuid: string;
- containerCountMax: number;
- mounts: any;
- runtimeConstraints: any;
- schedulingParameters: any;
- containerImage: string;
- environment: any;
- cwd: string;
- command: string[];
- outputPath: string;
- outputName: string;
- outputTtl: number;
- priority: number;
- expiresAt: string;
- useExisting: boolean;
- logUuid: string;
- outputUuid: string;
- filters: string;
-}
diff --git a/src/models/group.ts b/src/models/group.ts
index 5e8d7a1..5319250 100644
--- a/src/models/group.ts
+++ b/src/models/group.ts
@@ -2,20 +2,17 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { Resource, ResourceKind } from "./resource";
+import { ResourceKind, TrashResource } from "./resource";
-export interface GroupResource extends Resource {
+export interface GroupResource extends TrashResource {
kind: ResourceKind.GROUP;
name: string;
groupClass: GroupClass | null;
description: string;
properties: string;
writeableBy: string[];
- trashAt: string;
- deleteAt: string;
- isTrashed: boolean;
}
export enum GroupClass {
PROJECT = "project"
-}
\ No newline at end of file
+}
diff --git a/src/models/process.ts b/src/models/process.ts
index 1e04cb1..bcfbd3a 100644
--- a/src/models/process.ts
+++ b/src/models/process.ts
@@ -2,6 +2,37 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { ContainerRequestResource } from "./container-request";
+import { Resource, ResourceKind } from "./resource";
-export type ProcessResource = ContainerRequestResource;
+export enum ProcessState {
+ UNCOMMITTED = "Uncommitted",
+ COMMITTED = "Committed",
+ FINAL = "Final"
+}
+
+export interface ProcessResource extends Resource {
+ kind: ResourceKind.PROCESS;
+ name: string;
+ description: string;
+ properties: any;
+ state: ProcessState;
+ requestingContainerUuid: string;
+ containerUuid: string;
+ containerCountMax: number;
+ mounts: any;
+ runtimeConstraints: any;
+ schedulingParameters: any;
+ containerImage: string;
+ environment: any;
+ cwd: string;
+ command: string[];
+ outputPath: string;
+ outputName: string;
+ outputTtl: number;
+ priority: number;
+ expiresAt: string;
+ useExisting: boolean;
+ logUuid: string;
+ outputUuid: string;
+ filters: string;
+}
diff --git a/src/models/project.ts b/src/models/project.ts
index b919450..8e101ce 100644
--- a/src/models/project.ts
+++ b/src/models/project.ts
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { GroupResource, GroupClass } from "./group";
+import { GroupClass, GroupResource } from "./group";
export interface ProjectResource extends GroupResource {
groupClass: GroupClass.PROJECT;
diff --git a/src/models/resource.ts b/src/models/resource.ts
index 6a76b07..ab487da 100644
--- a/src/models/resource.ts
+++ b/src/models/resource.ts
@@ -14,9 +14,14 @@ export interface Resource {
etag: string;
}
+export interface TrashResource extends Resource {
+ trashAt: string;
+ deleteAt: string;
+ isTrashed: boolean;
+}
+
export enum ResourceKind {
COLLECTION = "arvados#collection",
- CONTAINER_REQUEST = "arvados#containerRequest",
GROUP = "arvados#group",
PROCESS = "arvados#containerRequest",
PROJECT = "arvados#group",
diff --git a/src/models/test-utils.ts b/src/models/test-utils.ts
index 6723430..49eea60 100644
--- a/src/models/test-utils.ts
+++ b/src/models/test-utils.ts
@@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0
-import { GroupResource, GroupClass } from "./group";
+import { GroupClass, GroupResource } from "./group";
import { Resource, ResourceKind } from "./resource";
import { ProjectResource } from "./project";
diff --git a/src/services/groups-service/groups-service.ts b/src/services/groups-service/groups-service.ts
index 822c810..39cc74a 100644
--- a/src/services/groups-service/groups-service.ts
+++ b/src/services/groups-service/groups-service.ts
@@ -16,6 +16,7 @@ export interface ContentsArguments {
order?: string;
filters?: string;
recursive?: boolean;
+ includeTrash?: boolean;
}
export type GroupContentsResource =
diff --git a/src/services/services.ts b/src/services/services.ts
index 61dd399..9199755 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -12,8 +12,9 @@ import { CollectionService } from "./collection-service/collection-service";
import { TagService } from "./tag-service/tag-service";
import { CollectionFilesService } from "./collection-files-service/collection-files-service";
import { KeepService } from "./keep-service/keep-service";
-import { WebDAV } from "../common/webdav";
-import { Config } from "../common/config";
+import { WebDAV } from "~/common/webdav";
+import { Config } from "~/common/config";
+import { TrashService } from "~/services/trash-service/trash-service";
export type ServiceRepository = ReturnType<typeof createServices>;
@@ -30,6 +31,7 @@ export const createServices = (config: Config) => {
const projectService = new ProjectService(apiClient);
const linkService = new LinkService(apiClient);
const favoriteService = new FavoriteService(linkService, groupsService);
+ const trashService = new TrashService(apiClient);
const collectionService = new CollectionService(apiClient, keepService, webdavClient, authService);
const tagService = new TagService(linkService);
const collectionFilesService = new CollectionFilesService(collectionService);
@@ -43,6 +45,7 @@ export const createServices = (config: Config) => {
projectService,
linkService,
favoriteService,
+ trashService,
collectionService,
tagService,
collectionFilesService
diff --git a/src/services/trash-service/trash-service.test.ts b/src/services/trash-service/trash-service.test.ts
new file mode 100644
index 0000000..f22d066
--- /dev/null
+++ b/src/services/trash-service/trash-service.test.ts
@@ -0,0 +1,17 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { GroupsService } from "../groups-service/groups-service";
+import { TrashService } from "./trash-service";
+import { mockResourceService } from "~/common/api/common-resource-service.test";
+
+describe("TrashService", () => {
+
+ let groupService: GroupsService;
+
+ beforeEach(() => {
+ groupService = mockResourceService(GroupsService);
+ });
+
+});
diff --git a/src/services/trash-service/trash-service.ts b/src/services/trash-service/trash-service.ts
new file mode 100644
index 0000000..fc02d2f
--- /dev/null
+++ b/src/services/trash-service/trash-service.ts
@@ -0,0 +1,12 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { GroupsService } from "../groups-service/groups-service";
+import { AxiosInstance } from "axios";
+
+export class TrashService extends GroupsService {
+ constructor(serverApi: AxiosInstance) {
+ super(serverApi);
+ }
+}
diff --git a/src/store/side-panel/side-panel-reducer.ts b/src/store/side-panel/side-panel-reducer.ts
index db1cbe5..b68ce7a 100644
--- a/src/store/side-panel/side-panel-reducer.ts
+++ b/src/store/side-panel/side-panel-reducer.ts
@@ -10,9 +10,11 @@ import { push } from "react-router-redux";
import { favoritePanelActions } from "../favorite-panel/favorite-panel-action";
import { projectPanelActions } from "../project-panel/project-panel-action";
import { projectActions } from "../project/project-action";
-import { getProjectUrl } from "../../models/project";
-import { columns as projectPanelColumns } from "../../views/project-panel/project-panel";
-import { columns as favoritePanelColumns } from "../../views/favorite-panel/favorite-panel";
+import { getProjectUrl } from "~/models/project";
+import { columns as projectPanelColumns } from "~/views/project-panel/project-panel";
+import { columns as favoritePanelColumns } from "~/views/favorite-panel/favorite-panel";
+import { columns as trashPanelColumns } from "~/views/trash-panel/trash-panel";
+import { trashPanelActions } from "~/store/trash-panel/trash-panel-action";
export type SidePanelState = SidePanelItem[];
@@ -102,6 +104,9 @@ export const sidePanelItems = [
active: false,
activeAction: (dispatch: Dispatch) => {
dispatch(push("/trash"));
+ dispatch(trashPanelActions.SET_COLUMNS({ columns: trashPanelColumns }));
+ dispatch(trashPanelActions.RESET_PAGINATION());
+ dispatch(trashPanelActions.REQUEST_ITEMS());
}
}
];
diff --git a/src/store/store.ts b/src/store/store.ts
index a4bf9d6..febaf93 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -29,6 +29,8 @@ import { CollectionsState, collectionsReducer } from './collections/collections-
import { ServiceRepository } from "~/services/services";
import { treePickerReducer } from './tree-picker/tree-picker-reducer';
import { TreePicker } from './tree-picker/tree-picker';
+import { TrashPanelMiddlewareService } from "~/store/trash-panel/trash-panel-middleware-service";
+import { TRASH_PANEL_ID } from "~/store/trash-panel/trash-panel-action";
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
@@ -79,12 +81,16 @@ export function configureStore(history: History, services: ServiceRepository): R
const favoritePanelMiddleware = dataExplorerMiddleware(
new FavoritePanelMiddlewareService(services, FAVORITE_PANEL_ID)
);
+ const trashPanelMiddleware = dataExplorerMiddleware(
+ new TrashPanelMiddlewareService(services, TRASH_PANEL_ID)
+ );
const middlewares: Middleware[] = [
routerMiddleware(history),
thunkMiddleware.withExtraArgument(services),
projectPanelMiddleware,
- favoritePanelMiddleware
+ favoritePanelMiddleware,
+ trashPanelMiddleware
];
const enhancer = composeEnhancers(applyMiddleware(...middlewares));
return createStore(rootReducer, enhancer);
diff --git a/src/store/trash-panel/trash-panel-action.ts b/src/store/trash-panel/trash-panel-action.ts
new file mode 100644
index 0000000..84d5602
--- /dev/null
+++ b/src/store/trash-panel/trash-panel-action.ts
@@ -0,0 +1,8 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { bindDataExplorerActions } from "../data-explorer/data-explorer-action";
+
+export const TRASH_PANEL_ID = "trashPanel";
+export const trashPanelActions = bindDataExplorerActions(TRASH_PANEL_ID);
diff --git a/src/store/trash-panel/trash-panel-middleware-service.ts b/src/store/trash-panel/trash-panel-middleware-service.ts
new file mode 100644
index 0000000..2d1dbf7
--- /dev/null
+++ b/src/store/trash-panel/trash-panel-middleware-service.ts
@@ -0,0 +1,80 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { DataExplorerMiddlewareService } from "../data-explorer/data-explorer-middleware-service";
+import { RootState } from "../store";
+import { DataColumns } from "~/components/data-table/data-table";
+import { ServiceRepository } from "~/services/services";
+import { SortDirection } from "~/components/data-table/data-column";
+import { FilterBuilder } from "~/common/api/filter-builder";
+import { checkPresenceInFavorites } from "../favorites/favorites-actions";
+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 { TrashPanelColumnNames, TrashPanelFilter } from "~/views/trash-panel/trash-panel";
+import { ProjectResource } from "~/models/project";
+import { ProjectPanelColumnNames } from "~/views/project-panel/project-panel";
+
+export class TrashPanelMiddlewareService extends DataExplorerMiddlewareService {
+ constructor(private services: ServiceRepository, id: string) {
+ super(id);
+ }
+
+ requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+ const dataExplorer = api.getState().dataExplorer[this.getId()];
+ const columns = dataExplorer.columns as DataColumns<TrashPanelItem, TrashPanelFilter>;
+ const sortColumn = dataExplorer.columns.find(c => c.sortDirection !== SortDirection.NONE);
+ const typeFilters = this.getColumnFilters(columns, TrashPanelColumnNames.TYPE);
+
+ const order = new OrderBuilder<ProjectResource>();
+
+ if (sortColumn) {
+ const sortDirection = sortColumn && sortColumn.sortDirection === SortDirection.ASC
+ ? OrderDirection.ASC
+ : OrderDirection.DESC;
+
+ const columnName = sortColumn && sortColumn.name === ProjectPanelColumnNames.NAME ? "name" : "createdAt";
+ order
+ .addOrder(sortDirection, columnName, GroupContentsResourcePrefix.COLLECTION)
+ .addOrder(sortDirection, columnName, GroupContentsResourcePrefix.PROCESS)
+ .addOrder(sortDirection, columnName, GroupContentsResourcePrefix.PROJECT);
+ }
+
+ const userUuid = this.services.authService.getUuid()!;
+
+ this.services.trashService
+ .contents(userUuid, {
+ limit: dataExplorer.rowsPerPage,
+ offset: dataExplorer.page * dataExplorer.rowsPerPage,
+ order: order.getOrder(),
+ filters: new FilterBuilder()
+ .addIsA("uuid", typeFilters.map(f => f.type))
+ .addILike("name", dataExplorer.searchValue, GroupContentsResourcePrefix.COLLECTION)
+ .addILike("name", dataExplorer.searchValue, GroupContentsResourcePrefix.PROCESS)
+ .addILike("name", dataExplorer.searchValue, GroupContentsResourcePrefix.PROJECT)
+ .getFilters(),
+ recursive: true,
+ includeTrash: true
+ })
+ .then(response => {
+ 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
+ }));
+ api.dispatch<any>(checkPresenceInFavorites(response.items.map(item => item.uuid)));
+ })
+ .catch(() => {
+ api.dispatch(trashPanelActions.SET_ITEMS({
+ items: [],
+ itemsAvailable: 0,
+ page: 0,
+ rowsPerPage: dataExplorer.rowsPerPage
+ }));
+ });
+ }
+}
diff --git a/src/views-components/data-explorer/renderers.tsx b/src/views-components/data-explorer/renderers.tsx
index 1b07642..8246d02 100644
--- a/src/views-components/data-explorer/renderers.tsx
+++ b/src/views-components/data-explorer/renderers.tsx
@@ -42,7 +42,7 @@ export const renderIcon = (item: {kind: string}) => {
}
};
-export const renderDate = (date: string) => {
+export const renderDate = (date?: string) => {
return <Typography noWrap>{formatDate(date)}</Typography>;
};
diff --git a/src/views/favorite-panel/favorite-panel.tsx b/src/views/favorite-panel/favorite-panel.tsx
index 125ea27..49f1f4a 100644
--- a/src/views/favorite-panel/favorite-panel.tsx
+++ b/src/views/favorite-panel/favorite-panel.tsx
@@ -11,7 +11,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 { ProcessState } from '~/models/process';
import { SortDirection } from '~/components/data-table/data-column';
import { ResourceKind } from '~/models/resource';
import { resourceLabel } from '~/common/labels';
@@ -42,7 +42,7 @@ export enum FavoritePanelColumnNames {
}
export interface FavoritePanelFilter extends DataTableFilterItem {
- type: ResourceKind | ContainerRequestState;
+ type: ResourceKind | ProcessState;
}
export const columns: DataColumns<FavoritePanelItem, FavoritePanelFilter> = [
@@ -62,19 +62,19 @@ export const columns: DataColumns<FavoritePanelItem, FavoritePanelFilter> = [
sortDirection: SortDirection.NONE,
filters: [
{
- name: ContainerRequestState.COMMITTED,
+ name: ProcessState.COMMITTED,
selected: true,
- type: ContainerRequestState.COMMITTED
+ type: ProcessState.COMMITTED
},
{
- name: ContainerRequestState.FINAL,
+ name: ProcessState.FINAL,
selected: true,
- type: ContainerRequestState.FINAL
+ type: ProcessState.FINAL
},
{
- name: ContainerRequestState.UNCOMMITTED,
+ name: ProcessState.UNCOMMITTED,
selected: true,
- type: ContainerRequestState.UNCOMMITTED
+ type: ProcessState.UNCOMMITTED
}
],
render: renderStatus,
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index 0f958d2..f63584b 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -11,7 +11,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 { ProcessState } from '~/models/process';
import { SortDirection } from '~/components/data-table/data-column';
import { ResourceKind } from '~/models/resource';
import { resourceLabel } from '~/common/labels';
@@ -47,7 +47,7 @@ export enum ProjectPanelColumnNames {
}
export interface ProjectPanelFilter extends DataTableFilterItem {
- type: ResourceKind | ContainerRequestState;
+ type: ResourceKind | ProcessState;
}
export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [
@@ -67,19 +67,19 @@ export const columns: DataColumns<ProjectPanelItem, ProjectPanelFilter> = [
sortDirection: SortDirection.NONE,
filters: [
{
- name: ContainerRequestState.COMMITTED,
+ name: ProcessState.COMMITTED,
selected: true,
- type: ContainerRequestState.COMMITTED
+ type: ProcessState.COMMITTED
},
{
- name: ContainerRequestState.FINAL,
+ name: ProcessState.FINAL,
selected: true,
- type: ContainerRequestState.FINAL
+ type: ProcessState.FINAL
},
{
- name: ContainerRequestState.UNCOMMITTED,
+ name: ProcessState.UNCOMMITTED,
selected: true,
- type: ContainerRequestState.UNCOMMITTED
+ type: ProcessState.UNCOMMITTED
}
],
render: renderStatus,
diff --git a/src/views/trash-panel/trash-panel-item.ts b/src/views/trash-panel/trash-panel-item.ts
new file mode 100644
index 0000000..8916458
--- /dev/null
+++ b/src/views/trash-panel/trash-panel-item.ts
@@ -0,0 +1,27 @@
+// 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;
+ fileSize?: number;
+ trashAt?: string;
+ deleteAt?: string;
+ isTrashed?: boolean;
+}
+
+export function resourceToDataItem(r: GroupContentsResource): TrashPanelItem {
+ return {
+ uuid: r.uuid,
+ name: r.name,
+ kind: r.kind,
+ trashAt: (r as TrashResource).trashAt,
+ deleteAt: (r as TrashResource).deleteAt,
+ isTrashed: (r as TrashResource).isTrashed
+ };
+}
diff --git a/src/views/favorite-panel/favorite-panel.tsx b/src/views/trash-panel/trash-panel.tsx
similarity index 57%
copy from src/views/favorite-panel/favorite-panel.tsx
copy to src/views/trash-panel/trash-panel.tsx
index 125ea27..c5a302e 100644
--- a/src/views/favorite-panel/favorite-panel.tsx
+++ b/src/views/trash-panel/trash-panel.tsx
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
-import { FavoritePanelItem } from './favorite-panel-item';
+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';
@@ -11,14 +11,14 @@ 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 { ProcessState } from '~/models/process';
import { SortDirection } from '~/components/data-table/data-column';
import { ResourceKind } from '~/models/resource';
import { resourceLabel } from '~/common/labels';
import { ArvadosTheme } from '~/common/custom-theme';
-import { renderName, renderStatus, renderType, renderOwner, renderFileSize, renderDate } from '~/views-components/data-explorer/renderers';
-import { FAVORITE_PANEL_ID } from "~/store/favorite-panel/favorite-panel-action";
-import { FavoriteIcon } from '~/components/icon/icon';
+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";
type CssRules = "toolbar" | "button";
@@ -32,22 +32,21 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
},
});
-export enum FavoritePanelColumnNames {
+export enum TrashPanelColumnNames {
NAME = "Name",
- STATUS = "Status",
TYPE = "Type",
- OWNER = "Owner",
FILE_SIZE = "File size",
- LAST_MODIFIED = "Last modified"
+ TRASHED_DATE = "Trashed date",
+ TO_BE_DELETED = "To be deleted"
}
-export interface FavoritePanelFilter extends DataTableFilterItem {
- type: ResourceKind | ContainerRequestState;
+export interface TrashPanelFilter extends DataTableFilterItem {
+ type: ResourceKind | ProcessState;
}
-export const columns: DataColumns<FavoritePanelItem, FavoritePanelFilter> = [
+export const columns: DataColumns<TrashPanelItem, TrashPanelFilter> = [
{
- name: FavoritePanelColumnNames.NAME,
+ name: TrashPanelColumnNames.NAME,
selected: true,
configurable: true,
sortDirection: SortDirection.ASC,
@@ -56,32 +55,7 @@ export const columns: DataColumns<FavoritePanelItem, FavoritePanelFilter> = [
width: "450px"
},
{
- name: "Status",
- selected: true,
- configurable: true,
- sortDirection: SortDirection.NONE,
- filters: [
- {
- name: ContainerRequestState.COMMITTED,
- selected: true,
- type: ContainerRequestState.COMMITTED
- },
- {
- name: ContainerRequestState.FINAL,
- selected: true,
- type: ContainerRequestState.FINAL
- },
- {
- name: ContainerRequestState.UNCOMMITTED,
- selected: true,
- type: ContainerRequestState.UNCOMMITTED
- }
- ],
- render: renderStatus,
- width: "75px"
- },
- {
- name: FavoritePanelColumnNames.TYPE,
+ name: TrashPanelColumnNames.TYPE,
selected: true,
configurable: true,
sortDirection: SortDirection.NONE,
@@ -106,66 +80,66 @@ export const columns: DataColumns<FavoritePanelItem, FavoritePanelFilter> = [
width: "125px"
},
{
- name: FavoritePanelColumnNames.OWNER,
+ name: TrashPanelColumnNames.FILE_SIZE,
selected: true,
configurable: true,
sortDirection: SortDirection.NONE,
filters: [],
- render: item => renderOwner(item.owner),
- width: "200px"
+ render: item => renderFileSize(item.fileSize),
+ width: "50px"
},
{
- name: FavoritePanelColumnNames.FILE_SIZE,
+ name: TrashPanelColumnNames.TRASHED_DATE,
selected: true,
configurable: true,
sortDirection: SortDirection.NONE,
filters: [],
- render: item => renderFileSize(item.fileSize),
+ render: item => renderDate(item.trashAt),
width: "50px"
},
{
- name: FavoritePanelColumnNames.LAST_MODIFIED,
+ name: TrashPanelColumnNames.TO_BE_DELETED,
selected: true,
configurable: true,
sortDirection: SortDirection.NONE,
filters: [],
- render: item => renderDate(item.lastModified),
- width: "150px"
- }
+ render: item => renderDate(item.deleteAt),
+ width: "50px"
+ },
];
-interface FavoritePanelDataProps {
+interface TrashPanelDataProps {
currentItemId: string;
}
-interface FavoritePanelActionProps {
- onItemClick: (item: FavoritePanelItem) => void;
- onContextMenu: (event: React.MouseEvent<HTMLElement>, item: FavoritePanelItem) => void;
+interface TrashPanelActionProps {
+ onItemClick: (item: TrashPanelItem) => void;
+ onContextMenu: (event: React.MouseEvent<HTMLElement>, item: TrashPanelItem) => void;
onDialogOpen: (ownerUuid: string) => void;
- onItemDoubleClick: (item: FavoritePanelItem) => void;
+ onItemDoubleClick: (item: TrashPanelItem) => void;
onItemRouteChange: (itemId: string) => void;
}
-type FavoritePanelProps = FavoritePanelDataProps & FavoritePanelActionProps & DispatchProp
+type TrashPanelProps = TrashPanelDataProps & TrashPanelActionProps & DispatchProp
& WithStyles<CssRules> & RouteComponentProps<{ id: string }>;
-export const FavoritePanel = withStyles(styles)(
+export const TrashPanel = withStyles(styles)(
connect((state: RootState) => ({ currentItemId: state.projects.currentItemId }))(
- class extends React.Component<FavoritePanelProps> {
+ class extends React.Component<TrashPanelProps> {
render() {
return <DataExplorer
- id={FAVORITE_PANEL_ID}
+ id={TRASH_PANEL_ID}
columns={columns}
onRowClick={this.props.onItemClick}
onRowDoubleClick={this.props.onItemDoubleClick}
onContextMenu={this.props.onContextMenu}
- extractKey={(item: FavoritePanelItem) => item.uuid}
- defaultIcon={FavoriteIcon}
- defaultMessages={['Your favorites list is empty.']}/>
+ extractKey={(item: TrashPanelItem) => item.uuid}
+ defaultIcon={TrashIcon}
+ defaultMessages={['Your trash list is empty.']}/>
;
}
- componentWillReceiveProps({ match, currentItemId, onItemRouteChange }: FavoritePanelProps) {
+ componentWillReceiveProps({ match, currentItemId, onItemRouteChange }: TrashPanelProps) {
if (match.params.id !== currentItemId) {
onItemRouteChange(match.params.id);
}
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index a2d61d5..a3f7624 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -49,6 +49,8 @@ import { MultipleFilesRemoveDialog } from '~/views-components/file-remove-dialog
import { DialogCollectionCreateWithSelectedFile } from '~/views-components/create-collection-dialog-with-selected/create-collection-dialog-with-selected';
import { COLLECTION_CREATE_DIALOG } from '~/views-components/dialog-create/dialog-collection-create';
import { PROJECT_CREATE_DIALOG } from '~/views-components/dialog-create/dialog-project-create';
+import { TrashPanel } from "~/views/trash-panel/trash-panel";
+import { trashPanelActions } from "~/store/trash-panel/trash-panel-action";
const DRAWER_WITDH = 240;
const APP_BAR_HEIGHT = 100;
@@ -232,6 +234,7 @@ export const Workbench = withStyles(styles)(
<Route path='/' exact render={() => <Redirect to={`/projects/${this.props.authService.getUuid()}`} />} />
<Route path="/projects/:id" render={this.renderProjectPanel} />
<Route path="/favorites" render={this.renderFavoritePanel} />
+ <Route path="/trash" render={this.renderTrashPanel} />
<Route path="/collections/:id" render={this.renderCollectionPanel} />
</Switch>
</div>
@@ -335,6 +338,33 @@ export const Workbench = withStyles(styles)(
}}
{...props} />
+ renderTrashPanel = (props: RouteComponentProps<{ id: string }>) => <TrashPanel
+ onItemRouteChange={() => this.props.dispatch(trashPanelActions.REQUEST_ITEMS())}
+ onContextMenu={(event, item) => {
+ const kind = item.kind === ResourceKind.PROJECT ? ContextMenuKind.PROJECT : ContextMenuKind.RESOURCE;
+ this.openContextMenu(event, {
+ uuid: item.uuid,
+ name: item.name,
+ kind,
+ });
+ }}
+ onDialogOpen={this.handleProjectCreationDialogOpen}
+ onItemClick={item => {
+ this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
+ }}
+ onItemDoubleClick={item => {
+ switch (item.kind) {
+ case ResourceKind.COLLECTION:
+ this.props.dispatch(loadCollection(item.uuid));
+ this.props.dispatch(push(getCollectionUrl(item.uuid)));
+ default:
+ this.props.dispatch(loadDetails(item.uuid, ResourceKind.PROJECT));
+ this.props.dispatch(setProjectItem(item.uuid, ItemMode.ACTIVE));
+ }
+
+ }}
+ {...props} />
+
mainAppBarActions: MainAppBarActionProps = {
onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => {
this.props.dispatch(setProjectItem(itemId, ItemMode.BOTH));
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list