21838: Add redux saga and convert loadProject into saga
[arvados.git] / services / workbench2 / src / views-components / projects-tree-picker / tree-picker-field.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 { Typography } from "@mui/material";
7 import { TreeItem } from "components/tree/tree";
8 import { WrappedFieldProps } from 'redux-form';
9 import { ProjectsTreePicker } from 'views-components/projects-tree-picker/projects-tree-picker';
10 import { ProjectsTreePickerItem } from 'store/tree-picker/tree-picker-middleware';
11 import { PickerIdProp } from 'store/tree-picker/picker-id';
12 import { FileOperationLocation, getFileOperationLocation, SEARCH_PROJECT_ID_PREFIX } from "store/tree-picker/tree-picker-actions";
13 import { connect } from "react-redux";
14 import { Dispatch } from "redux";
15
16 export const ProjectTreePickerField = (props: WrappedFieldProps & PickerIdProp) =>
17     <div style={{ display: 'flex', minHeight: 0, flexDirection: 'column' }}>
18         <div style={{ flexBasis: '960px', flexShrink: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
19             <ProjectsTreePicker
20                 pickerId={props.pickerId}
21                 toggleItemActive={handleChange(props)}
22                 cascadeSelection={false}
23                 options={{ showOnlyOwned: false, showOnlyWritable: true }} />
24             {props.meta.dirty && props.meta.error &&
25                 <Typography variant='caption' color='error'>
26                     {props.meta.error}
27                 </Typography>}
28         </div>
29     </div>;
30
31 const handleChange = (props: WrappedFieldProps) =>
32     (_: any, { id }: TreeItem<ProjectsTreePickerItem>) => {
33         if (id.startsWith(SEARCH_PROJECT_ID_PREFIX)) {
34             props.input.onChange(id.slice(SEARCH_PROJECT_ID_PREFIX.length));
35         } else {
36             props.input.onChange(id);
37         }
38     }
39
40 export const CollectionTreePickerField = (props: WrappedFieldProps & PickerIdProp) =>
41     <div style={{ display: 'flex', minHeight: 0, flexDirection: 'column' }}>
42         <div style={{ flexBasis: '275px', flexShrink: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
43             <ProjectsTreePicker
44                 pickerId={props.pickerId}
45                 toggleItemActive={handleChange(props)}
46                 cascadeSelection={false}
47                 options={{ showOnlyOwned: false, showOnlyWritable: true }}
48                 includeCollections />
49             {props.meta.dirty && props.meta.error &&
50                 <Typography variant='caption' color='error'>
51                     {props.meta.error}
52                 </Typography>}
53         </div>
54     </div>;
55
56 type ProjectsTreePickerActionProps = {
57     getFileOperationLocation: (item: ProjectsTreePickerItem) => Promise<FileOperationLocation | undefined>;
58 }
59
60 const projectsTreePickerMapDispatchToProps = (dispatch: Dispatch): ProjectsTreePickerActionProps => ({
61     getFileOperationLocation: (item: ProjectsTreePickerItem) => dispatch<any>(getFileOperationLocation(item)),
62 });
63
64 type ProjectsTreePickerCombinedProps = ProjectsTreePickerActionProps & WrappedFieldProps & PickerIdProp;
65
66 export const DirectoryTreePickerField = connect(null, projectsTreePickerMapDispatchToProps)(
67     class DirectoryTreePickerFieldComponent extends React.Component<ProjectsTreePickerCombinedProps> {
68
69         handleDirectoryChange = (props: WrappedFieldProps) =>
70             async (_: any, { data }: TreeItem<ProjectsTreePickerItem>) => {
71                 const location = await this.props.getFileOperationLocation(data);
72                 props.input.onChange(location || '');
73             }
74
75         render() {
76             return <div style={{ display: 'flex', minHeight: 0, flexDirection: 'column' }}>
77                 <div style={{ flexBasis: '275px', flexShrink: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
78                     <ProjectsTreePicker
79                         currentUuids={[this.props.input.value.uuid]}
80                         pickerId={this.props.pickerId}
81                         toggleItemActive={this.handleDirectoryChange(this.props)}
82                         cascadeSelection={false}
83                         options={{ showOnlyOwned: false, showOnlyWritable: true }}
84                         includeCollections
85                         includeDirectories />
86                     {this.props.meta.dirty && this.props.meta.error &&
87                         <Typography variant='caption' color='error'>
88                             {this.props.meta.error}
89                         </Typography>}
90                 </div>
91             </div>;
92         }
93     });