20382: cancel in context menu works for non-admins Arvados-DCO-1.1-Signed-off-by...
[arvados.git] / src / views / all-processes-panel / all-processes-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from "react";
6 import { StyleRulesCallback, WithStyles, withStyles } from "@material-ui/core";
7 import { DataExplorer } from "views-components/data-explorer/data-explorer";
8 import { connect, DispatchProp } from "react-redux";
9 import { DataColumns } from "components/data-table/data-table";
10 import { RouteComponentProps } from "react-router";
11 import { DataTableFilterItem } from "components/data-table-filters/data-table-filters";
12 import { SortDirection } from "components/data-table/data-column";
13 import { ResourceKind } from "models/resource";
14 import { ArvadosTheme } from "common/custom-theme";
15 import { ALL_PROCESSES_PANEL_ID } from "store/all-processes-panel/all-processes-panel-action";
16 import {
17     ProcessStatus,
18     ResourceName,
19     ResourceOwnerWithName,
20     ResourceType,
21     ContainerRunTime,
22     ResourceCreatedAtDate,
23 } from "views-components/data-explorer/renderers";
24 import { ProcessIcon } from "components/icon/icon";
25 import { openProcessContextMenu, openRunningProcessContextMenu } from "store/context-menu/context-menu-actions";
26 import { loadDetailsPanel } from "store/details-panel/details-panel-action";
27 import { navigateTo } from "store/navigation/navigation-action";
28 import { ContainerRequestResource, ContainerRequestState } from "models/container-request";
29 import { RootState } from "store/store";
30 import { createTree } from "models/tree";
31 import { getInitialProcessStatusFilters, getInitialProcessTypeFilters } from "store/resource-type-filters/resource-type-filters";
32 import { getProcess, isProcessCancelable } from "store/processes/process";
33 import { ResourcesState } from "store/resources/resources";
34
35 type CssRules = "toolbar" | "button" | "root";
36
37 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
38     toolbar: {
39         paddingBottom: theme.spacing.unit * 3,
40         textAlign: "right",
41     },
42     button: {
43         marginLeft: theme.spacing.unit,
44     },
45     root: {
46         width: "100%",
47     },
48 });
49
50 export enum AllProcessesPanelColumnNames {
51     NAME = "Name",
52     STATUS = "Status",
53     TYPE = "Type",
54     OWNER = "Owner",
55     CREATED_AT = "Created at",
56     RUNTIME = "Run Time",
57 }
58
59 export interface AllProcessesPanelFilter extends DataTableFilterItem {
60     type: ResourceKind | ContainerRequestState;
61 }
62
63 export const allProcessesPanelColumns: DataColumns<string, ContainerRequestResource> = [
64     {
65         name: AllProcessesPanelColumnNames.NAME,
66         selected: true,
67         configurable: true,
68         sort: { direction: SortDirection.NONE, field: "name" },
69         filters: createTree(),
70         render: uuid => <ResourceName uuid={uuid} />,
71     },
72     {
73         name: AllProcessesPanelColumnNames.STATUS,
74         selected: true,
75         configurable: true,
76         mutuallyExclusiveFilters: true,
77         filters: getInitialProcessStatusFilters(),
78         render: uuid => <ProcessStatus uuid={uuid} />,
79     },
80     {
81         name: AllProcessesPanelColumnNames.TYPE,
82         selected: true,
83         configurable: true,
84         filters: getInitialProcessTypeFilters(),
85         render: uuid => <ResourceType uuid={uuid} />,
86     },
87     {
88         name: AllProcessesPanelColumnNames.OWNER,
89         selected: true,
90         configurable: true,
91         filters: createTree(),
92         render: uuid => <ResourceOwnerWithName uuid={uuid} />,
93     },
94     {
95         name: AllProcessesPanelColumnNames.CREATED_AT,
96         selected: true,
97         configurable: true,
98         sort: { direction: SortDirection.DESC, field: "createdAt" },
99         filters: createTree(),
100         render: uuid => <ResourceCreatedAtDate uuid={uuid} />,
101     },
102     {
103         name: AllProcessesPanelColumnNames.RUNTIME,
104         selected: true,
105         configurable: true,
106         filters: createTree(),
107         render: uuid => <ContainerRunTime uuid={uuid} />,
108     },
109 ];
110
111 interface AllProcessesPanelDataProps {
112     resources: ResourcesState;
113 }
114
115 interface AllProcessesPanelActionProps {
116     onItemClick: (item: string) => void;
117     onDialogOpen: (ownerUuid: string) => void;
118     onItemDoubleClick: (item: string) => void;
119 }
120 const mapStateToProps = (state: RootState): AllProcessesPanelDataProps => ({
121     resources: state.resources,
122 });
123
124 type AllProcessesPanelProps = AllProcessesPanelDataProps &
125     AllProcessesPanelActionProps &
126     DispatchProp &
127     WithStyles<CssRules> &
128     RouteComponentProps<{ id: string }>;
129
130 export const AllProcessesPanel = withStyles(styles)(
131     connect(mapStateToProps)(
132         class extends React.Component<AllProcessesPanelProps> {
133             handleContextMenu = (event: React.MouseEvent<HTMLElement>, resourceUuid: string) => {
134                 const process = getProcess(resourceUuid)(this.props.resources);
135                 if (process && isProcessCancelable(process)) {
136                     this.props.dispatch<any>(openRunningProcessContextMenu(event, process));
137                 } else if (process) {
138                     this.props.dispatch<any>(openProcessContextMenu(event, process));
139                 }
140                 this.props.dispatch<any>(loadDetailsPanel(resourceUuid));
141             };
142
143             handleRowDoubleClick = (uuid: string) => {
144                 this.props.dispatch<any>(navigateTo(uuid));
145             };
146
147             handleRowClick = (uuid: string) => {
148                 this.props.dispatch<any>(loadDetailsPanel(uuid));
149             };
150
151             render() {
152                 return (
153                     <div className={this.props.classes.root}>
154                         <DataExplorer
155                             id={ALL_PROCESSES_PANEL_ID}
156                             onRowClick={this.handleRowClick}
157                             onRowDoubleClick={this.handleRowDoubleClick}
158                             onContextMenu={this.handleContextMenu}
159                             contextMenuColumn={true}
160                             defaultViewIcon={ProcessIcon}
161                             defaultViewMessages={["Processes list empty."]}
162                         />
163                     </div>
164                 );
165             }
166         }
167     )
168 );