mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.7`: - [[Synthetics] handle onboarding for onprem deployments (#152048)](https://github.com/elastic/kibana/pull/152048) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Dominique Clarke","email":"dominique.clarke@elastic.co"},"sourceCommit":{"committedDate":"2023-03-11T02:29:14Z","message":"[Synthetics] handle onboarding for onprem deployments (#152048)\n\n## Summary\r\n\r\nDirects on-prem users to create a private location, before allowing\r\non-prem users to create monitors.\r\n\r\nAdmin user\r\n[Monitor-Management-Synthetics---Kibana\r\n(6).webm](https://user-images.githubusercontent.com/11356435/222554184-3f399764-0c3d-41e4-9652-7ec5616a320c.webm)\r\n\r\nUser without Fleet privileges\r\n[Synthetics-Getting-Started-Synthetics---Kibana\r\n(3).webm](https://user-images.githubusercontent.com/11356435/222554216-893a9a79-a152-459d-b6e6-d5bdfc5014dc.webm)\r\n\r\n\r\n### Testing\r\n\r\n1. Start ES with yarn es snapshot\r\n2. Remove all `xpack.uptime.service` configs in your Kibana.dev.yml\r\n3. Start Kibana connected to local ES\r\n4. Navigate to Synthetics and enable monitor\r\n5. Confirm that Add monitor flow appears first before creating a monitor\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: shahzad31 <shahzad31comp@gmail.com>\r\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>","sha":"01ba0270d9e9f62aadbe8cfc38b20810581619d7","branchLabelMapping":{"^v8.8.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","Team:uptime","release_note:skip","v8.7.0","v8.8.0"],"number":152048,"url":"https://github.com/elastic/kibana/pull/152048","mergeCommit":{"message":"[Synthetics] handle onboarding for onprem deployments (#152048)\n\n## Summary\r\n\r\nDirects on-prem users to create a private location, before allowing\r\non-prem users to create monitors.\r\n\r\nAdmin user\r\n[Monitor-Management-Synthetics---Kibana\r\n(6).webm](https://user-images.githubusercontent.com/11356435/222554184-3f399764-0c3d-41e4-9652-7ec5616a320c.webm)\r\n\r\nUser without Fleet privileges\r\n[Synthetics-Getting-Started-Synthetics---Kibana\r\n(3).webm](https://user-images.githubusercontent.com/11356435/222554216-893a9a79-a152-459d-b6e6-d5bdfc5014dc.webm)\r\n\r\n\r\n### Testing\r\n\r\n1. Start ES with yarn es snapshot\r\n2. Remove all `xpack.uptime.service` configs in your Kibana.dev.yml\r\n3. Start Kibana connected to local ES\r\n4. Navigate to Synthetics and enable monitor\r\n5. Confirm that Add monitor flow appears first before creating a monitor\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: shahzad31 <shahzad31comp@gmail.com>\r\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>","sha":"01ba0270d9e9f62aadbe8cfc38b20810581619d7"}},"sourceBranch":"main","suggestedTargetBranches":["8.7"],"targetPullRequestStates":[{"branch":"8.7","label":"v8.7.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.8.0","labelRegex":"^v8.8.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/152048","number":152048,"mergeCommit":{"message":"[Synthetics] handle onboarding for onprem deployments (#152048)\n\n## Summary\r\n\r\nDirects on-prem users to create a private location, before allowing\r\non-prem users to create monitors.\r\n\r\nAdmin user\r\n[Monitor-Management-Synthetics---Kibana\r\n(6).webm](https://user-images.githubusercontent.com/11356435/222554184-3f399764-0c3d-41e4-9652-7ec5616a320c.webm)\r\n\r\nUser without Fleet privileges\r\n[Synthetics-Getting-Started-Synthetics---Kibana\r\n(3).webm](https://user-images.githubusercontent.com/11356435/222554216-893a9a79-a152-459d-b6e6-d5bdfc5014dc.webm)\r\n\r\n\r\n### Testing\r\n\r\n1. Start ES with yarn es snapshot\r\n2. Remove all `xpack.uptime.service` configs in your Kibana.dev.yml\r\n3. Start Kibana connected to local ES\r\n4. Navigate to Synthetics and enable monitor\r\n5. Confirm that Add monitor flow appears first before creating a monitor\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: shahzad31 <shahzad31comp@gmail.com>\r\nCo-authored-by: florent-leborgne <florent.leborgne@elastic.co>","sha":"01ba0270d9e9f62aadbe8cfc38b20810581619d7"}}]}] BACKPORT--> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
bfab6b1d49
commit
21c8d91a24
21 changed files with 581 additions and 174 deletions
|
@ -27,6 +27,8 @@ export const GETTING_STARTED_ROUTE = '/monitors/getting-started';
|
|||
|
||||
export const SETTINGS_ROUTE = '/settings';
|
||||
|
||||
export const PRIVATE_LOCATIOSN_ROUTE = '/settings/private-locations';
|
||||
|
||||
export const SYNTHETICS_SETTINGS_ROUTE = '/settings/:tabId';
|
||||
|
||||
export const CERTIFICATES_ROUTE = '/certificates';
|
||||
|
|
|
@ -66,7 +66,7 @@ export const ServiceLocationsField = ({
|
|||
const SELECT_ONE_OR_MORE_LOCATIONS = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.selectOneOrMoreLocations',
|
||||
{
|
||||
defaultMessage: 'Select one or more locations',
|
||||
defaultMessage: 'Select one or more locations.',
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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 * as permissionsHooks from '../../hooks/use_fleet_permissions';
|
||||
import { render } from '../../utils/testing/rtl_helpers';
|
||||
import { GettingStartedPage } from './getting_started_page';
|
||||
import * as privateLocationsHooks from '../settings/private_locations/hooks/use_locations_api';
|
||||
|
||||
describe('GettingStartedPage', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(privateLocationsHooks, 'usePrivateLocationsAPI').mockReturnValue({
|
||||
loading: false,
|
||||
privateLocations: [],
|
||||
deleteLoading: false,
|
||||
onSubmit: jest.fn(),
|
||||
onDelete: jest.fn(),
|
||||
formData: undefined,
|
||||
});
|
||||
jest.spyOn(permissionsHooks, 'useCanManagePrivateLocation').mockReturnValue(true);
|
||||
});
|
||||
it('works with cloud locations', () => {
|
||||
const { getByText } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [
|
||||
{
|
||||
id: 'us_central',
|
||||
label: 'Us Central',
|
||||
},
|
||||
{
|
||||
id: 'us_east',
|
||||
label: 'US East',
|
||||
},
|
||||
],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
agentPolicies: {
|
||||
loading: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Create a single page browser monitor')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('serves on prem getting started experience when locations are not available', () => {
|
||||
const { getByText } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Get started with synthetic monitoring')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows need agent flyout when isAddingNewPrivateLocation is true and agentPolicies.length === 0', async () => {
|
||||
const { getByText, getByRole, queryByLabelText } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
agentPolicies: {
|
||||
data: {
|
||||
total: 0,
|
||||
},
|
||||
isAddingNewPrivateLocation: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Get started with synthetic monitoring')).toBeInTheDocument();
|
||||
|
||||
expect(getByRole('heading', { name: 'Create private location', level: 2 }));
|
||||
expect(getByText('No agent policies found')).toBeInTheDocument();
|
||||
expect(getByRole('link', { name: 'Create agent policy' })).toBeEnabled();
|
||||
expect(queryByLabelText('Location name')).not.toBeInTheDocument();
|
||||
expect(queryByLabelText('Agent policy')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows add location flyout when isAddingNewPrivateLocation is true and agentPolicies.length > 0', async () => {
|
||||
const { getByText, getByRole, getByLabelText, queryByText } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
agentPolicies: {
|
||||
data: {
|
||||
total: 1,
|
||||
items: [{}],
|
||||
},
|
||||
isAddingNewPrivateLocation: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Get started with synthetic monitoring')).toBeInTheDocument();
|
||||
|
||||
expect(getByRole('heading', { name: 'Create private location', level: 2 }));
|
||||
expect(queryByText('No agent policies found')).not.toBeInTheDocument();
|
||||
expect(getByLabelText('Location name')).toBeInTheDocument();
|
||||
expect(getByLabelText('Agent policy')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows permissions callout and hides form when agent policies are available but the user does not have permissions', async () => {
|
||||
jest.spyOn(permissionsHooks, 'useCanManagePrivateLocation').mockReturnValue(false);
|
||||
const { getByText, getByRole, queryByLabelText, queryByRole } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
agentPolicies: {
|
||||
data: {
|
||||
total: 1,
|
||||
items: [{}],
|
||||
},
|
||||
isAddingNewPrivateLocation: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Get started with synthetic monitoring')).toBeInTheDocument();
|
||||
|
||||
expect(getByRole('heading', { name: 'Create private location', level: 2 }));
|
||||
expect(queryByLabelText('Location name')).not.toBeInTheDocument();
|
||||
expect(queryByLabelText('Agent policy')).not.toBeInTheDocument();
|
||||
expect(queryByRole('button', { name: 'Save' })).not.toBeInTheDocument();
|
||||
expect(getByText("You're missing some Kibana privileges to manage private locations"));
|
||||
});
|
||||
|
||||
it('shows permissions callout when agent policy is needed but the user does not have permissions', async () => {
|
||||
jest.spyOn(permissionsHooks, 'useCanManagePrivateLocation').mockReturnValue(false);
|
||||
const { getByText, getByRole, queryByLabelText } = render(<GettingStartedPage />, {
|
||||
state: {
|
||||
serviceLocations: {
|
||||
locations: [],
|
||||
locationsLoaded: true,
|
||||
loading: false,
|
||||
},
|
||||
agentPolicies: {
|
||||
data: undefined, // data will be undefined when user does not have permissions
|
||||
isAddingNewPrivateLocation: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// page is loaded
|
||||
expect(getByText('Get started with synthetic monitoring')).toBeInTheDocument();
|
||||
|
||||
expect(getByRole('heading', { name: 'Create private location', level: 2 }));
|
||||
expect(queryByLabelText('Location name')).not.toBeInTheDocument();
|
||||
expect(queryByLabelText('Agent policy')).not.toBeInTheDocument();
|
||||
expect(getByText("You're missing some Kibana privileges to manage private locations"));
|
||||
});
|
||||
});
|
|
@ -5,54 +5,152 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { EuiEmptyPrompt, EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import {
|
||||
EuiEmptyPrompt,
|
||||
EuiLink,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import styled from 'styled-components';
|
||||
import { useBreadcrumbs } from '../../hooks';
|
||||
import { getServiceLocations } from '../../state';
|
||||
import { useBreadcrumbs, useLocations, useFleetPermissions } from '../../hooks';
|
||||
import { usePrivateLocationsAPI } from '../settings/private_locations/hooks/use_locations_api';
|
||||
import { LoadingState } from '../monitors_page/overview/overview/monitor_detail_flyout';
|
||||
import {
|
||||
getServiceLocations,
|
||||
selectAddingNewPrivateLocation,
|
||||
setAddingNewPrivateLocation,
|
||||
getAgentPoliciesAction,
|
||||
selectAgentPolicies,
|
||||
} from '../../state';
|
||||
import { MONITOR_ADD_ROUTE } from '../../../../../common/constants/ui';
|
||||
import { PrivateLocation } from '../../../../../common/runtime_types';
|
||||
import { SimpleMonitorForm } from './simple_monitor_form';
|
||||
import { AddLocationFlyout } from '../settings/private_locations/add_location_flyout';
|
||||
|
||||
export const GettingStartedPage = () => {
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
const { canReadAgentPolicies } = useFleetPermissions();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getServiceLocations());
|
||||
}, [dispatch]);
|
||||
if (canReadAgentPolicies) {
|
||||
dispatch(getAgentPoliciesAction.get());
|
||||
}
|
||||
}, [canReadAgentPolicies, dispatch]);
|
||||
|
||||
useBreadcrumbs([{ text: MONITORING_OVERVIEW_LABEL }]); // No extra breadcrumbs on overview
|
||||
|
||||
return (
|
||||
const { locations, loading: allLocationsLoading } = useLocations();
|
||||
const { loading: agentPoliciesLoading } = useSelector(selectAgentPolicies);
|
||||
const loading = allLocationsLoading || agentPoliciesLoading;
|
||||
|
||||
const hasNoLocations = !allLocationsLoading && locations.length === 0;
|
||||
|
||||
return !loading ? (
|
||||
<Wrapper>
|
||||
{hasNoLocations ? (
|
||||
<GettingStartedOnPrem />
|
||||
) : (
|
||||
<EuiEmptyPrompt
|
||||
title={<h2>{CREATE_SINGLE_PAGE_LABEL}</h2>}
|
||||
layout="horizontal"
|
||||
color="plain"
|
||||
body={
|
||||
<>
|
||||
<EuiText size="s">
|
||||
{OR_LABEL}{' '}
|
||||
<EuiLink
|
||||
href={history.createHref({
|
||||
pathname: MONITOR_ADD_ROUTE,
|
||||
})}
|
||||
>
|
||||
{SELECT_DIFFERENT_MONITOR}
|
||||
</EuiLink>
|
||||
{i18n.translate('xpack.synthetics.gettingStarted.createSingle.description', {
|
||||
defaultMessage: ' to get started with Elastic Synthetics Monitoring.',
|
||||
})}
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<SimpleMonitorForm />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
) : (
|
||||
<LoadingState />
|
||||
);
|
||||
};
|
||||
|
||||
export const GettingStartedOnPrem = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useBreadcrumbs([{ text: MONITORING_OVERVIEW_LABEL }]); // No extra breadcrumbs on overview
|
||||
|
||||
const isAddingNewLocation = useSelector(selectAddingNewPrivateLocation);
|
||||
|
||||
const setIsAddingNewLocation = useCallback(
|
||||
(val: boolean) => dispatch(setAddingNewPrivateLocation(val)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const { onSubmit, privateLocations, loading } = usePrivateLocationsAPI();
|
||||
|
||||
const handleSubmit = (formData: PrivateLocation) => {
|
||||
onSubmit(formData);
|
||||
};
|
||||
|
||||
// make sure flyout is closed when first visiting the page
|
||||
useEffect(() => {
|
||||
setIsAddingNewLocation(false);
|
||||
}, [setIsAddingNewLocation]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiEmptyPrompt
|
||||
title={<h2>{CREATE_SINGLE_PAGE_LABEL}</h2>}
|
||||
title={<h2>{GET_STARTED_LABEL}</h2>}
|
||||
layout="horizontal"
|
||||
color="plain"
|
||||
body={
|
||||
<>
|
||||
<EuiText size="s">
|
||||
{OR_LABEL}{' '}
|
||||
<EuiLink
|
||||
href={history.createHref({
|
||||
pathname: MONITOR_ADD_ROUTE,
|
||||
})}
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem>
|
||||
<EuiText>{CREATE_LOCATION_DESCRIPTION}</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiText>{PUBLIC_LOCATION_DESCRIPTION}</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="plusInCircleFilled"
|
||||
data-test-subj="gettingStartedAddLocationButton"
|
||||
onClick={() => setIsAddingNewLocation(true)}
|
||||
>
|
||||
{SELECT_DIFFERENT_MONITOR}
|
||||
</EuiLink>
|
||||
{i18n.translate('xpack.synthetics.gettingStarted.createSingle.description', {
|
||||
defaultMessage: ' to get started with Elastic Synthetics Monitoring',
|
||||
})}
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<SimpleMonitorForm />
|
||||
</>
|
||||
{CREATE_LOCATION_LABEL}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
/>
|
||||
</Wrapper>
|
||||
|
||||
{isAddingNewLocation ? (
|
||||
<AddLocationFlyout
|
||||
setIsOpen={setIsAddingNewLocation}
|
||||
onSubmit={handleSubmit}
|
||||
privateLocations={privateLocations}
|
||||
isLoading={loading}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -72,6 +170,69 @@ const CREATE_SINGLE_PAGE_LABEL = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
const GET_STARTED_LABEL = i18n.translate('xpack.synthetics.gettingStarted.createLocationHeading', {
|
||||
defaultMessage: 'Get started with synthetic monitoring',
|
||||
});
|
||||
|
||||
const PRIVATE_LOCATION_LABEL = i18n.translate(
|
||||
'xpack.synthetics.gettingStarted.privateLocationLabel',
|
||||
{
|
||||
defaultMessage: 'private location',
|
||||
}
|
||||
);
|
||||
|
||||
const CREATE_LOCATION_LABEL = i18n.translate(
|
||||
'xpack.synthetics.gettingStarted.createLocationLabel',
|
||||
{
|
||||
defaultMessage: 'Create location',
|
||||
}
|
||||
);
|
||||
|
||||
const CREATE_LOCATION_DESCRIPTION = (
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.gettingStarted.createLocationDescription"
|
||||
defaultMessage="To start creating monitors, you first need to create a {link}. Private locations allow you to run monitors from your own premises. They require an Elastic agent and Agent policy which you can control and maintain via Fleet."
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/observability/current/synthetics-private-location.html"
|
||||
target="_blank"
|
||||
>
|
||||
{PRIVATE_LOCATION_LABEL}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const PUBLIC_LOCATION_DESCRIPTION = (
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.gettingStarted.publicLocationDescription"
|
||||
defaultMessage="In {link} you can also use {elasticManagedLink}. With it, you can create and run monitors in multiple locations without having to manage your own infrastructure. Elastic takes care of software updates and capacity planning for you."
|
||||
values={{
|
||||
elasticManagedLink: (
|
||||
<strong>
|
||||
{i18n.translate(
|
||||
'xpack.synthetics.gettingStarted.gettingStartedLabel.elasticManagedLink',
|
||||
{
|
||||
defaultMessage: 'Elastic’s global managed testing infrastructure',
|
||||
}
|
||||
)}
|
||||
</strong>
|
||||
),
|
||||
link: (
|
||||
<EuiLink href="https://www.elastic.co/cloud/" target="_blank">
|
||||
{i18n.translate(
|
||||
'xpack.synthetics.gettingStarted.gettingStartedLabel.elasticCloudDeployments',
|
||||
{
|
||||
defaultMessage: 'Elastic Cloud',
|
||||
}
|
||||
)}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const SELECT_DIFFERENT_MONITOR = i18n.translate(
|
||||
'xpack.synthetics.gettingStarted.gettingStartedLabel.selectDifferentMonitor',
|
||||
{
|
||||
|
|
|
@ -126,7 +126,7 @@ export const WEBSITE_URL_PLACEHOLDER = i18n.translate(
|
|||
export const WEBSITE_URL_HELP_TEXT = i18n.translate(
|
||||
'xpack.synthetics.monitorManagement.websiteUrlHelpText',
|
||||
{
|
||||
defaultMessage: `For example, your company's homepage or https://elastic.co`,
|
||||
defaultMessage: `For example, your company's homepage or https://elastic.co.`,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import { useFormWrapped } from '../../../../../hooks/use_form_wrapped';
|
|||
import { PrivateLocation } from '../../../../../../common/runtime_types';
|
||||
import { FleetPermissionsCallout } from '../../common/components/permissions';
|
||||
import { LocationForm } from './location_form';
|
||||
import { ManageEmptyState } from './manage_empty_state';
|
||||
|
||||
export const AddLocationFlyout = ({
|
||||
onSubmit,
|
||||
|
@ -69,32 +70,39 @@ export const AddLocationFlyout = ({
|
|||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
{!canManagePrivateLocation && <FleetPermissionsCallout />}
|
||||
|
||||
<LocationForm
|
||||
<ManageEmptyState
|
||||
privateLocations={privateLocations}
|
||||
hasPermissions={canManagePrivateLocation}
|
||||
/>
|
||||
hasFleetPermissions={canManagePrivateLocation}
|
||||
showEmptyLocations={false}
|
||||
>
|
||||
{!canManagePrivateLocation && <FleetPermissionsCallout />}
|
||||
<LocationForm
|
||||
privateLocations={privateLocations}
|
||||
hasPermissions={canManagePrivateLocation}
|
||||
/>
|
||||
</ManageEmptyState>
|
||||
</EuiFlyoutBody>
|
||||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
iconType="cross"
|
||||
onClick={closeFlyout}
|
||||
flush="left"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{CANCEL_LABEL}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={handleSubmit(onSubmit)} isLoading={isLoading}>
|
||||
{SAVE_LABEL}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
{canManagePrivateLocation && (
|
||||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
iconType="cross"
|
||||
onClick={closeFlyout}
|
||||
flush="left"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{CANCEL_LABEL}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton fill onClick={handleSubmit(onSubmit)} isLoading={isLoading}>
|
||||
{SAVE_LABEL}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
)}
|
||||
</EuiFlyout>
|
||||
</FormProvider>
|
||||
);
|
||||
|
|
|
@ -6,21 +6,26 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { EuiEmptyPrompt, EuiButton, EuiLink, EuiText } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { PRIVATE_LOCATIOSN_ROUTE } from '../../../../../../common/constants';
|
||||
import { setAddingNewPrivateLocation, setManageFlyoutOpen } from '../../../state/private_locations';
|
||||
|
||||
export const EmptyLocations = ({
|
||||
inFlyout = true,
|
||||
setIsAddingNew,
|
||||
disabled,
|
||||
redirectToSettings,
|
||||
}: {
|
||||
inFlyout?: boolean;
|
||||
disabled?: boolean;
|
||||
setIsAddingNew?: (val: boolean) => void;
|
||||
redirectToSettings?: boolean;
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
|
@ -33,19 +38,33 @@ export const EmptyLocations = ({
|
|||
</EuiText>
|
||||
}
|
||||
actions={
|
||||
<EuiButton
|
||||
iconType="plusInCircle"
|
||||
disabled={disabled}
|
||||
color="primary"
|
||||
fill
|
||||
onClick={() => {
|
||||
setIsAddingNew?.(true);
|
||||
dispatch(setManageFlyoutOpen(true));
|
||||
dispatch(setAddingNewPrivateLocation(true));
|
||||
}}
|
||||
>
|
||||
{ADD_LOCATION}
|
||||
</EuiButton>
|
||||
redirectToSettings ? (
|
||||
<EuiButton
|
||||
iconType="plusInCircle"
|
||||
color="primary"
|
||||
fill
|
||||
isDisabled={disabled}
|
||||
href={history.createHref({
|
||||
pathname: PRIVATE_LOCATIOSN_ROUTE,
|
||||
})}
|
||||
>
|
||||
{ADD_LOCATION}
|
||||
</EuiButton>
|
||||
) : (
|
||||
<EuiButton
|
||||
iconType="plusInCircle"
|
||||
disabled={disabled}
|
||||
color="primary"
|
||||
fill
|
||||
onClick={() => {
|
||||
setIsAddingNew?.(true);
|
||||
dispatch(setManageFlyoutOpen(true));
|
||||
dispatch(setAddingNewPrivateLocation(true));
|
||||
}}
|
||||
>
|
||||
{ADD_LOCATION}
|
||||
</EuiButton>
|
||||
)
|
||||
}
|
||||
footer={
|
||||
<EuiText size="s">
|
||||
|
|
|
@ -9,11 +9,11 @@ import { renderHook, act } from '@testing-library/react-hooks';
|
|||
import { WrappedHelper } from '../../../../utils/testing';
|
||||
import { getServiceLocations } from '../../../../state/service_locations';
|
||||
import { setAddingNewPrivateLocation } from '../../../../state/private_locations';
|
||||
import { useLocationsAPI } from './use_locations_api';
|
||||
import { usePrivateLocationsAPI } from './use_locations_api';
|
||||
import * as locationAPI from '../../../../state/private_locations/api';
|
||||
import * as reduxHooks from 'react-redux';
|
||||
|
||||
describe('useLocationsAPI', () => {
|
||||
describe('usePrivateLocationsAPI', () => {
|
||||
const dispatch = jest.fn();
|
||||
const addAPI = jest.spyOn(locationAPI, 'addSyntheticsPrivateLocations').mockResolvedValue({
|
||||
locations: [],
|
||||
|
@ -25,7 +25,7 @@ describe('useLocationsAPI', () => {
|
|||
jest.spyOn(reduxHooks, 'useDispatch').mockReturnValue(dispatch);
|
||||
|
||||
it('returns expected results', () => {
|
||||
const { result } = renderHook(() => useLocationsAPI(), {
|
||||
const { result } = renderHook(() => usePrivateLocationsAPI(), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
|
||||
|
@ -46,7 +46,7 @@ describe('useLocationsAPI', () => {
|
|||
],
|
||||
});
|
||||
it('returns expected results after data', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI(), {
|
||||
const { result, waitForNextUpdate } = renderHook(() => usePrivateLocationsAPI(), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
|
||||
|
@ -73,7 +73,7 @@ describe('useLocationsAPI', () => {
|
|||
});
|
||||
|
||||
it('adds location on submit', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI(), {
|
||||
const { result, waitForNextUpdate } = renderHook(() => usePrivateLocationsAPI(), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
|
||||
|
@ -109,7 +109,7 @@ describe('useLocationsAPI', () => {
|
|||
});
|
||||
|
||||
it('deletes location on delete', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI(), {
|
||||
const { result, waitForNextUpdate } = renderHook(() => usePrivateLocationsAPI(), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from '../../../../state/private_locations/api';
|
||||
import { PrivateLocation } from '../../../../../../../common/runtime_types';
|
||||
|
||||
export const useLocationsAPI = () => {
|
||||
export const usePrivateLocationsAPI = () => {
|
||||
const [formData, setFormData] = useState<PrivateLocation>();
|
||||
const [deleteId, setDeleteId] = useState<string>();
|
||||
const [privateLocations, setPrivateLocations] = useState<PrivateLocation[]>([]);
|
||||
|
|
|
@ -46,78 +46,47 @@ export const LocationForm = ({
|
|||
return (
|
||||
<>
|
||||
{data?.items.length === 0 && <AgentPolicyNeeded disabled={!hasPermissions} />}
|
||||
<EuiForm component="form" noValidate>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
label={LOCATION_NAME_LABEL}
|
||||
isInvalid={Boolean(errors?.label)}
|
||||
error={errors?.label?.message}
|
||||
>
|
||||
<EuiFieldText
|
||||
{hasPermissions ? (
|
||||
<EuiForm component="form" noValidate>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
aria-label={LOCATION_NAME_LABEL}
|
||||
{...register('label', {
|
||||
required: {
|
||||
value: true,
|
||||
message: NAME_REQUIRED,
|
||||
},
|
||||
validate: (val: string) => {
|
||||
return privateLocations.some((loc) => loc.label === val)
|
||||
? NAME_ALREADY_EXISTS
|
||||
: undefined;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer />
|
||||
<PolicyHostsField errors={errors} control={control} privateLocations={privateLocations} />
|
||||
<EuiSpacer />
|
||||
<TagsField tagsList={tagsList} control={control} errors={errors} />
|
||||
<EuiSpacer />
|
||||
<EuiCallOut title={AGENT_CALLOUT_TITLE} size="s" style={{ textAlign: 'left' }}>
|
||||
<p>
|
||||
{
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentCallout.content"
|
||||
defaultMessage='If you intend to run "Browser" monitors on this private location, please ensure you are using the {code} Docker container, which contains the dependencies to run these monitors. For more information, {link}.'
|
||||
values={{
|
||||
code: <EuiCode>elastic-agent-complete</EuiCode>,
|
||||
link: (
|
||||
<EuiLink
|
||||
target="_blank"
|
||||
href="https://www.elastic.co/guide/en/observability/current/uptime-set-up-choose-agent.html#private-locations"
|
||||
external
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentCallout.link"
|
||||
defaultMessage="read the docs"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
|
||||
<EuiSpacer />
|
||||
{selectedPolicy?.agents === 0 && (
|
||||
<EuiCallOut
|
||||
title={AGENT_MISSING_CALLOUT_TITLE}
|
||||
size="s"
|
||||
style={{ textAlign: 'left' }}
|
||||
color="warning"
|
||||
label={LOCATION_NAME_LABEL}
|
||||
isInvalid={Boolean(errors?.label)}
|
||||
error={errors?.label?.message}
|
||||
>
|
||||
<EuiFieldText
|
||||
fullWidth
|
||||
aria-label={LOCATION_NAME_LABEL}
|
||||
{...register('label', {
|
||||
required: {
|
||||
value: true,
|
||||
message: NAME_REQUIRED,
|
||||
},
|
||||
validate: (val: string) => {
|
||||
return privateLocations.some((loc) => loc.label === val)
|
||||
? NAME_ALREADY_EXISTS
|
||||
: undefined;
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer />
|
||||
<PolicyHostsField errors={errors} control={control} privateLocations={privateLocations} />
|
||||
<EuiSpacer />
|
||||
<TagsField tagsList={tagsList} control={control} errors={errors} />
|
||||
<EuiSpacer />
|
||||
<EuiCallOut title={AGENT_CALLOUT_TITLE} size="s" style={{ textAlign: 'left' }}>
|
||||
<p>
|
||||
{
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentMissingCallout.content"
|
||||
defaultMessage="You have selected an agent policy that has no agents attached. Please ensure you have at least one agent enrolled in this policy. You can add agent before or after creating a location. For more information, {link}."
|
||||
id="xpack.synthetics.monitorManagement.agentCallout.content"
|
||||
defaultMessage='To run "Browser" monitors on this private location, make sure that you're using the {code} Docker container, which contains the dependencies necessary to run these monitors. For more information, {link}.'
|
||||
values={{
|
||||
code: <EuiCode>elastic-agent-complete</EuiCode>,
|
||||
link: (
|
||||
<EuiLink
|
||||
target="_blank"
|
||||
href="https://www.elastic.co/guide/en/observability/current/synthetics-private-location.html#synthetics-private-location-fleet-agent"
|
||||
href="https://www.elastic.co/guide/en/observability/current/uptime-set-up-choose-agent.html#private-locations"
|
||||
external
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -131,8 +100,41 @@ export const LocationForm = ({
|
|||
}
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
)}
|
||||
</EuiForm>
|
||||
|
||||
<EuiSpacer />
|
||||
{selectedPolicy?.agents === 0 && (
|
||||
<EuiCallOut
|
||||
title={AGENT_MISSING_CALLOUT_TITLE}
|
||||
size="s"
|
||||
style={{ textAlign: 'left' }}
|
||||
color="warning"
|
||||
>
|
||||
<p>
|
||||
{
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentMissingCallout.content"
|
||||
defaultMessage="You have selected an agent policy that has no agent attached. Make sure that you have at least one agent enrolled in this policy. You can add agent before or after creating a location. For more information, {link}."
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink
|
||||
target="_blank"
|
||||
href="https://www.elastic.co/guide/en/observability/current/synthetics-private-location.html#synthetics-private-location-fleet-agent"
|
||||
external
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentCallout.link"
|
||||
defaultMessage="read the docs"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
)}
|
||||
</EuiForm>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -15,15 +15,24 @@ import { selectAgentPolicies } from '../../../state/private_locations';
|
|||
export const ManageEmptyState: FC<{
|
||||
privateLocations: PrivateLocation[];
|
||||
hasFleetPermissions: boolean;
|
||||
setIsAddingNew: (val: boolean) => void;
|
||||
}> = ({ children, privateLocations, setIsAddingNew, hasFleetPermissions }) => {
|
||||
setIsAddingNew?: (val: boolean) => void;
|
||||
showNeedAgentPolicy?: boolean;
|
||||
showEmptyLocations?: boolean;
|
||||
}> = ({
|
||||
children,
|
||||
privateLocations,
|
||||
setIsAddingNew,
|
||||
hasFleetPermissions,
|
||||
showNeedAgentPolicy = true,
|
||||
showEmptyLocations = true,
|
||||
}) => {
|
||||
const { data: agentPolicies } = useSelector(selectAgentPolicies);
|
||||
|
||||
if (agentPolicies?.total === 0) {
|
||||
if (agentPolicies?.total === 0 && showNeedAgentPolicy) {
|
||||
return <AgentPolicyNeeded disabled={!hasFleetPermissions} />;
|
||||
}
|
||||
|
||||
if (privateLocations.length === 0) {
|
||||
if (privateLocations.length === 0 && showEmptyLocations) {
|
||||
return <EmptyLocations setIsAddingNew={setIsAddingNew} disabled={!hasFleetPermissions} />;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,11 @@ jest.mock('../../../contexts/synthetics_settings_context');
|
|||
describe('<ManagePrivateLocations />', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(permissionsHooks, 'useCanManagePrivateLocation').mockReturnValue(true);
|
||||
jest.spyOn(locationHooks, 'useLocationsAPI').mockReturnValue({
|
||||
jest.spyOn(permissionsHooks, 'useFleetPermissions').mockReturnValue({
|
||||
canReadAgentPolicies: true,
|
||||
canSaveIntegrations: false,
|
||||
});
|
||||
jest.spyOn(locationHooks, 'usePrivateLocationsAPI').mockReturnValue({
|
||||
formData: {} as PrivateLocation,
|
||||
loading: false,
|
||||
onSubmit: jest.fn(),
|
||||
|
@ -120,7 +124,7 @@ describe('<ManagePrivateLocations />', () => {
|
|||
canSaveIntegrations: hasFleetPermissions,
|
||||
canReadAgentPolicies: hasFleetPermissions,
|
||||
});
|
||||
jest.spyOn(locationHooks, 'useLocationsAPI').mockReturnValue({
|
||||
jest.spyOn(locationHooks, 'usePrivateLocationsAPI').mockReturnValue({
|
||||
formData: {} as PrivateLocation,
|
||||
loading: false,
|
||||
onSubmit: jest.fn(),
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { LoadingState } from '../../monitors_page/overview/overview/monitor_detail_flyout';
|
||||
import { PrivateLocationsTable } from './locations_table';
|
||||
import { useCanManagePrivateLocation } from '../../../hooks';
|
||||
import { useCanManagePrivateLocation, useFleetPermissions } from '../../../hooks';
|
||||
import { ManageEmptyState } from './manage_empty_state';
|
||||
import { AddLocationFlyout } from './add_location_flyout';
|
||||
import { useLocationsAPI } from './hooks/use_locations_api';
|
||||
import { usePrivateLocationsAPI } from './hooks/use_locations_api';
|
||||
import {
|
||||
getAgentPoliciesAction,
|
||||
selectAddingNewPrivateLocation,
|
||||
|
@ -26,16 +26,27 @@ export const ManagePrivateLocations = () => {
|
|||
const dispatch = useDispatch();
|
||||
|
||||
const isAddingNew = useSelector(selectAddingNewPrivateLocation);
|
||||
const setIsAddingNew = (val: boolean) => dispatch(setAddingNewPrivateLocation(val));
|
||||
const setIsAddingNew = useCallback(
|
||||
(val: boolean) => dispatch(setAddingNewPrivateLocation(val)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const { onSubmit, loading, privateLocations, onDelete, deleteLoading } = useLocationsAPI();
|
||||
const { onSubmit, loading, privateLocations, onDelete, deleteLoading } = usePrivateLocationsAPI();
|
||||
|
||||
const { canReadAgentPolicies } = useFleetPermissions();
|
||||
const canManagePrivateLocation = useCanManagePrivateLocation();
|
||||
|
||||
// make sure flyout is closed when first visiting the page
|
||||
useEffect(() => {
|
||||
dispatch(getAgentPoliciesAction.get());
|
||||
setIsAddingNew(false);
|
||||
}, [setIsAddingNew]);
|
||||
|
||||
useEffect(() => {
|
||||
if (canReadAgentPolicies) {
|
||||
dispatch(getAgentPoliciesAction.get());
|
||||
}
|
||||
dispatch(getServiceLocations());
|
||||
}, [dispatch]);
|
||||
}, [dispatch, canReadAgentPolicies]);
|
||||
|
||||
const handleSubmit = (formData: PrivateLocation) => {
|
||||
onSubmit(formData);
|
||||
|
|
|
@ -43,11 +43,15 @@ export const PolicyName = ({ agentPolicyId }: { agentPolicyId: string }) => {
|
|||
) : (
|
||||
agentPolicyId
|
||||
)}
|
||||
|
||||
<EuiBadge color={policy?.agents === 0 ? 'warning' : 'hollow'}>
|
||||
{AGENTS_LABEL}
|
||||
{policy?.agents}
|
||||
</EuiBadge>
|
||||
{canReadAgentPolicies && (
|
||||
<>
|
||||
|
||||
<EuiBadge color={policy?.agents === 0 ? 'warning' : 'hollow'}>
|
||||
{AGENTS_LABEL}
|
||||
{policy?.agents}
|
||||
</EuiBadge>
|
||||
</>
|
||||
)}
|
||||
</EuiText>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -52,11 +52,9 @@ describe('useLocationName', () => {
|
|||
{ wrapper: WrapperWithState }
|
||||
);
|
||||
expect(result.current).toEqual({
|
||||
geo: { lat: 41.25, lon: -95.86 },
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'US Central',
|
||||
status: 'ga',
|
||||
url: 'mockUrl',
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,3 +18,4 @@ export * from './monitor_details';
|
|||
export * from './overview';
|
||||
export * from './browser_journey';
|
||||
export * from './ping_status';
|
||||
export * from './private_locations';
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
RenderOptions,
|
||||
} from '@testing-library/react';
|
||||
import { Router, Route } from 'react-router-dom';
|
||||
import { merge } from 'lodash';
|
||||
import { merge, mergeWith } from 'lodash';
|
||||
import { createMemoryHistory, History } from 'history';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
|
@ -225,7 +225,11 @@ export function WrappedHelper<ExtraCore>({
|
|||
path,
|
||||
history = createMemoryHistory(),
|
||||
}: RenderRouterOptions<ExtraCore> & { children: ReactElement; useRealStore?: boolean }) {
|
||||
const testState: AppState = merge({}, mockState, state);
|
||||
const testState: AppState = mergeWith({}, mockState, state, (objValue, srcValue) => {
|
||||
if (Array.isArray(objValue)) {
|
||||
return srcValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (url) {
|
||||
history = getHistoryFromUrl(url);
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
import { renderHook } from '@testing-library/react-hooks';
|
||||
|
||||
import { defaultCore, WrappedHelper } from '../../../../../apps/synthetics/utils/testing';
|
||||
import { useLocationsAPI } from './use_locations_api';
|
||||
import { usePrivateLocationsAPI } from './use_locations_api';
|
||||
|
||||
describe('useLocationsAPI', () => {
|
||||
describe('usePrivateLocationsAPI', () => {
|
||||
it('returns expected results', () => {
|
||||
const { result } = renderHook(() => useLocationsAPI({ isOpen: false }), {
|
||||
const { result } = renderHook(() => usePrivateLocationsAPI({ isOpen: false }), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
|
||||
|
@ -38,9 +38,12 @@ describe('useLocationsAPI', () => {
|
|||
},
|
||||
});
|
||||
it('returns expected results after data', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI({ isOpen: true }), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => usePrivateLocationsAPI({ isOpen: true }),
|
||||
{
|
||||
wrapper: WrappedHelper,
|
||||
}
|
||||
);
|
||||
|
||||
expect(result.current).toEqual(
|
||||
expect.objectContaining({
|
||||
|
@ -65,9 +68,12 @@ describe('useLocationsAPI', () => {
|
|||
});
|
||||
|
||||
it('adds location on submit', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI({ isOpen: true }), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => usePrivateLocationsAPI({ isOpen: true }),
|
||||
{
|
||||
wrapper: WrappedHelper,
|
||||
}
|
||||
);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
|
@ -121,9 +127,12 @@ describe('useLocationsAPI', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLocationsAPI({ isOpen: true }), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
const { result, waitForNextUpdate } = renderHook(
|
||||
() => usePrivateLocationsAPI({ isOpen: true }),
|
||||
{
|
||||
wrapper: WrappedHelper,
|
||||
}
|
||||
);
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
getSyntheticsPrivateLocations,
|
||||
} from '../../../../state/private_locations/api';
|
||||
|
||||
export const useLocationsAPI = ({ isOpen }: { isOpen: boolean }) => {
|
||||
export const usePrivateLocationsAPI = ({ isOpen }: { isOpen: boolean }) => {
|
||||
const [formData, setFormData] = useState<PrivateLocation>();
|
||||
const [deleteId, setDeleteId] = useState<string>();
|
||||
const [privateLocations, setPrivateLocations] = useState<PrivateLocation[]>([]);
|
||||
|
|
|
@ -67,7 +67,7 @@ export const LocationForm = ({
|
|||
{
|
||||
<FormattedMessage
|
||||
id="xpack.synthetics.monitorManagement.agentCallout.content"
|
||||
defaultMessage='If you intend to run "Browser" monitors on this private location, please ensure you are using the {code} Docker container, which contains the dependencies to run these monitors. For more information, {link}.'
|
||||
defaultMessage='To run "Browser" monitors on this private location, make sure that you're using the {code} Docker container, which contains the dependencies necessary to run these monitors. For more information, {link}.'
|
||||
values={{
|
||||
code: <EuiCode>elastic-agent-complete</EuiCode>,
|
||||
link: (
|
||||
|
|
|
@ -27,7 +27,7 @@ import { AddLocationFlyout } from './add_location_flyout';
|
|||
import { ClientPluginsStart } from '../../../../plugin';
|
||||
import { getServiceLocations } from '../../../state/actions';
|
||||
import { PrivateLocationsList } from './locations_list';
|
||||
import { useLocationsAPI } from './hooks/use_locations_api';
|
||||
import { usePrivateLocationsAPI } from './hooks/use_locations_api';
|
||||
import {
|
||||
getAgentPoliciesAction,
|
||||
selectAddingNewPrivateLocation,
|
||||
|
@ -49,7 +49,7 @@ export const ManageLocationsFlyout = () => {
|
|||
|
||||
const setIsAddingNew = (val: boolean) => dispatch(setAddingNewPrivateLocation(val));
|
||||
|
||||
const { onSubmit, loading, privateLocations, onDelete } = useLocationsAPI({
|
||||
const { onSubmit, loading, privateLocations, onDelete } = usePrivateLocationsAPI({
|
||||
isOpen,
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue