mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
Added user avatar tooltip (#142162)
* Added user avatar tooltip * Updated js docs
This commit is contained in:
parent
40b397d0e1
commit
44b38630e6
9 changed files with 334 additions and 10 deletions
|
@ -31,6 +31,5 @@ export const PanelWithCodeBlock: React.FunctionComponent<PanelWithCodeBlockProps
|
||||||
</EuiCodeBlock>
|
</EuiCodeBlock>
|
||||||
</EuiSplitPanel.Inner>
|
</EuiSplitPanel.Inner>
|
||||||
</EuiSplitPanel.Outer>
|
</EuiSplitPanel.Outer>
|
||||||
<EuiSpacer size="l" />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||||
import { AvatarDemo } from './avatar_demo';
|
import { AvatarDemo } from './avatar_demo';
|
||||||
import { PopoverDemo } from './popover_demo';
|
import { PopoverDemo } from './popover_demo';
|
||||||
import { SelectableDemo } from './selectable_demo';
|
import { SelectableDemo } from './selectable_demo';
|
||||||
|
import { ToolTipDemo } from './tooltip_demo';
|
||||||
|
|
||||||
interface SetupDeps {
|
interface SetupDeps {
|
||||||
developerExamples: DeveloperExamplesSetup;
|
developerExamples: DeveloperExamplesSetup;
|
||||||
|
@ -38,14 +39,20 @@ export class UserProfilesPlugin implements Plugin<void, void, SetupDeps, StartDe
|
||||||
// });
|
// });
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<KibanaPageTemplate
|
<KibanaPageTemplate>
|
||||||
pageHeader={{
|
<KibanaPageTemplate.Header pageTitle="User profile components" />
|
||||||
pageTitle: 'User profile components',
|
<KibanaPageTemplate.Section>
|
||||||
}}
|
<AvatarDemo />
|
||||||
>
|
</KibanaPageTemplate.Section>
|
||||||
<AvatarDemo />
|
<KibanaPageTemplate.Section>
|
||||||
<SelectableDemo />
|
<ToolTipDemo />
|
||||||
<PopoverDemo />
|
</KibanaPageTemplate.Section>
|
||||||
|
<KibanaPageTemplate.Section>
|
||||||
|
<SelectableDemo />
|
||||||
|
</KibanaPageTemplate.Section>
|
||||||
|
<KibanaPageTemplate.Section>
|
||||||
|
<PopoverDemo />
|
||||||
|
</KibanaPageTemplate.Section>
|
||||||
</KibanaPageTemplate>,
|
</KibanaPageTemplate>,
|
||||||
element
|
element
|
||||||
);
|
);
|
||||||
|
|
62
examples/user_profile_examples/public/tooltip_demo.tsx
Normal file
62
examples/user_profile_examples/public/tooltip_demo.tsx
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import { UserAvatarTip, UserToolTip } from '@kbn/user-profile-components';
|
||||||
|
import type { UserProfile, UserProfileAvatarData } from '@kbn/user-profile-components';
|
||||||
|
import { EuiCommentList, EuiComment } from '@elastic/eui';
|
||||||
|
import { PanelWithCodeBlock } from './panel_with_code_block';
|
||||||
|
|
||||||
|
export const ToolTipDemo: FunctionComponent = () => {
|
||||||
|
const userProfile: UserProfile<{ avatar: UserProfileAvatarData }> = {
|
||||||
|
uid: 'u_9xDEQqUqoYCnFnPPLq5mIRHKL8gBTo_NiKgOnd5gGk0_0',
|
||||||
|
enabled: true,
|
||||||
|
user: {
|
||||||
|
username: 'wet_dingo',
|
||||||
|
email: 'wet_dingo@elastic.co',
|
||||||
|
full_name: 'Wet Dingo',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
avatar: {
|
||||||
|
color: '#09e8ca',
|
||||||
|
initials: 'WD',
|
||||||
|
imageUrl: 'https://source.unsplash.com/64x64/?dingo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelWithCodeBlock title="Tooltip" code={code}>
|
||||||
|
<EuiCommentList>
|
||||||
|
<EuiComment
|
||||||
|
timelineAvatar={
|
||||||
|
<UserAvatarTip user={userProfile.user} avatar={userProfile.data.avatar} />
|
||||||
|
}
|
||||||
|
username={
|
||||||
|
<UserToolTip
|
||||||
|
position="top"
|
||||||
|
delay="regular"
|
||||||
|
user={userProfile.user}
|
||||||
|
avatar={userProfile.data.avatar}
|
||||||
|
>
|
||||||
|
<strong>{userProfile.user.full_name}</strong>
|
||||||
|
</UserToolTip>
|
||||||
|
}
|
||||||
|
event="pushed incident X0Z235 on Jan 3, 2020"
|
||||||
|
/>
|
||||||
|
</EuiCommentList>
|
||||||
|
</PanelWithCodeBlock>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const code = `import { UserToolTip, UserAvatarTip } from '@kbn/user-profile-components';
|
||||||
|
|
||||||
|
<UserToolTip user={userProfile.user} avatar={userProfile.data.avatar}>
|
||||||
|
<!-- An inline element to trigger the tooltip -->
|
||||||
|
</UserToolTip>
|
||||||
|
|
||||||
|
<UserAvatarTip user={userProfile.user} avatar={userProfile.data.avatar} />`;
|
|
@ -7,9 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type { UserAvatarProps, UserProfileWithAvatar } from './src/user_avatar';
|
export type { UserAvatarProps, UserProfileWithAvatar } from './src/user_avatar';
|
||||||
|
export type { UserToolTipProps } from './src/user_tooltip';
|
||||||
export type { UserProfilesSelectableProps } from './src/user_profiles_selectable';
|
export type { UserProfilesSelectableProps } from './src/user_profiles_selectable';
|
||||||
export type { UserProfilesPopoverProps } from './src/user_profiles_popover';
|
export type { UserProfilesPopoverProps } from './src/user_profiles_popover';
|
||||||
export { UserAvatar } from './src/user_avatar';
|
export { UserAvatar } from './src/user_avatar';
|
||||||
|
export { UserAvatarTip } from './src/user_avatar_tip';
|
||||||
|
export { UserToolTip } from './src/user_tooltip';
|
||||||
export { UserProfilesSelectable } from './src/user_profiles_selectable';
|
export { UserProfilesSelectable } from './src/user_profiles_selectable';
|
||||||
export { UserProfilesPopover } from './src/user_profiles_popover';
|
export { UserProfilesPopover } from './src/user_profiles_popover';
|
||||||
export { getUserDisplayName } from './src/user_profile';
|
export { getUserDisplayName } from './src/user_profile';
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { UserAvatarTip } from './user_avatar_tip';
|
||||||
|
|
||||||
|
describe('UserAvatarTip', () => {
|
||||||
|
it('should render `UserToolTip` correctly with `UserAvatar`', () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<UserAvatarTip
|
||||||
|
user={{
|
||||||
|
username: 'delighted_nightingale',
|
||||||
|
email: 'delighted_nightingale@elastic.co',
|
||||||
|
full_name: 'Delighted Nightingale',
|
||||||
|
}}
|
||||||
|
avatar={{
|
||||||
|
color: '#09e8ca',
|
||||||
|
initials: 'DN',
|
||||||
|
imageUrl: 'https://source.unsplash.com/64x64/?cat',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper).toMatchInlineSnapshot(`
|
||||||
|
<UserToolTip
|
||||||
|
avatar={
|
||||||
|
Object {
|
||||||
|
"color": "#09e8ca",
|
||||||
|
"imageUrl": "https://source.unsplash.com/64x64/?cat",
|
||||||
|
"initials": "DN",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay="regular"
|
||||||
|
position="top"
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"email": "delighted_nightingale@elastic.co",
|
||||||
|
"full_name": "Delighted Nightingale",
|
||||||
|
"username": "delighted_nightingale",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<UserAvatar
|
||||||
|
avatar={
|
||||||
|
Object {
|
||||||
|
"color": "#09e8ca",
|
||||||
|
"imageUrl": "https://source.unsplash.com/64x64/?cat",
|
||||||
|
"initials": "DN",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"email": "delighted_nightingale@elastic.co",
|
||||||
|
"full_name": "Delighted Nightingale",
|
||||||
|
"username": "delighted_nightingale",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</UserToolTip>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render `UserToolTip` when user is not set', () => {
|
||||||
|
const wrapper = shallow(<UserAvatarTip />);
|
||||||
|
expect(wrapper).toMatchInlineSnapshot(`<UserAvatar />`);
|
||||||
|
});
|
||||||
|
});
|
29
packages/kbn-user-profile-components/src/user_avatar_tip.tsx
Normal file
29
packages/kbn-user-profile-components/src/user_avatar_tip.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { FunctionComponent } from 'react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import type { UserAvatarProps } from './user_avatar';
|
||||||
|
import { UserAvatar } from './user_avatar';
|
||||||
|
import { UserToolTip } from './user_tooltip';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a user avatar with tooltip
|
||||||
|
*/
|
||||||
|
export const UserAvatarTip: FunctionComponent<UserAvatarProps> = ({ user, avatar, ...rest }) => {
|
||||||
|
if (!user) {
|
||||||
|
return <UserAvatar {...rest} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserToolTip user={user} avatar={avatar} position="top" delay="regular">
|
||||||
|
<UserAvatar user={user} avatar={avatar} {...rest} />
|
||||||
|
</UserToolTip>
|
||||||
|
);
|
||||||
|
};
|
|
@ -301,7 +301,7 @@ export const UserProfilesSelectable = <Option extends UserProfileWithAvatar | nu
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<EuiHighlight search={searchValue}>{option.label}</EuiHighlight>
|
<EuiHighlight search={searchValue}>{option.label}</EuiHighlight>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
{option.user.email ? (
|
{option.user.email && option.user.email !== option.label ? (
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<EuiTextColor color="subdued">
|
<EuiTextColor color="subdued">
|
||||||
{searchValue ? (
|
{searchValue ? (
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { UserToolTip } from './user_tooltip';
|
||||||
|
|
||||||
|
describe('UserToolTip', () => {
|
||||||
|
it('should render `EuiToolTip` correctly with `UserAvatar`', () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<UserToolTip
|
||||||
|
user={{
|
||||||
|
username: 'delighted_nightingale',
|
||||||
|
email: 'delighted_nightingale@elastic.co',
|
||||||
|
full_name: 'Delighted Nightingale',
|
||||||
|
}}
|
||||||
|
avatar={{
|
||||||
|
color: '#09e8ca',
|
||||||
|
initials: 'DN',
|
||||||
|
imageUrl: 'https://source.unsplash.com/64x64/?cat',
|
||||||
|
}}
|
||||||
|
position="top"
|
||||||
|
delay="regular"
|
||||||
|
>
|
||||||
|
<button>Toggle</button>
|
||||||
|
</UserToolTip>
|
||||||
|
);
|
||||||
|
expect(wrapper).toMatchInlineSnapshot(`
|
||||||
|
<EuiToolTip
|
||||||
|
content={
|
||||||
|
<EuiFlexGroup
|
||||||
|
alignItems="center"
|
||||||
|
gutterSize="s"
|
||||||
|
>
|
||||||
|
<EuiFlexItem
|
||||||
|
grow={false}
|
||||||
|
>
|
||||||
|
<UserAvatar
|
||||||
|
avatar={
|
||||||
|
Object {
|
||||||
|
"color": "#09e8ca",
|
||||||
|
"imageUrl": "https://source.unsplash.com/64x64/?cat",
|
||||||
|
"initials": "DN",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size="l"
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"email": "delighted_nightingale@elastic.co",
|
||||||
|
"full_name": "Delighted Nightingale",
|
||||||
|
"username": "delighted_nightingale",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem
|
||||||
|
grow={true}
|
||||||
|
>
|
||||||
|
<EuiFlexGroup
|
||||||
|
direction="column"
|
||||||
|
gutterSize="none"
|
||||||
|
>
|
||||||
|
<EuiFlexItem>
|
||||||
|
<strong>
|
||||||
|
Delighted Nightingale
|
||||||
|
</strong>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem>
|
||||||
|
delighted_nightingale@elastic.co
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
}
|
||||||
|
delay="regular"
|
||||||
|
display="inlineBlock"
|
||||||
|
position="top"
|
||||||
|
>
|
||||||
|
<button>
|
||||||
|
Toggle
|
||||||
|
</button>
|
||||||
|
</EuiToolTip>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
60
packages/kbn-user-profile-components/src/user_tooltip.tsx
Normal file
60
packages/kbn-user-profile-components/src/user_tooltip.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { EuiToolTipProps } from '@elastic/eui';
|
||||||
|
import { EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||||
|
import type { FunctionComponent } from 'react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import type { UserProfileUserInfo, UserProfileAvatarData } from './user_profile';
|
||||||
|
import { UserAvatar } from './user_avatar';
|
||||||
|
import { getUserDisplayName } from './user_profile';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props of {@link UserToolTip} component
|
||||||
|
*/
|
||||||
|
export interface UserToolTipProps extends Omit<EuiToolTipProps, 'content' | 'title'> {
|
||||||
|
/**
|
||||||
|
* User to be rendered
|
||||||
|
*/
|
||||||
|
user: UserProfileUserInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avatar data of user to be rendered
|
||||||
|
*/
|
||||||
|
avatar?: UserProfileAvatarData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a tooltip with user information
|
||||||
|
*/
|
||||||
|
export const UserToolTip: FunctionComponent<UserToolTipProps> = ({ user, avatar, ...rest }) => {
|
||||||
|
const displayName = getUserDisplayName(user);
|
||||||
|
return (
|
||||||
|
<EuiToolTip
|
||||||
|
content={
|
||||||
|
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<UserAvatar user={user} avatar={avatar} size="l" />
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem grow>
|
||||||
|
<EuiFlexGroup direction="column" gutterSize="none">
|
||||||
|
<EuiFlexItem>
|
||||||
|
<strong>{displayName}</strong>
|
||||||
|
</EuiFlexItem>
|
||||||
|
{user.email && user.email !== displayName ? (
|
||||||
|
<EuiFlexItem>{user.email}</EuiFlexItem>
|
||||||
|
) : undefined}
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue