"unionize": "2.1.2"
},
"scripts": {
- "start": "react-scripts-ts start",
- "build": "react-scripts-ts build",
+ "start": "REACT_APP_BUILD_NUMBER=$BUILD_NUMBER REACT_APP_GIT_COMMIT=$GIT_COMMIT react-scripts-ts start",
+ "build": "REACT_APP_BUILD_NUMBER=$BUILD_NUMBER REACT_APP_GIT_COMMIT=$GIT_COMMIT react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"eject": "react-scripts-ts eject",
"lint": "tslint src/** -t verbose"
import PersonAdd from '@material-ui/icons/PersonAdd';
import PlayArrow from '@material-ui/icons/PlayArrow';
import RateReview from '@material-ui/icons/RateReview';
+import RestoreFromTrash from '@material-ui/icons/RestoreFromTrash';
import Search from '@material-ui/icons/Search';
import SettingsApplications from '@material-ui/icons/SettingsApplications';
import Star from '@material-ui/icons/Star';
export const RemoveIcon: IconType = (props) => <Delete {...props} />;
export const RemoveFavoriteIcon: IconType = (props) => <Star {...props} />;
export const RenameIcon: IconType = (props) => <Edit {...props} />;
+export const RestoreFromTrashIcon: IconType = (props) => <RestoreFromTrash {...props} />;
export const ReRunProcessIcon: IconType = (props) => <Cached {...props} />;
export const SearchIcon: IconType = (props) => <Search {...props} />;
export const ShareIcon: IconType = (props) => <PersonAdd {...props} />;
});
}
-
private readFile(file: File): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>(resolve => {
const reader = new FileReader();
}
});
}
+
+ trash(uuid: string): Promise<CollectionResource> {
+ return this.serverApi
+ .post(this.resourceType + `${uuid}/trash`)
+ .then(CommonResourceService.mapResponseKeys);
+ }
+
+ untrash(uuid: string): Promise<CollectionResource> {
+ const params = {
+ ensure_unique_name: true
+ };
+ return this.serverApi
+ .post(this.resourceType + `${uuid}/untrash`, {
+ params: CommonResourceService.mapKeys(_.snakeCase)(params)
+ })
+ .then(CommonResourceService.mapResponseKeys);
+ }
+
}
import * as _ from "lodash";
import { CommonResourceService, ListResults } from "~/common/api/common-resource-service";
import { AxiosInstance } from "axios";
-import { GroupResource } from "~/models/group";
import { CollectionResource } from "~/models/collection";
import { ProjectResource } from "~/models/project";
import { ProcessResource } from "~/models/process";
+import { TrashResource } from "~/models/resource";
export interface ContentsArguments {
limit?: number;
ProjectResource |
ProcessResource;
-export class GroupsService<T extends GroupResource = GroupResource> extends CommonResourceService<T> {
+export class GroupsService<T extends TrashResource = TrashResource> extends CommonResourceService<T> {
constructor(serverApi: AxiosInstance) {
super(serverApi, "groups");
order: order ? order : undefined
};
return this.serverApi
- .get(this.resourceType + `${uuid}/contents/`, {
+ .get(this.resourceType + `${uuid}/contents`, {
params: CommonResourceService.mapKeys(_.snakeCase)(params)
})
.then(CommonResourceService.mapResponseKeys);
}
+
+ trash(uuid: string): Promise<T> {
+ return this.serverApi
+ .post(this.resourceType + `${uuid}/trash`)
+ .then(CommonResourceService.mapResponseKeys);
+ }
+
+ untrash(uuid: string): Promise<T> {
+ const params = {
+ ensure_unique_name: true
+ };
+ return this.serverApi
+ .post(this.resourceType + `${uuid}/untrash`, {
+ params: CommonResourceService.mapKeys(_.snakeCase)(params)
+ })
+ .then(CommonResourceService.mapResponseKeys);
+ }
+
}
export enum GroupContentsResourcePrefix {
import { KeepService } from "./keep-service/keep-service";
import { WebDAV } from "~/common/webdav";
import { Config } from "~/common/config";
-import { TrashService } from "~/services/trash-service/trash-service";
export type ServiceRepository = ReturnType<typeof createServices>;
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);
projectService,
linkService,
favoriteService,
- trashService,
collectionService,
tagService,
collectionFilesService
+++ /dev/null
-// 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);
- });
-
-});
+++ /dev/null
-// 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);
- }
-}
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import { RootState } from "~/store/store";
+import { ServiceRepository } from "~/services/services";
+import { snackbarActions } from "~/store/snackbar/snackbar-actions";
+import { sidePanelActions } from "~/store/side-panel/side-panel-action";
+import { SidePanelId } from "~/store/side-panel/side-panel-reducer";
+import { trashPanelActions } from "~/store/trash-panel/trash-panel-action";
+import { getProjectList, projectActions } from "~/store/project/project-action";
+
+export const toggleCollectionTrashed = (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.collectionService.untrash(resource.uuid).then(() => {
+ 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 }));
+ });
+ dispatch(trashPanelActions.REQUEST_ITEMS());
+ dispatch(snackbarActions.CLOSE_SNACKBAR());
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: "Restored from trash",
+ hideDuration: 2000
+ }));
+ });
+ } else {
+ return services.collectionService.trash(resource.uuid).then(() => {
+ dispatch(snackbarActions.CLOSE_SNACKBAR());
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: "Added to trash",
+ hideDuration: 2000
+ }));
+ });
+ }
+ };
kind: string;
name: string;
description?: string;
+ isTrashed?: boolean;
+ ownerUuid?: string;
}
const initialState = {
if (router.location && !router.location.pathname.includes(resourceUrl)) {
dispatch(push(resourceUrl));
}
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(treeItem.data.uuid));
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE({ itemId: treeItem.data.uuid }));
}
const promise = treeItem.status === TreeItemStatus.LOADED
promise
.then(() => dispatch<any>(() => {
if (itemMode === ItemMode.OPEN || itemMode === ItemMode.BOTH) {
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(treeItem.data.uuid));
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: treeItem.data.uuid }));
}
dispatch(projectPanelActions.RESET_PAGINATION());
dispatch(projectPanelActions.REQUEST_ITEMS());
} else {
const uuid = services.authService.getUuid();
if (itemId === uuid) {
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(uuid));
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE({ itemId: uuid }));
dispatch(projectPanelActions.RESET_PAGINATION());
dispatch(projectPanelActions.REQUEST_ITEMS());
}
await loadBranch(uuids, dispatch);
dispatch(sidePanelActions.TOGGLE_SIDE_PANEL_ITEM_OPEN(SidePanelId.PROJECTS));
uuids.forEach(uuid => {
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(uuid));
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: uuid }));
});
};
import { ServiceRepository } from "~/services/services";
import { projectPanelActions } from "~/store/project-panel/project-panel-action";
import { updateDetails } from "~/store/details-panel/details-panel-action";
+import { snackbarActions } from "~/store/snackbar/snackbar-actions";
+import { trashPanelActions } from "~/store/trash-panel/trash-panel-action";
+import { sidePanelActions } from "~/store/side-panel/side-panel-action";
+import { SidePanelId } from "~/store/side-panel/side-panel-reducer";
export const projectActions = unionize({
OPEN_PROJECT_CREATOR: ofType<{ ownerUuid: string }>(),
REMOVE_PROJECT: ofType<string>(),
PROJECTS_REQUEST: ofType<string>(),
PROJECTS_SUCCESS: ofType<{ projects: ProjectResource[], parentItemId?: string }>(),
- TOGGLE_PROJECT_TREE_ITEM_OPEN: ofType<string>(),
- TOGGLE_PROJECT_TREE_ITEM_ACTIVE: ofType<string>(),
+ TOGGLE_PROJECT_TREE_ITEM_OPEN: ofType<{ itemId: string, open?: boolean, recursive?: boolean }>(),
+ TOGGLE_PROJECT_TREE_ITEM_ACTIVE: ofType<{ itemId: string, active?: boolean, recursive?: boolean }>(),
RESET_PROJECT_TREE_ACTIVITY: ofType<string>()
}, {
tag: 'type',
export const PROJECT_FORM_NAME = 'projectEditDialog';
-export const getProjectList = (parentUuid: string = '') =>
+export const getProjectList = (parentUuid: string = '') =>
(dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(projectActions.PROJECTS_REQUEST(parentUuid));
return services.projectService.list({
});
};
+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>(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 }));
+ });
+ dispatch(trashPanelActions.REQUEST_ITEMS());
+ dispatch(snackbarActions.CLOSE_SNACKBAR());
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: "Restored from trash",
+ hideDuration: 2000
+ }));
+ });
+ } else {
+ return services.groupsService.trash(resource.uuid).then(() => {
+ dispatch<any>(getProjectList(resource.ownerUuid)).then(() => {
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: resource.ownerUuid!!, open: true, recursive: true }));
+ });
+ dispatch(snackbarActions.CLOSE_SNACKBAR());
+ dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: "Added to trash",
+ hideDuration: 2000
+ }));
+ });
+ }
+ };
+
export type ProjectAction = UnionOf<typeof projectActions>;
updater: { opened: false, uuid: '' }
};
- const state = projectsReducer(initialState, projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(initialState.items[0].id));
+ const state = projectsReducer(initialState, projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE({ itemId: initialState.items[0].id }));
expect(state).toEqual(project);
});
};
- const state = projectsReducer(initialState, projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN(initialState.items[0].id));
+ const state = projectsReducer(initialState, projectActions.TOGGLE_PROJECT_TREE_ITEM_OPEN({ itemId: initialState.items[0].id }));
expect(state).toEqual(project);
});
});
//
// SPDX-License-Identifier: AGPL-3.0
-import * as _ from "lodash";
-
import { projectActions, ProjectAction } from "./project-action";
import { TreeItem, TreeItemStatus } from "~/components/tree/tree";
import { ProjectResource } from "~/models/project";
uuid: string;
}
-export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
- let item;
+function rebuildTree<T>(tree: Array<TreeItem<T>>, action: (item: TreeItem<T>, visitedItems: TreeItem<T>[]) => void, visitedItems: TreeItem<T>[] = []): Array<TreeItem<T>> {
+ const newTree: Array<TreeItem<T>> = [];
for (const t of tree) {
- item = t.id === itemId
- ? t
- : findTreeItem(t.items ? t.items : [], itemId);
- if (item) {
- break;
- }
+ const items = t.items
+ ? rebuildTree(t.items, action, visitedItems.concat(t))
+ : undefined;
+ const item: TreeItem<T> = { ...t, items };
+ action(item, visitedItems);
+ newTree.push(item);
}
- return item;
+ return newTree;
}
-export function getActiveTreeItem<T>(tree: Array<TreeItem<T>>): TreeItem<T> | undefined {
+export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
let item;
for (const t of tree) {
- item = t.active
+ item = t.id === itemId
? t
- : getActiveTreeItem(t.items ? t.items : []);
+ : findTreeItem(t.items ? t.items : [], itemId);
if (item) {
break;
}
return [];
}
-function resetTreeActivity<T>(tree: Array<TreeItem<T>>) {
- for (const t of tree) {
- t.active = false;
- resetTreeActivity(t.items ? t.items : []);
- }
-}
-
-function updateProjectTree(tree: Array<TreeItem<ProjectResource>>, projects: ProjectResource[], parentItemId?: string): Array<TreeItem<ProjectResource>> {
- let treeItem;
- if (parentItemId) {
- treeItem = findTreeItem(tree, parentItemId);
- if (treeItem) {
- treeItem.status = TreeItemStatus.LOADED;
- }
- }
- const items = projects.map(p => ({
- id: p.uuid,
- open: false,
- active: false,
- status: TreeItemStatus.INITIAL,
- data: p,
- items: []
- } as TreeItem<ProjectResource>));
-
- if (treeItem) {
- treeItem.items = items;
- return tree;
- }
-
- return items;
-}
-
const updateCreator = (state: ProjectState, creator: Partial<ProjectCreator>) => ({
...state,
creator: {
}
};
-
export const projectsReducer = (state: ProjectState = initialState, action: ProjectAction) => {
return projectActions.match(action, {
OPEN_PROJECT_CREATOR: ({ ownerUuid }) => updateCreator(state, { ownerUuid, opened: true }),
UPDATE_PROJECT_SUCCESS: () => updateProject(state, { opened: false, uuid: "" }),
REMOVE_PROJECT: () => state,
PROJECTS_REQUEST: itemId => {
- const items = _.cloneDeep(state.items);
- const item = findTreeItem(items, itemId);
- if (item) {
- item.status = TreeItemStatus.PENDING;
- state.items = items;
- }
- return { ...state, items };
- },
- PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
- const items = _.cloneDeep(state.items);
return {
...state,
- items: updateProjectTree(items, projects, parentItemId)
+ items: rebuildTree(state.items, item => {
+ if (item.id === itemId) {
+ item.status = TreeItemStatus.PENDING;
+ }
+ })
};
},
- TOGGLE_PROJECT_TREE_ITEM_OPEN: itemId => {
- const items = _.cloneDeep(state.items);
- const item = findTreeItem(items, itemId);
- if (item) {
- item.open = !item.open;
- }
- return {
- ...state,
- items,
- currentItemId: itemId
- };
- },
- TOGGLE_PROJECT_TREE_ITEM_ACTIVE: itemId => {
- const items = _.cloneDeep(state.items);
- resetTreeActivity(items);
- const item = findTreeItem(items, itemId);
- if (item) {
- item.active = true;
- }
- return {
- ...state,
- items,
- currentItemId: itemId
- };
- },
- RESET_PROJECT_TREE_ACTIVITY: () => {
- const items = _.cloneDeep(state.items);
- resetTreeActivity(items);
+ PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
+ const items = projects.map(p => ({
+ id: p.uuid,
+ open: false,
+ active: false,
+ status: TreeItemStatus.INITIAL,
+ data: p,
+ items: []
+ }));
return {
...state,
- items,
- currentItemId: ""
+ items: state.items.length > 0 ?
+ rebuildTree(state.items, item => {
+ if (item.id === parentItemId) {
+ item.status = TreeItemStatus.LOADED;
+ item.items = items;
+ }
+ }) : items
};
},
+ TOGGLE_PROJECT_TREE_ITEM_OPEN: ({ itemId, open, recursive }) => ({
+ ...state,
+ items: rebuildTree(state.items, (item, visitedItems) => {
+ if (item.id === itemId) {
+ if (recursive && open !== undefined) {
+ visitedItems.forEach(item => item.open = open);
+ }
+ item.open = open !== undefined ? open : !item.open;
+ }
+ }),
+ currentItemId: itemId
+ }),
+ TOGGLE_PROJECT_TREE_ITEM_ACTIVE: ({ itemId, active, recursive }) => ({
+ ...state,
+ items: rebuildTree(state.items, (item, visitedItems) => {
+ item.active = false;
+ if (item.id === itemId) {
+ if (recursive && active !== undefined) {
+ visitedItems.forEach(item => item.active = active);
+ }
+
+ item.active = active !== undefined ? active : true;
+ }
+ }),
+ currentItemId: itemId
+ }),
+ RESET_PROJECT_TREE_ACTIVITY: () => ({
+ ...state,
+ items: rebuildTree(state.items, item => {
+ item.active = false;
+ }),
+ currentItemId: ""
+ }),
default: () => state
});
};
openAble: true,
activeAction: (dispatch: Dispatch, uuid: string) => {
dispatch(push(getProjectUrl(uuid)));
- dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE(uuid));
+ dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM_ACTIVE({ itemId: uuid }));
dispatch(projectPanelActions.SET_COLUMNS({ columns: projectPanelColumns }));
dispatch(projectPanelActions.RESET_PAGINATION());
dispatch(projectPanelActions.REQUEST_ITEMS());
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
+ this.services.groupsService
.contents(userUuid, {
limit: dataExplorer.rowsPerPage,
offset: dataExplorer.page * dataExplorer.rowsPerPage,
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,
import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGraphIcon, AdvancedIcon, RemoveIcon } from "~/components/icon/icon";
import { openUpdater } from "~/store/collections/updater/collection-updater-action";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
+import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
+import { toggleCollectionTrashed } from "~/store/collections/collection-trash-actions";
export const collectionActionSet: ContextMenuActionSet = [[
{
});
}
},
+ {
+ component: ToggleTrashAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleCollectionTrashed(resource));
+ }
+ },
{
icon: CopyIcon,
name: "Copy to project",
import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, RemoveIcon } from "~/components/icon/icon";
import { openUpdater } from "~/store/collections/updater/collection-updater-action";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
+import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
+import { toggleCollectionTrashed } from "~/store/collections/collection-trash-actions";
export const collectionResourceActionSet: ContextMenuActionSet = [[
{
});
}
},
+ {
+ component: ToggleTrashAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleCollectionTrashed(resource));
+ }
+ },
{
icon: CopyIcon,
name: "Copy to project",
import { reset, initialize } from "redux-form";
import { ContextMenuActionSet } from "../context-menu-action-set";
-import { projectActions, PROJECT_FORM_NAME } from "~/store/project/project-action";
+import { projectActions, PROJECT_FORM_NAME, toggleProjectTrashed } from "~/store/project/project-action";
import { NewProjectIcon, RenameIcon } from "~/components/icon/icon";
import { ToggleFavoriteAction } from "../actions/favorite-action";
import { toggleFavorite } from "~/store/favorites/favorites-actions";
import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
import { PROJECT_CREATE_DIALOG } from "../../dialog-create/dialog-project-create";
+import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
export const projectActionSet: ContextMenuActionSet = [[
{
dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
});
}
+ },
+ {
+ component: ToggleTrashAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleProjectTrashed(resource));
+ }
}
]];
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { ListItemIcon, ListItemText, ListItem } from "@material-ui/core";
+import { RestoreFromTrashIcon, TrashIcon } from "~/components/icon/icon";
+import { connect } from "react-redux";
+import { RootState } from "~/store/store";
+
+const mapStateToProps = (state: RootState, props: { onClick: () => {} }) => ({
+ isTrashed: state.contextMenu.resource && state.contextMenu.resource.isTrashed,
+ onClick: props.onClick
+});
+
+export const ToggleTrashAction = connect(mapStateToProps)((props: { isTrashed?: boolean, onClick: () => void }) =>
+ <ListItem button
+ onClick={props.onClick}>
+ <ListItemIcon>
+ {props.isTrashed
+ ? <RestoreFromTrashIcon/>
+ : <TrashIcon/>}
+ </ListItemIcon>
+ <ListItemText style={{ textDecoration: 'none' }}>
+ {props.isTrashed
+ ? <>Restore</>
+ : <>Move to trash</>}
+ </ListItemText>
+ </ListItem >);
tags: state.collectionPanel.tags
}))(
class extends React.Component<CollectionPanelProps> {
-
render() {
const { classes, item, tags, onContextMenu } = this.props;
return <div>
onItemRouteChange(match.params.id);
}
}
-
}
)
);
lastModified: string;
fileSize?: number;
status?: string;
+ isTrashed?: boolean;
}
export function resourceToDataItem(r: GroupContentsResource): FavoritePanelItem {
url: "",
owner: r.ownerUuid,
lastModified: r.modifiedAt,
- status: r.kind === ResourceKind.PROCESS ? r.state : undefined
+ status: r.kind === ResourceKind.PROCESS ? r.state : undefined,
+ isTrashed: r.kind === ResourceKind.GROUP || r.kind === ResourceKind.COLLECTION ? r.isTrashed: undefined
};
}
lastModified: string;
fileSize?: number;
status?: string;
+ isTrashed?: boolean;
}
export function resourceToDataItem(r: GroupContentsResource): ProjectPanelItem {
url: "",
owner: r.ownerUuid,
lastModified: r.modifiedAt,
- status: r.kind === ResourceKind.PROCESS ? r.state : undefined
+ status: r.kind === ResourceKind.PROCESS ? r.state : undefined,
+ isTrashed: r.kind === ResourceKind.GROUP || r.kind === ResourceKind.COLLECTION ? r.isTrashed: undefined
};
}
uuid: string;
name: string;
kind: string;
+ owner: string;
fileSize?: number;
trashAt?: string;
deleteAt?: string;
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
import { RouteComponentProps } from 'react-router';
import { RootState } from '~/store/store';
import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
-import { ProcessState } from '~/models/process';
import { SortDirection } from '~/components/data-table/data-column';
import { ResourceKind } from '~/models/resource';
import { resourceLabel } from '~/common/labels';
}
export interface TrashPanelFilter extends DataTableFilterItem {
- type: ResourceKind | ProcessState;
+ type: ResourceKind;
}
export const columns: DataColumns<TrashPanelItem, TrashPanelFilter> = [
toggleOpen={itemId => this.props.dispatch(setProjectItem(itemId, ItemMode.OPEN))}
onContextMenu={(event, item) => this.openContextMenu(event, {
uuid: item.data.uuid,
+ ownerUuid: item.data.ownerUuid || this.props.authService.getUuid(),
+ isTrashed: item.data.isTrashed,
name: item.data.name,
kind: ContextMenuKind.PROJECT
})}
uuid: item.uuid,
name: item.name,
description: item.description,
+ isTrashed: item.isTrashed,
kind: ContextMenuKind.COLLECTION
});
}}
uuid: item.uuid,
name: item.name,
description: item.description,
+ isTrashed: item.isTrashed,
+ ownerUuid: item.owner || this.props.authService.getUuid(),
kind
});
}}
this.openContextMenu(event, {
uuid: item.uuid,
name: item.name,
+ isTrashed: item.isTrashed,
kind,
});
}}
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;
+ const kind = item.kind === ResourceKind.PROJECT ? ContextMenuKind.PROJECT : ContextMenuKind.COLLECTION;
this.openContextMenu(event, {
uuid: item.uuid,
name: item.name,
+ isTrashed: item.isTrashed,
+ ownerUuid: item.owner,
kind,
});
}}
onDialogOpen={this.handleProjectCreationDialogOpen}
onItemClick={item => {
- this.props.dispatch(loadDetails(item.uuid, item.kind as ResourceKind));
+ // 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));
- }
+ // 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} />
this.props.dispatch(collectionCreateActions.OPEN_COLLECTION_CREATOR({ ownerUuid: itemUuid }));
}
- openContextMenu = (event: React.MouseEvent<HTMLElement>, resource: { name: string; uuid: string; description?: string; kind: ContextMenuKind; }) => {
+ openContextMenu = (event: React.MouseEvent<HTMLElement>, resource: { name: string; uuid: string; description?: string; isTrashed?: boolean, ownerUuid?: string, kind: ContextMenuKind; }) => {
event.preventDefault();
this.props.dispatch(
contextMenuActions.OPEN_CONTEXT_MENU({