import { addRouteChangeHandlers } from './routes/routes';
import { loadWorkbench } from './store/workbench/workbench-actions';
import { Routes } from '~/routes/routes';
+import { trashActionSet } from "~/views-components/context-menu/action-sets/trash-action-set";
const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
const getGitCommit = () => "GIT-" + (process.env.REACT_APP_GIT_COMMIT || "latest").substr(0, 7);
addMenuActionSet(ContextMenuKind.COLLECTION, collectionActionSet);
addMenuActionSet(ContextMenuKind.COLLECTION_RESOURCE, collectionResourceActionSet);
addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
+addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
fetchConfig()
.then((config) => {
modifiedByUserUuid: string;
modifiedAt: string;
href: string;
- kind: string;
+ kind: ResourceKind;
etag: string;
}
PROJECT = "arvados#group",
USER = "arvados#user",
WORKFLOW = "arvados#workflow",
+ NONE = "arvados#none"
}
export enum ResourceObjectType {
createdAt: "",
etag: "",
href: "",
- kind: "",
+ kind: ResourceKind.NONE,
modifiedAt: "",
modifiedByClientUuid: "",
modifiedByUserUuid: "",
import { initialize, startSubmit, stopSubmit } from 'redux-form';
import { RootState } from "~/store/store";
import { collectionPanelActions } from "~/store/collection-panel/collection-panel-action";
-import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
import { dialogActions } from "~/store/dialog/dialog-actions";
-import { dataExplorerActions } from "~/store/data-explorer/data-explorer-action";
-import { snackbarActions } from "~/store/snackbar/snackbar-actions";
-import { ContextMenuResource } from '~/store/context-menu/context-menu-reducer';
-import { PROJECT_PANEL_ID } from "~/views/project-panel/project-panel";
import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
import { ServiceRepository } from "~/services/services";
import { CollectionResource } from '~/models/collection';
+import { ContextMenuResource } from "~/store/context-menu/context-menu-actions";
export interface CollectionUpdateFormDialogData {
uuid: string;
// SPDX-License-Identifier: AGPL-3.0
import { unionize, ofType, UnionOf } from '~/common/unionize';
-import { ContextMenuPosition, ContextMenuResource } from "./context-menu-reducer";
+import { ContextMenuPosition } from "./context-menu-reducer";
import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
import { Dispatch } from 'redux';
import { RootState } from '~/store/store';
import { ProjectResource } from '~/models/project';
import { UserResource } from '~/models/user';
import { isSidePanelTreeCategory } from '~/store/side-panel-tree/side-panel-tree-actions';
-import { extractUuidKind, ResourceKind } from '~/models/resource';
+import { extractUuidKind, ResourceKind, TrashableResource } from '~/models/resource';
export const contextMenuActions = unionize({
OPEN_CONTEXT_MENU: ofType<{ position: ContextMenuPosition, resource: ContextMenuResource }>(),
uuid: string;
ownerUuid: string;
description?: string;
- kind: ContextMenuKind;
+ kind: ResourceKind,
+ menuKind: ContextMenuKind;
isTrashed?: boolean;
};
name: '',
uuid: res.uuid,
ownerUuid: res.uuid,
- kind: ContextMenuKind.ROOT_PROJECT,
+ kind: res.kind,
+ menuKind: ContextMenuKind.ROOT_PROJECT,
isTrashed: false
}));
}
dispatch<any>(openContextMenu(event, {
name: res.name,
uuid: res.uuid,
- kind: ContextMenuKind.PROJECT,
+ kind: res.kind,
+ menuKind: ContextMenuKind.PROJECT,
ownerUuid: res.ownerUuid,
isTrashed: res.isTrashed
}));
(dispatch: Dispatch, getState: () => RootState) => {
const resource = {
uuid: '',
+ ownerUuid: '',
+ kind: ResourceKind.PROCESS,
name: '',
description: '',
- kind: ContextMenuKind.PROCESS
+ menuKind: ContextMenuKind.PROCESS
};
dispatch<any>(openContextMenu(event, resource));
};
//
// SPDX-License-Identifier: AGPL-3.0
-import { contextMenuActions, ContextMenuAction } from "./context-menu-actions";
+import { contextMenuActions, ContextMenuAction, ContextMenuResource } from "./context-menu-actions";
export interface ContextMenuState {
open: boolean;
y: number;
}
-export interface ContextMenuResource {
- uuid: string;
- kind: string;
- name: string;
- description?: string;
- isTrashed?: boolean;
- ownerUuid?: string;
-}
-
const initialState = {
open: false,
position: { x: 0, y: 0 }
import { initialize, startSubmit, stopSubmit } from 'redux-form';
import { RootState } from "~/store/store";
import { dialogActions } from "~/store/dialog/dialog-actions";
-import { ContextMenuResource } from '~/store/context-menu/context-menu-reducer';
import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
import { ServiceRepository } from "~/services/services";
import { ProjectResource } from '~/models/project';
+import { ContextMenuResource } from "~/store/context-menu/context-menu-actions";
export interface ProjectUpdateFormDialogData {
uuid: string;
import { activateSidePanelTreeItem, loadSidePanelTreeProjects } from "~/store/side-panel-tree/side-panel-tree-actions";
import { projectPanelActions } from "~/store/project-panel/project-panel-action";
-export const toggleProjectTrashed = (resource: { uuid: string; name: string, isTrashed?: boolean, ownerUuid?: string }) =>
+export const toggleProjectTrashed = (uuid: string, ownerUuid: string, isTrashed: boolean) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<any> => {
- if (resource.isTrashed) {
+ if (isTrashed) {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Restoring from trash..." }));
- await services.groupsService.untrash(resource.uuid);
- dispatch<any>(activateSidePanelTreeItem(resource.uuid));
+ await services.groupsService.untrash(uuid);
+ dispatch<any>(activateSidePanelTreeItem(uuid));
dispatch(trashPanelActions.REQUEST_ITEMS());
dispatch(snackbarActions.CLOSE_SNACKBAR());
dispatch(snackbarActions.OPEN_SNACKBAR({
}));
} else {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Moving to trash..." }));
- await services.groupsService.trash(resource.uuid);
- dispatch<any>(loadSidePanelTreeProjects(resource.ownerUuid!!));
+ await services.groupsService.trash(uuid);
+ dispatch<any>(loadSidePanelTreeProjects(ownerUuid));
dispatch(snackbarActions.CLOSE_SNACKBAR());
dispatch(snackbarActions.OPEN_SNACKBAR({
message: "Added to trash",
}
};
-export const toggleCollectionTrashed = (resource: { uuid: string; name: string, isTrashed?: boolean, ownerUuid?: string }) =>
+export const toggleCollectionTrashed = (uuid: string, isTrashed: boolean) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<any> => {
- if (resource.isTrashed) {
+ if (isTrashed) {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Restoring from trash..." }));
- await services.collectionService.untrash(resource.uuid);
+ await services.collectionService.untrash(uuid);
dispatch(trashPanelActions.REQUEST_ITEMS());
dispatch(snackbarActions.OPEN_SNACKBAR({
message: "Restored from trash",
}));
} else {
dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Moving to trash..." }));
- await services.collectionService.trash(resource.uuid);
+ await services.collectionService.trash(uuid);
dispatch(projectPanelActions.REQUEST_ITEMS());
dispatch(snackbarActions.OPEN_SNACKBAR({
message: "Added to trash",
// SPDX-License-Identifier: AGPL-3.0
import { connect } from "react-redux";
-import { CollectionPanelFiles as Component, CollectionPanelFilesProps } from "~/components/collection-panel-files/collection-panel-files";
+import {
+ CollectionPanelFiles as Component,
+ CollectionPanelFilesProps
+} from "~/components/collection-panel-files/collection-panel-files";
import { RootState } from "~/store/store";
-import { TreeItemStatus, TreeItem } from "~/components/tree/tree";
-import { CollectionPanelFilesState, CollectionPanelDirectory, CollectionPanelFile } from "~/store/collection-panel/collection-panel-files/collection-panel-files-state";
+import { TreeItem, TreeItemStatus } from "~/components/tree/tree";
+import {
+ CollectionPanelDirectory,
+ CollectionPanelFile,
+ CollectionPanelFilesState
+} from "~/store/collection-panel/collection-panel-files/collection-panel-files-state";
import { FileTreeData } from "~/components/file-tree/file-tree-data";
import { Dispatch } from "redux";
import { collectionPanelFilesAction } from "~/store/collection-panel/collection-panel-files/collection-panel-files-actions";
import { ContextMenuKind } from "../context-menu/context-menu";
-import { Tree, getNodeChildrenIds, getNode } from "~/models/tree";
+import { getNode, getNodeChildrenIds, Tree } from "~/models/tree";
import { CollectionFileType } from "~/models/collection-file";
import { openContextMenu } from '~/store/context-menu/context-menu-actions';
import { openUploadCollectionFilesDialog } from '~/store/collections/collection-upload-actions';
+import { ResourceKind } from "~/models/resource";
const memoizedMapStateToProps = () => {
let prevState: CollectionPanelFilesState;
dispatch(collectionPanelFilesAction.TOGGLE_COLLECTION_FILE_SELECTION({ id: item.id }));
},
onItemMenuOpen: (event, item) => {
- dispatch<any>(openContextMenu(event, { kind: ContextMenuKind.COLLECTION_FILES_ITEM, name: item.data.name, uuid: item.id }));
+ dispatch<any>(openContextMenu(event, { menuKind: ContextMenuKind.COLLECTION_FILES_ITEM, kind: ResourceKind.COLLECTION, name: item.data.name, uuid: item.id, ownerUuid: '' }));
},
onOptionsMenuOpen: (event) => {
- dispatch<any>(openContextMenu(event, { kind: ContextMenuKind.COLLECTION_FILES, name: '', uuid: '' }));
+ dispatch<any>(openContextMenu(event, { menuKind: ContextMenuKind.COLLECTION_FILES, kind: ResourceKind.COLLECTION, name: '', uuid: '', ownerUuid: '' }));
},
});
{
component: ToggleTrashAction,
execute: (dispatch, resource) => {
- dispatch<any>(toggleCollectionTrashed(resource));
+ dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
}
},
{
{
component: ToggleTrashAction,
execute: (dispatch, resource) => {
- dispatch<any>(toggleCollectionTrashed(resource));
+ dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
}
},
{
{
component: ToggleTrashAction,
execute: (dispatch, resource) => {
- dispatch<any>(toggleProjectTrashed(resource));
+ dispatch<any>(toggleProjectTrashed(resource.uuid, resource.ownerUuid, resource.isTrashed!!));
}
},
{
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ToggleTrashAction } from "~/views-components/context-menu/actions/trash-action";
+import { toggleCollectionTrashed } from "~/store/trash/trash-actions";
+
+export const trashActionSet: ContextMenuActionSet = [[
+ {
+ component: ToggleTrashAction,
+ execute: (dispatch, resource) => {
+ dispatch<any>(toggleCollectionTrashed(resource.uuid, resource.isTrashed!!));
+ }
+ },
+]];
import { Dispatch } from "redux";
import { ContextMenuItem } from "~/components/context-menu/context-menu";
-import { ContextMenuResource } from "~/store/context-menu/context-menu-reducer";
+import { ContextMenuResource } from "~/store/context-menu/context-menu-actions";
export interface ContextMenuAction extends ContextMenuItem {
execute(dispatch: Dispatch, resource: ContextMenuResource): void;
import { connect } from "react-redux";
import { RootState } from "~/store/store";
-import { contextMenuActions } from "~/store/context-menu/context-menu-actions";
+import { contextMenuActions, ContextMenuResource } from "~/store/context-menu/context-menu-actions";
import { ContextMenu as ContextMenuComponent, ContextMenuProps, ContextMenuItem } from "~/components/context-menu/context-menu";
import { createAnchorAt } from "~/components/popover/helpers";
-import { ContextMenuResource } from "~/store/context-menu/context-menu-reducer";
import { ContextMenuActionSet, ContextMenuAction } from "./context-menu-action-set";
import { Dispatch } from "redux";
};
const getMenuActionSet = (resource?: ContextMenuResource): ContextMenuActionSet => {
- return resource ? menuActionSets.get(resource.kind) || [] : [];
+ return resource ? menuActionSets.get(resource.menuKind) || [] : [];
};
export enum ContextMenuKind {
PROJECT = "Project",
RESOURCE = "Resource",
FAVORITE = "Favorite",
+ TRASH = "Trash",
COLLECTION_FILES = "CollectionFiles",
COLLECTION_FILES_ITEM = "CollectionFilesItem",
COLLECTION = 'Collection',
import { deleteCollectionTag } from '~/store/collection-panel/collection-panel-action';
import { snackbarActions } from '~/store/snackbar/snackbar-actions';
import { getResource } from '~/store/resources/resources';
-import { contextMenuActions, openContextMenu } from '~/store/context-menu/context-menu-actions';
+import { openContextMenu } from '~/store/context-menu/context-menu-actions';
import { ContextMenuKind } from '~/views-components/context-menu/context-menu';
type CssRules = 'card' | 'iconHeader' | 'tag' | 'copyIcon' | 'label' | 'value';
}
handleContextMenu = (event: React.MouseEvent<any>) => {
- const { uuid, name, description } = this.props.item;
+ const { uuid, ownerUuid, name, description, kind } = this.props.item;
const resource = {
uuid,
+ ownerUuid,
name,
description,
- kind: ContextMenuKind.COLLECTION
+ kind,
+ menuKind: ContextMenuKind.COLLECTION
};
this.props.dispatch<any>(openContextMenu(event, resource));
}
import * as React from 'react';
import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
-import { DispatchProp, connect } from 'react-redux';
+import { connect, DispatchProp } from 'react-redux';
import { DataColumns } from '~/components/data-table/data-table';
import { RouteComponentProps } from 'react-router';
import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
import { resourceLabel } from '~/common/labels';
import { ArvadosTheme } from '~/common/custom-theme';
import { FAVORITE_PANEL_ID } from "~/store/favorite-panel/favorite-panel-action";
-import { ResourceFileSize, ResourceLastModifiedDate, ProcessStatus, ResourceType, ResourceOwner, ResourceName } from '~/views-components/data-explorer/renderers';
+import {
+ ProcessStatus,
+ ResourceFileSize,
+ ResourceLastModifiedDate,
+ ResourceName,
+ ResourceOwner,
+ ResourceType
+} from '~/views-components/data-explorer/renderers';
import { FavoriteIcon } from '~/components/icon/icon';
import { Dispatch } from 'redux';
import { openContextMenu, resourceKindToContextMenuKind } from '~/store/context-menu/context-menu-actions';
onContextMenu: (event, resourceUuid) => {
const kind = resourceKindToContextMenuKind(resourceUuid);
if (kind) {
- dispatch<any>(openContextMenu(event, { name: '', uuid: resourceUuid, kind }));
+ dispatch<any>(openContextMenu(event, {
+ name: '',
+ uuid: resourceUuid,
+ ownerUuid: '',
+ kind: ResourceKind.NONE,
+ menuKind: kind
+ }));
}
},
onDialogOpen: (ownerUuid: string) => { return; },
}
handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
- const kind = resourceKindToContextMenuKind(resourceUuid);
+ const menuKind = resourceKindToContextMenuKind(resourceUuid);
const resource = getResource<ProjectResource>(resourceUuid)(this.props.resources);
- if (kind && resource) {
+ if (menuKind && resource) {
this.props.dispatch<any>(openContextMenu(event, {
name: resource.name,
uuid: resource.uuid,
ownerUuid: resource.ownerUuid,
isTrashed: resource.isTrashed,
- kind
+ kind: resource.kind,
+ menuKind
}));
}
}
import * as React from 'react';
import { IconButton, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
-import { DispatchProp, connect } from 'react-redux';
+import { connect, DispatchProp } from 'react-redux';
import { DataColumns } from '~/components/data-table/data-table';
import { RootState } from '~/store/store';
import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
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 { ContextMenuResource, openContextMenu } from "~/store/context-menu/context-menu-actions";
import { getResource, ResourcesState } from "~/store/resources/resources";
import {
- renderDate,
ResourceDeleteDate,
ResourceFileSize,
ResourceName,
import { navigateTo } from "~/store/navigation/navigation-action";
import { loadDetailsPanel } from "~/store/details-panel/details-panel-action";
import { toggleCollectionTrashed, toggleProjectTrashed } from "~/store/trash/trash-actions";
+import { ContextMenuKind } from "~/views-components/context-menu/context-menu";
import { Dispatch } from "redux";
type CssRules = "toolbar" | "button";
})((props: { resource?: TrashableResource, dispatch?: Dispatch<any> }) =>
<IconButton onClick={() => {
if (props.resource && props.dispatch) {
- const ctxRes = {
- name: '',
- uuid: props.resource.uuid,
- isTrashed: props.resource.isTrashed,
- ownerUuid: props.resource.ownerUuid
- };
+ const res = props.resource;
if (props.resource.kind === ResourceKind.PROJECT) {
- props.dispatch(toggleProjectTrashed(ctxRes));
+ props.dispatch(toggleProjectTrashed(res.uuid, res.ownerUuid, res.isTrashed));
} else if (props.resource.kind === ResourceKind.COLLECTION) {
- props.dispatch(toggleCollectionTrashed(ctxRes));
+ props.dispatch(toggleCollectionTrashed(res.uuid, res.isTrashed));
}
}
}}>
}
handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
- const kind = resourceKindToContextMenuKind(resourceUuid);
- const resource = getResource(resourceUuid)(this.props.resources) as TrashableResource;
- if (kind && resource) {
+ const resource = getResource<TrashableResource>(resourceUuid)(this.props.resources);
+ if (resource) {
this.props.dispatch<any>(openContextMenu(event, {
name: '',
uuid: resource.uuid,
ownerUuid: resource.ownerUuid,
isTrashed: resource.isTrashed,
- kind
+ kind: resource.kind,
+ menuKind: ContextMenuKind.TRASH
}));
}
}