Merge branch '14434-display-workflow-name'
[arvados-workbench2.git] / src / views-components / sharing-dialog / people-select.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { Autocomplete } from '~/components/autocomplete/autocomplete';
7 import { UserResource } from '~/models/user';
8 import { connect, DispatchProp } from 'react-redux';
9 import { ServiceRepository } from '~/services/services';
10 import { FilterBuilder } from '../../services/api/filter-builder';
11 import { debounce } from 'debounce';
12 import { ListItemText, Typography } from '@material-ui/core';
13 import { noop } from 'lodash/fp';
14
15 export interface Person {
16     name: string;
17     email: string;
18     uuid: string;
19 }
20
21 export interface PeopleSelectProps {
22
23     items: Person[];
24     label?: string;
25     autofocus?: boolean;
26
27     onBlur?: (event: React.FocusEvent<HTMLInputElement>) => void;
28     onFocus?: (event: React.FocusEvent<HTMLInputElement>) => void;
29     onCreate?: (person: Person) => void;
30     onDelete?: (index: number) => void;
31     onSelect?: (person: Person) => void;
32
33 }
34
35 export interface PeopleSelectState {
36     value: string;
37     suggestions: UserResource[];
38 }
39
40 export const PeopleSelect = connect()(
41     class PeopleSelect extends React.Component<PeopleSelectProps & DispatchProp, PeopleSelectState> {
42
43         state: PeopleSelectState = {
44             value: '',
45             suggestions: []
46         };
47
48         render() {
49
50             const { label = 'Invite people' } = this.props;
51
52             return (
53                 <Autocomplete
54                     label={label}
55                     value={this.state.value}
56                     items={this.props.items}
57                     suggestions={this.state.suggestions}
58                     autofocus={this.props.autofocus}
59                     onChange={this.handleChange}
60                     onCreate={this.handleCreate}
61                     onSelect={this.handleSelect}
62                     onDelete={this.handleDelete}
63                     onFocus={this.props.onFocus}
64                     onBlur={this.props.onBlur}
65                     renderChipValue={this.renderChipValue}
66                     renderSuggestion={this.renderSuggestion} />
67             );
68         }
69
70         renderChipValue({ name, uuid }: Person) {
71             return name ? name : uuid;
72         }
73
74         renderSuggestion({ firstName, lastName, email }: UserResource) {
75             return (
76                 <ListItemText>
77                     <Typography noWrap>{`${firstName} ${lastName} <<${email}>>`}</Typography>
78                 </ListItemText>
79             );
80         }
81
82         handleDelete = (_: Person, index: number) => {
83             const { onDelete = noop } = this.props;
84             onDelete(index);
85         }
86
87         handleCreate = () => {
88             const { onCreate } = this.props;
89             if (onCreate) {
90                 this.setState({ value: '', suggestions: [] });
91                 onCreate({
92                     email: '',
93                     name: '',
94                     uuid: this.state.value,
95                 });
96             }
97         }
98
99         handleSelect = ({ email, firstName, lastName, uuid }: UserResource) => {
100             const { onSelect = noop } = this.props;
101             this.setState({ value: '', suggestions: [] });
102             onSelect({
103                 email,
104                 name: `${firstName} ${lastName}`,
105                 uuid,
106             });
107         }
108
109         handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
110             this.setState({ value: event.target.value }, this.getSuggestions);
111         }
112
113         getSuggestions = debounce(() => this.props.dispatch<any>(this.requestSuggestions), 500);
114
115         requestSuggestions = async (_: void, __: void, { userService }: ServiceRepository) => {
116             const { value } = this.state;
117             const filters = new FilterBuilder()
118                 .addILike('email', value)
119                 .getFilters();
120             const { items } = await userService.list({ filters, limit: 5 });
121             this.setState({ suggestions: items });
122         }
123
124     });