[SecuritySolution] Display full name in greetings (#180670)

## Summary

We could find the user's full name might not always be available from
the 1st image below, but username should always exist.
Previously, we displayed username straight away and it didn't look good.
[bug](https://github.com/elastic/kibana/issues/177204)
In this PR, we change the logic and display user's full name if it
exists, otherwise fallback to the username.


**No Full Name scenario - It displays username**

<img width="2293" alt="Screenshot 2024-04-12 at 09 58 52"
src="355e5a3d-e8f8-4204-8234-8eddd14691e1">


<img width="2559" alt="Screenshot 2024-04-12 at 09 59 18"
src="14ba8250-57cf-4fc1-9bdf-a3ac021b91c8">

**Full Name available scenario - It displays the full name**

<img width="2291" alt="Screenshot 2024-04-12 at 10 07 28"
src="57cb5aa2-ae23-4e0b-bd13-7b6d72edce40">
<img width="2557" alt="Screenshot 2024-04-12 at 10 08 24"
src="a4cbd64f-7eef-454b-a5fc-e12f25a82ea5">

### Checklist

Delete any items that are not applicable to this PR.


- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Angela Chuang 2024-04-15 14:15:48 +01:00 committed by GitHub
parent bcd709352a
commit 01e2379929
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 103 additions and 4 deletions

View file

@ -22,6 +22,7 @@ jest.mock('../../../lib/kibana', () => {
const original = jest.requireActual('../../../lib/kibana');
return {
...original,
useCurrentUser: jest.fn().mockReturnValue({ fullName: 'UserFullName' }),
useAppUrl: jest.fn().mockReturnValue({ getAppUrl: jest.fn().mockReturnValue('mock url') }),
};
});
@ -63,10 +64,14 @@ describe('OnboardingComponent', () => {
ViewAlertsSteps.viewAlerts,
],
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should render page title, subtitle, and description', () => {
const { getByText } = render(<OnboardingComponent {...props} />);
const pageTitle = getByText('Hi Unknown!');
const pageTitle = getByText('Hi UserFullName!');
const subtitle = getByText(`Get started with Security`);
const description = getByText(
`This area shows you everything you need to know. Feel free to explore all content. You can always come back here at any time.`

View file

@ -0,0 +1,86 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { render } from '@testing-library/react';
import { WelcomeHeader } from '.';
import { useCurrentUser } from '../../../../lib/kibana';
import { CurrentPlan } from './current_plan';
import { ProductTier } from '../configs';
import { useProjectFeaturesUrl } from '../hooks/use_project_features_url';
jest.mock('../../../../lib/kibana', () => ({
useCurrentUser: jest.fn(),
}));
jest.mock('../hooks/use_project_features_url', () => ({
useProjectFeaturesUrl: jest.fn(),
}));
jest.mock('./current_plan', () => ({
CurrentPlan: jest.fn().mockReturnValue(<div data-test-subj="current-plan" />),
}));
const mockUseCurrentUser = useCurrentUser as jest.Mock;
const mockCurrentPlan = CurrentPlan as unknown as jest.Mock;
const mockUseProjectFeaturesUrl = useProjectFeaturesUrl as jest.Mock;
const mockProjectFeaturesUrl = '/features';
describe('WelcomeHeaderComponent', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should render fullName when fullName is provided', () => {
const fullName = 'John Doe';
mockUseCurrentUser.mockReturnValue({ fullName });
const { getByText } = render(<WelcomeHeader />);
const titleElement = getByText(`Hi ${fullName}!`);
expect(titleElement).toBeInTheDocument();
});
it('should render username when fullName is not provided', () => {
const username = 'jd';
mockUseCurrentUser.mockReturnValue({ username });
const { getByText } = render(<WelcomeHeader />);
const titleElement = getByText(`Hi ${username}!`);
expect(titleElement).toBeInTheDocument();
});
it('should not render the greeting message if both fullName and username are not available', () => {
mockUseCurrentUser.mockReturnValue({});
const { queryByTestId } = render(<WelcomeHeader />);
const greetings = queryByTestId(`welcome-header-greetings`);
expect(greetings).not.toBeInTheDocument();
});
it('should render subtitle', () => {
const { getByText } = render(<WelcomeHeader />);
const subtitleElement = getByText('Get started with Security');
expect(subtitleElement).toBeInTheDocument();
});
it('should render description', () => {
const { getByText } = render(<WelcomeHeader />);
const descriptionElement = getByText(
'This area shows you everything you need to know. Feel free to explore all content. You can always come back here at any time.'
);
expect(descriptionElement).toBeInTheDocument();
});
it('should render current plan', () => {
mockUseProjectFeaturesUrl.mockReturnValue(mockProjectFeaturesUrl);
const { getByTestId } = render(<WelcomeHeader productTier={ProductTier.complete} />);
const currentPlanElement = getByTestId('current-plan');
expect(currentPlanElement).toBeInTheDocument();
expect(mockCurrentPlan.mock.calls[0][0]).toEqual({
productTier: 'complete',
projectFeaturesUrl: mockProjectFeaturesUrl,
});
});
});

View file

@ -22,6 +22,10 @@ import { CurrentPlan } from './current_plan';
const WelcomeHeaderComponent: React.FC<{ productTier?: ProductTier }> = ({ productTier }) => {
const userName = useCurrentUser();
// Full name could be null, user name should always exist
const name = userName?.fullName ?? userName?.username;
const projectFeaturesUrl = useProjectFeaturesUrl();
const {
@ -38,9 +42,13 @@ const WelcomeHeaderComponent: React.FC<{ productTier?: ProductTier }> = ({ produ
return (
<EuiFlexGroup className={headerStyles} data-test-subj="welcome-header">
<EuiFlexItem grow={false} className={headerContentStyles}>
{userName?.username && (
<EuiTitle size="l" className={headerTitleStyles}>
<span>{GET_STARTED_PAGE_TITLE(userName.username)}</span>
{name && (
<EuiTitle
size="l"
className={headerTitleStyles}
data-test-subj="welcome-header-greetings"
>
<span>{GET_STARTED_PAGE_TITLE(name)}</span>
</EuiTitle>
)}
<EuiSpacer size="s" />