19294: Add tooltip to participant select chip with username/email/uuid
authorStephen Smith <stephen@curii.com>
Fri, 10 Feb 2023 16:03:01 +0000 (11:03 -0500)
committerStephen Smith <stephen@curii.com>
Fri, 10 Feb 2023 16:03:01 +0000 (11:03 -0500)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/components/autocomplete/autocomplete.tsx
src/models/user.ts
src/views-components/sharing-dialog/participant-select.tsx

index 0044807b8a9ddb3e2abeb43a546dad5a2ada4d83..b2a10ec7b48996488a1ff1f8da6b28a4fb8fbc36 100644 (file)
@@ -8,7 +8,7 @@ import {
     Chip as MuiChip,
     Popper as MuiPopper,
     Paper as MuiPaper,
-    FormControl, InputLabel, StyleRulesCallback, withStyles, RootRef, ListItemText, ListItem, List, FormHelperText
+    FormControl, InputLabel, StyleRulesCallback, withStyles, RootRef, ListItemText, ListItem, List, FormHelperText, Tooltip
 } from '@material-ui/core';
 import { PopperProps } from '@material-ui/core/Popper';
 import { WithStyles } from '@material-ui/core/styles';
@@ -30,6 +30,7 @@ export interface AutocompleteProps<Item, Suggestion> {
     onDelete?: (item: Item, index: number) => void;
     onSelect?: (suggestion: Suggestion) => void;
     renderChipValue?: (item: Item) => string;
+    renderChipTooltip?: (item: Item) => string;
     renderSuggestion?: (suggestion: Suggestion) => React.ReactNode;
 }
 
@@ -171,11 +172,22 @@ export class Autocomplete<Value, Suggestion> extends React.Component<Autocomplet
         }
 
         return items.map(
-            (item, index) =>
-                <Chip
-                    label={this.renderChipValue(item)}
-                    key={index}
-                    onDelete={onDelete && !this.props.disabled ? (() =>  onDelete(item, index)) : undefined} />
+            (item, index) => {
+                const tooltip = this.props.renderChipTooltip ? this.props.renderChipTooltip(item) : '';
+                if (tooltip.length) {
+                    return <Tooltip title={tooltip}>
+                        <Chip
+                            label={this.renderChipValue(item)}
+                            key={index}
+                            onDelete={onDelete && !this.props.disabled ? (() =>  onDelete(item, index)) : undefined} />
+                    </Tooltip>
+                } else {
+                    return <Chip
+                        label={this.renderChipValue(item)}
+                        key={index}
+                        onDelete={onDelete && !this.props.disabled ? (() =>  onDelete(item, index)) : undefined} />
+                }
+            }
         );
     }
 
index 9b3d97d8486337befae509d35761d93cf1edf6be..6d66d9d32829fa39e6f8bb91fbd3d3f006272e0e 100644 (file)
@@ -44,6 +44,14 @@ export const getUserDisplayName = (user: User, withEmail = false, withUuid = fal
     return parts.join(' ');
 };
 
+export const getUserDetailsString = (user: User) => {
+    let parts: string[] = [];
+    user.username.length && parts.push(user.username);
+    user.email.length && parts.push(`<${user.email}>`);
+    user.uuid.length && parts.push(`(${user.uuid})`);
+    return parts.join(' ');
+};
+
 export interface UserResource extends Resource, User {
     kind: ResourceKind.USER;
     defaultOwnerUuid: string;
index ac5d6c2d9309c56978583090710d3526c4fb522c..02cdeaf2c28e814a3a1d72d24d8cfadfe143eee3 100644 (file)
@@ -11,12 +11,13 @@ import { debounce } from 'debounce';
 import { ListItemText, Typography } from '@material-ui/core';
 import { noop } from 'lodash/fp';
 import { GroupClass, GroupResource } from 'models/group';
-import { getUserDisplayName, UserResource } from 'models/user';
+import { getUserDetailsString, getUserDisplayName, UserResource } from 'models/user';
 import { Resource, ResourceKind } from 'models/resource';
 import { ListResults } from 'services/common-service/common-service';
 
 export interface Participant {
     name: string;
+    tooltip: string;
     uuid: string;
 }
 
@@ -54,6 +55,17 @@ const getDisplayName = (item: GroupResource | UserResource, detailed: boolean) =
     }
 };
 
+const getDisplayTooltip = (item: GroupResource | UserResource) => {
+    switch (item.kind) {
+        case ResourceKind.USER:
+            return getUserDetailsString(item);
+        case ResourceKind.GROUP:
+            return item.name + `(${`(${(item as Resource).uuid})`})`;
+        default:
+            return (item as Resource).uuid;
+    }
+};
+
 export const ParticipantSelect = connect()(
     class ParticipantSelect extends React.Component<ParticipantSelectProps & DispatchProp, ParticipantSelectState> {
         state: ParticipantSelectState = {
@@ -78,6 +90,7 @@ export const ParticipantSelect = connect()(
                     onFocus={this.props.onFocus}
                     onBlur={this.props.onBlur}
                     renderChipValue={this.renderChipValue}
+                    renderChipTooltip={this.renderChipTooltip}
                     renderSuggestion={this.renderSuggestion}
                     disabled={this.props.disabled}/>
             );
@@ -88,6 +101,10 @@ export const ParticipantSelect = connect()(
             return name || uuid;
         }
 
+        renderChipTooltip(item: Participant) {
+            return item.tooltip;
+        }
+
         renderSuggestion(item: ParticipantResource) {
             return (
                 <ListItemText>
@@ -107,6 +124,7 @@ export const ParticipantSelect = connect()(
                 this.setState({ value: '', suggestions: [] });
                 onCreate({
                     name: '',
+                    tooltip: '',
                     uuid: this.state.value,
                 });
             }
@@ -118,6 +136,7 @@ export const ParticipantSelect = connect()(
             this.setState({ value: '', suggestions: [] });
             onSelect({
                 name: getDisplayName(selection, false),
+                tooltip: getDisplayTooltip(selection),
                 uuid,
             });
         }