diff --git a/x-pack/plugins/apm/jest.config.js b/x-pack/plugins/apm/jest.config.js
index ffd3a39e8afd1..849dd7f5c3e2d 100644
--- a/x-pack/plugins/apm/jest.config.js
+++ b/x-pack/plugins/apm/jest.config.js
@@ -29,7 +29,7 @@ module.exports = {
roots: [`${rootDir}/common`, `${rootDir}/public`, `${rootDir}/server`],
collectCoverage: true,
collectCoverageFrom: [
- ...(jestConfig.collectCoverageFrom ?? []),
+ ...(jestConfig.collectCoverageFrom || []),
'**/*.{js,mjs,jsx,ts,tsx}',
'!**/*.stories.{js,mjs,ts,tsx}',
'!**/dev_docs/**',
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/DeleteButton.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/DeleteButton.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/Documentation.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/Documentation.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/FiltersSection.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/FiltersSection.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/FlyoutFooter.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/FlyoutFooter.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/LinkPreview.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/LinkPreview.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/LinkSection.tsx
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/LinkSection.tsx
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper.test.ts
similarity index 99%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper.test.ts
index 5f8e0b9052a65..4af9321152da3 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts
+++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper.test.ts
@@ -6,7 +6,7 @@
import {
getSelectOptions,
replaceTemplateVariables,
-} from '../CustomLinkFlyout/helper';
+} from '../CreateEditCustomLinkFlyout/helper';
import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction';
describe('Custom link helper', () => {
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper.ts
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper.ts
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/index.tsx
similarity index 98%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/index.tsx
index 9687846d6c520..c6566af3a8b61 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/index.tsx
@@ -37,7 +37,7 @@ interface Props {
const filtersEmptyState: Filter[] = [{ key: '', value: '' }];
-export function CustomLinkFlyout({
+export function CreateEditCustomLinkFlyout({
onClose,
onSave,
onDelete,
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/link_preview.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/link_preview.test.tsx
similarity index 97%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/link_preview.test.tsx
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/link_preview.test.tsx
index 3a2aa01ba3bc4..7fa8e3a025956 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/link_preview.test.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/link_preview.test.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
-import { LinkPreview } from '../CustomLinkFlyout/LinkPreview';
+import { LinkPreview } from '../CreateEditCustomLinkFlyout/LinkPreview';
import {
render,
getNodeText,
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/saveCustomLink.ts
similarity index 100%
rename from x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts
rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/saveCustomLink.ts
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx
deleted file mode 100644
index 2017aa42e1c5a..0000000000000
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import React from 'react';
-
-export function Title() {
- return (
-
-
-
-
-
-
- {i18n.translate('xpack.apm.settings.customizeUI.customLink', {
- defaultMessage: 'Custom Links',
- })}
-
-
-
-
-
-
- );
-}
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx
index a7feafad11111..96a634828f669 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx
@@ -21,7 +21,7 @@ import {
expectTextsInDocument,
expectTextsNotInDocument,
} from '../../../../../utils/testHelpers';
-import * as saveCustomLink from './CustomLinkFlyout/saveCustomLink';
+import * as saveCustomLink from './CreateEditCustomLinkFlyout/saveCustomLink';
import { MockApmPluginContextWrapper } from '../../../../../context/ApmPluginContext/MockApmPluginContext';
const data = [
diff --git a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx
index d872f6d21ed96..771a8c6154dc0 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx
@@ -9,6 +9,7 @@ import {
EuiFlexItem,
EuiPanel,
EuiSpacer,
+ EuiTitle,
EuiText,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -20,10 +21,9 @@ import { FETCH_STATUS, useFetcher } from '../../../../../hooks/useFetcher';
import { useLicense } from '../../../../../hooks/useLicense';
import { LicensePrompt } from '../../../../shared/LicensePrompt';
import { CreateCustomLinkButton } from './CreateCustomLinkButton';
-import { CustomLinkFlyout } from './CustomLinkFlyout';
+import { CreateEditCustomLinkFlyout } from './CreateEditCustomLinkFlyout';
import { CustomLinkTable } from './CustomLinkTable';
import { EmptyPrompt } from './EmptyPrompt';
-import { Title } from './Title';
export function CustomLinkOverview() {
const license = useLicense();
@@ -35,9 +35,14 @@ export function CustomLinkOverview() {
>();
const { data: customLinks = [], status, refetch } = useFetcher(
- (callApmApi) =>
- callApmApi({ endpoint: 'GET /api/apm/settings/custom_links' }),
- []
+ async (callApmApi) => {
+ if (hasValidLicense) {
+ return callApmApi({
+ endpoint: 'GET /api/apm/settings/custom_links',
+ });
+ }
+ },
+ [hasValidLicense]
);
useEffect(() => {
@@ -61,7 +66,7 @@ export function CustomLinkOverview() {
return (
<>
{isFlyoutOpen && (
-
-
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.settings.customizeUI.customLink',
+ {
+ defaultMessage: 'Custom Links',
+ }
+ )}
+
+
+
+
+
+
{hasValidLicense && !showEmptyPrompt && (
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx
deleted file mode 100644
index 62952d1fb501b..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { act, fireEvent, render } from '@testing-library/react';
-import React, { ReactNode } from 'react';
-import { MemoryRouter } from 'react-router-dom';
-import { CustomLink } from '../../../../../common/custom_link/custom_link_types';
-import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
-import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext';
-import { expectTextsInDocument } from '../../../../utils/testHelpers';
-import { CustomLinkPopover } from './CustomLinkPopover';
-
-function Wrapper({ children }: { children?: ReactNode }) {
- return (
-
- {children}
-
- );
-}
-
-describe('CustomLinkPopover', () => {
- const customLinks = [
- { id: '1', label: 'foo', url: 'http://elastic.co' },
- {
- id: '2',
- label: 'bar',
- url: 'http://elastic.co?service.name={{service.name}}',
- },
- ] as CustomLink[];
- const transaction = ({
- service: { name: 'foo.bar' },
- } as unknown) as Transaction;
- it('renders popover', () => {
- const component = render(
- ,
- { wrapper: Wrapper }
- );
- expectTextsInDocument(component, ['CUSTOM LINKS', 'Create', 'foo', 'bar']);
- });
-
- it('closes popover', () => {
- const handleCloseMock = jest.fn();
- const { getByText } = render(
- ,
- { wrapper: Wrapper }
- );
- expect(handleCloseMock).not.toHaveBeenCalled();
- act(() => {
- fireEvent.click(getByText('CUSTOM LINKS'));
- });
- expect(handleCloseMock).toHaveBeenCalled();
- });
-
- it('opens flyout to create new custom link', () => {
- const handleCreateCustomLinkClickMock = jest.fn();
- const { getByText } = render(
- ,
- { wrapper: Wrapper }
- );
- expect(handleCreateCustomLinkClickMock).not.toHaveBeenCalled();
- act(() => {
- fireEvent.click(getByText('Create'));
- });
- expect(handleCreateCustomLinkClickMock).toHaveBeenCalled();
- });
-});
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx
deleted file mode 100644
index 27c6aa82ac674..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React from 'react';
-import {
- EuiPopoverTitle,
- EuiFlexGroup,
- EuiFlexItem,
- EuiButtonEmpty,
-} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import styled from 'styled-components';
-import { CustomLink } from '../../../../../common/custom_link/custom_link_types';
-import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
-import { CustomLinkSection } from './CustomLinkSection';
-import { ManageCustomLink } from './ManageCustomLink';
-import { px } from '../../../../style/variables';
-
-const ScrollableContainer = styled.div`
- -ms-overflow-style: none;
- max-height: ${px(535)};
- overflow: scroll;
-`;
-
-export function CustomLinkPopover({
- customLinks,
- onCreateCustomLinkClick,
- onClose,
- transaction,
-}: {
- customLinks: CustomLink[];
- onCreateCustomLinkClick: () => void;
- onClose: () => void;
- transaction: Transaction;
-}) {
- return (
- <>
-
-
-
-
- {i18n.translate(
- 'xpack.apm.transactionActionMenu.customLink.popover.title',
- {
- defaultMessage: 'CUSTOM LINKS',
- }
- )}
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx
deleted file mode 100644
index 6b421bc370332..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import { EuiLink, EuiText } from '@elastic/eui';
-import Mustache from 'mustache';
-import React from 'react';
-import styled from 'styled-components';
-import { CustomLink } from '../../../../../common/custom_link/custom_link_types';
-import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
-import { px, truncate, units } from '../../../../style/variables';
-
-const LinkContainer = styled.li`
- margin-top: ${px(units.half)};
- &:first-of-type {
- margin-top: 0;
- }
-`;
-
-const TruncateText = styled(EuiText)`
- font-weight: 500;
- line-height: ${px(units.unit)};
- ${truncate(px(units.unit * 25))}
-`;
-
-export function CustomLinkSection({
- customLinks,
- transaction,
-}: {
- customLinks: CustomLink[];
- transaction: Transaction;
-}) {
- return (
-
- {customLinks.map((link) => {
- let href = link.url;
- try {
- href = Mustache.render(link.url, transaction);
- } catch (e) {
- // ignores any error that happens
- }
- return (
-
-
- {link.label}
-
-
- );
- })}
-
- );
-}
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx
deleted file mode 100644
index d6484f52e84f9..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-import React from 'react';
-import {
- EuiText,
- EuiIcon,
- EuiFlexGroup,
- EuiFlexItem,
- EuiSpacer,
- EuiButtonEmpty,
-} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import styled from 'styled-components';
-import { isEmpty } from 'lodash';
-import { CustomLink as CustomLinkType } from '../../../../../common/custom_link/custom_link_types';
-import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
-import {
- ActionMenuDivider,
- SectionSubtitle,
-} from '../../../../../../observability/public';
-import { CustomLinkSection } from './CustomLinkSection';
-import { ManageCustomLink } from './ManageCustomLink';
-import { FETCH_STATUS } from '../../../../hooks/useFetcher';
-import { LoadingStatePrompt } from '../../LoadingStatePrompt';
-import { px } from '../../../../style/variables';
-
-const SeeMoreButton = styled.button<{ show: boolean }>`
- display: ${(props) => (props.show ? 'flex' : 'none')};
- align-items: center;
- width: 100%;
- justify-content: space-between;
- &:hover {
- text-decoration: underline;
- }
-`;
-
-export function CustomLink({
- customLinks,
- status,
- onCreateCustomLinkClick,
- onSeeMoreClick,
- transaction,
-}: {
- customLinks: CustomLinkType[];
- status: FETCH_STATUS;
- onCreateCustomLinkClick: () => void;
- onSeeMoreClick: () => void;
- transaction: Transaction;
-}) {
- const renderEmptyPrompt = (
- <>
-
- {i18n.translate('xpack.apm.customLink.empty', {
- defaultMessage:
- 'No custom links found. Set up your own custom links, e.g., a link to a specific Dashboard or external link.',
- })}
-
-
-
- {i18n.translate('xpack.apm.customLink.buttom.create', {
- defaultMessage: 'Create custom link',
- })}
-
- >
- );
-
- const renderCustomLinkBottomSection = isEmpty(customLinks) ? (
- renderEmptyPrompt
- ) : (
- 3}>
-
- {i18n.translate('xpack.apm.transactionActionMenu.customLink.seeMore', {
- defaultMessage: 'See more',
- })}
-
-
-
- );
-
- return (
- <>
-
-
-
-
-
- {i18n.translate(
- 'xpack.apm.transactionActionMenu.customLink.section',
- {
- defaultMessage: 'Custom Links',
- }
- )}
-
-
-
-
-
-
-
-
-
- {i18n.translate('xpack.apm.transactionActionMenu.customLink.subtitle', {
- defaultMessage: 'Links will open in a new window.',
- })}
-
-
-
- {status === FETCH_STATUS.LOADING ? (
-
- ) : (
- renderCustomLinkBottomSection
- )}
- >
- );
-}
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.test.tsx
similarity index 82%
rename from x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx
rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.test.tsx
index 88a4137b47200..16d526bda2103 100644
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.test.tsx
@@ -5,7 +5,7 @@
*/
import React from 'react';
import { render } from '@testing-library/react';
-import { CustomLinkSection } from './CustomLinkSection';
+import { CustomLinkList } from './CustomLinkList';
import {
expectTextsInDocument,
expectTextsNotInDocument,
@@ -13,7 +13,7 @@ import {
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { CustomLink } from '../../../../../common/custom_link/custom_link_types';
-describe('CustomLinkSection', () => {
+describe('CustomLinkList', () => {
const customLinks = [
{ id: '1', label: 'foo', url: 'http://elastic.co' },
{
@@ -27,14 +27,14 @@ describe('CustomLinkSection', () => {
} as unknown) as Transaction;
it('shows links', () => {
const component = render(
-
+
);
expectTextsInDocument(component, ['foo', 'bar']);
});
it('doesnt show any links', () => {
const component = render(
-
+
);
expectTextsNotInDocument(component, ['foo', 'bar']);
});
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.tsx
new file mode 100644
index 0000000000000..0304b850d6cee
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkList.tsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import Mustache from 'mustache';
+import React from 'react';
+import {
+ SectionLinks,
+ SectionLink,
+} from '../../../../../../observability/public';
+import { CustomLink } from '../../../../../common/custom_link/custom_link_types';
+import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
+import { px, unit } from '../../../../style/variables';
+
+export function CustomLinkList({
+ customLinks,
+ transaction,
+}: {
+ customLinks: CustomLink[];
+ transaction: Transaction;
+}) {
+ return (
+
+ {customLinks.map((link) => {
+ const href = getHref(link, transaction);
+ return (
+
+ );
+ })}
+
+ );
+}
+
+function getHref(link: CustomLink, transaction: Transaction) {
+ try {
+ return Mustache.render(link.url, transaction);
+ } catch (e) {
+ return link.url;
+ }
+}
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.test.tsx
similarity index 78%
rename from x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx
rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.test.tsx
index 29e93a47629b3..0241167aba1fb 100644
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.test.tsx
@@ -12,7 +12,7 @@ import {
expectTextsInDocument,
expectTextsNotInDocument,
} from '../../../../utils/testHelpers';
-import { ManageCustomLink } from './ManageCustomLink';
+import { CustomLinkToolbar } from './CustomLinkToolbar';
function Wrapper({ children }: { children?: ReactNode }) {
return (
@@ -22,23 +22,20 @@ function Wrapper({ children }: { children?: ReactNode }) {
);
}
-describe('ManageCustomLink', () => {
+describe('CustomLinkToolbar', () => {
it('renders with create button', () => {
- const component = render(
- ,
- { wrapper: Wrapper }
- );
+ const component = render(, {
+ wrapper: Wrapper,
+ });
expect(
component.getByLabelText('Custom links settings page')
).toBeInTheDocument();
expectTextsInDocument(component, ['Create']);
});
+
it('renders without create button', () => {
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expect(
@@ -46,12 +43,11 @@ describe('ManageCustomLink', () => {
).toBeInTheDocument();
expectTextsNotInDocument(component, ['Create']);
});
+
it('opens flyout to create new custom link', () => {
const handleCreateCustomLinkClickMock = jest.fn();
const { getByText } = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expect(handleCreateCustomLinkClickMock).not.toHaveBeenCalled();
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.tsx
similarity index 85%
rename from x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx
rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.tsx
index 09cdaa26004bb..36b370b4069ae 100644
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/CustomLinkToolbar.tsx
@@ -14,12 +14,12 @@ import {
import { i18n } from '@kbn/i18n';
import { APMLink } from '../../Links/apm/APMLink';
-export function ManageCustomLink({
- onCreateCustomLinkClick,
- showCreateCustomLinkButton = true,
+export function CustomLinkToolbar({
+ onClickCreate,
+ showCreateButton = true,
}: {
- onCreateCustomLinkClick: () => void;
- showCreateCustomLinkButton?: boolean;
+ onClickCreate: () => void;
+ showCreateButton?: boolean;
}) {
return (
@@ -41,12 +41,12 @@ export function ManageCustomLink({
- {showCreateCustomLinkButton && (
+ {showCreateButton && (
{i18n.translate('xpack.apm.customLink.buttom.create.title', {
defaultMessage: 'Create',
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.test.tsx
similarity index 61%
rename from x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx
rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.test.tsx
index 5abeae265dfa6..db7a284f6adff 100644
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.test.tsx
@@ -7,11 +7,11 @@
import { act, fireEvent, render } from '@testing-library/react';
import React, { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
-import { CustomLink } from '.';
+import { CustomLinkMenuSection } from '.';
import { CustomLink as CustomLinkType } from '../../../../../common/custom_link/custom_link_types';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext';
-import { FETCH_STATUS } from '../../../../hooks/useFetcher';
+import * as useFetcher from '../../../../hooks/useFetcher';
import {
expectTextsInDocument,
expectTextsNotInDocument,
@@ -25,16 +25,27 @@ function Wrapper({ children }: { children?: ReactNode }) {
);
}
+const transaction = ({
+ service: {
+ name: 'name',
+ environment: 'env',
+ },
+ transaction: {
+ name: 'tx name',
+ type: 'tx type',
+ },
+} as unknown) as Transaction;
+
describe('Custom links', () => {
it('shows empty message when no custom link is available', () => {
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: [],
+ status: useFetcher.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
@@ -45,14 +56,14 @@ describe('Custom links', () => {
});
it('shows loading while custom links are fetched', () => {
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: [],
+ status: useFetcher.FETCH_STATUS.LOADING,
+ refetch: jest.fn(),
+ });
+
const { getByTestId } = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expect(getByTestId('loading-spinner')).toBeInTheDocument();
@@ -65,61 +76,68 @@ describe('Custom links', () => {
{ id: '3', label: 'baz', url: 'baz' },
{ id: '4', label: 'qux', url: 'qux' },
] as CustomLinkType[];
+
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: customLinks,
+ status: useFetcher.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expectTextsInDocument(component, ['foo', 'bar', 'baz']);
expectTextsNotInDocument(component, ['qux']);
});
- it('clicks on See more button', () => {
+ it('clicks "show all" and "show fewer"', () => {
const customLinks = [
{ id: '1', label: 'foo', url: 'foo' },
{ id: '2', label: 'bar', url: 'bar' },
{ id: '3', label: 'baz', url: 'baz' },
{ id: '4', label: 'qux', url: 'qux' },
] as CustomLinkType[];
- const onSeeMoreClickMock = jest.fn();
+
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: customLinks,
+ status: useFetcher.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
- expect(onSeeMoreClickMock).not.toHaveBeenCalled();
+
+ expect(component.getAllByRole('listitem').length).toEqual(3);
+ act(() => {
+ fireEvent.click(component.getByText('Show all'));
+ });
+ expect(component.getAllByRole('listitem').length).toEqual(4);
act(() => {
- fireEvent.click(component.getByText('See more'));
+ fireEvent.click(component.getByText('Show fewer'));
});
- expect(onSeeMoreClickMock).toHaveBeenCalled();
+ expect(component.getAllByRole('listitem').length).toEqual(3);
});
describe('create custom link buttons', () => {
it('shows create button below empty message', () => {
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: [],
+ status: useFetcher.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expectTextsInDocument(component, ['Create custom link']);
expectTextsNotInDocument(component, ['Create']);
});
+
it('shows create button besides the title', () => {
const customLinks = [
{ id: '1', label: 'foo', url: 'foo' },
@@ -127,14 +145,15 @@ describe('Custom links', () => {
{ id: '3', label: 'baz', url: 'baz' },
{ id: '4', label: 'qux', url: 'qux' },
] as CustomLinkType[];
+
+ jest.spyOn(useFetcher, 'useFetcher').mockReturnValue({
+ data: customLinks,
+ status: useFetcher.FETCH_STATUS.SUCCESS,
+ refetch: jest.fn(),
+ });
+
const component = render(
- ,
+ ,
{ wrapper: Wrapper }
);
expectTextsInDocument(component, ['Create']);
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.tsx
new file mode 100644
index 0000000000000..2825363b10197
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLinkMenuSection/index.tsx
@@ -0,0 +1,207 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React, { useMemo, useState } from 'react';
+import {
+ EuiText,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiSpacer,
+ EuiButtonEmpty,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { isEmpty } from 'lodash';
+import {
+ ActionMenuDivider,
+ Section,
+ SectionSubtitle,
+ SectionTitle,
+} from '../../../../../../observability/public';
+import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
+import { CustomLinkList } from './CustomLinkList';
+import { CustomLinkToolbar } from './CustomLinkToolbar';
+import { FETCH_STATUS, useFetcher } from '../../../../hooks/useFetcher';
+import { LoadingStatePrompt } from '../../LoadingStatePrompt';
+import { px } from '../../../../style/variables';
+import { CreateEditCustomLinkFlyout } from '../../../app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout';
+import { convertFiltersToQuery } from '../../../app/Settings/CustomizeUI/CustomLink/CreateEditCustomLinkFlyout/helper';
+import {
+ CustomLink,
+ Filter,
+} from '../../../../../common/custom_link/custom_link_types';
+
+const DEFAULT_LINKS_TO_SHOW = 3;
+
+export function CustomLinkMenuSection({
+ transaction,
+}: {
+ transaction: Transaction;
+}) {
+ const [showAllLinks, setShowAllLinks] = useState(false);
+ const [isCreateEditFlyoutOpen, setIsCreateEditFlyoutOpen] = useState(false);
+
+ const filters = useMemo(
+ () =>
+ [
+ { key: 'service.name', value: transaction?.service.name },
+ { key: 'service.environment', value: transaction?.service.environment },
+ { key: 'transaction.name', value: transaction?.transaction.name },
+ { key: 'transaction.type', value: transaction?.transaction.type },
+ ].filter((filter): filter is Filter => typeof filter.value === 'string'),
+ [transaction]
+ );
+
+ const { data: customLinks = [], status, refetch } = useFetcher(
+ (callApmApi) =>
+ callApmApi({
+ isCachable: true,
+ endpoint: 'GET /api/apm/settings/custom_links',
+ params: { query: convertFiltersToQuery(filters) },
+ }),
+ [filters]
+ );
+
+ return (
+ <>
+ {isCreateEditFlyoutOpen && (
+ {
+ setIsCreateEditFlyoutOpen(false);
+ }}
+ onSave={() => {
+ setIsCreateEditFlyoutOpen(false);
+ refetch();
+ }}
+ onDelete={() => {
+ setIsCreateEditFlyoutOpen(false);
+ refetch();
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.transactionActionMenu.customLink.section',
+ {
+ defaultMessage: 'Custom Links',
+ }
+ )}
+
+
+
+ setIsCreateEditFlyoutOpen(true)}
+ showCreateButton={customLinks.length > 0}
+ />
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.apm.transactionActionMenu.customLink.subtitle',
+ {
+ defaultMessage: 'Links will open in a new window.',
+ }
+ )}
+
+
+
+ setShowAllLinks((show) => !show)}
+ onClickCreate={() => setIsCreateEditFlyoutOpen(true)}
+ />
+
+ >
+ );
+}
+
+function BottomSection({
+ status,
+ customLinks,
+ showAllLinks,
+ toggleShowAll,
+ onClickCreate,
+}: {
+ status: FETCH_STATUS;
+ customLinks: CustomLink[];
+ showAllLinks: boolean;
+ toggleShowAll: () => void;
+ onClickCreate: () => void;
+}) {
+ if (status === FETCH_STATUS.LOADING) {
+ return ;
+ }
+
+ // render empty prompt if there are no custom links
+ if (isEmpty(customLinks)) {
+ return (
+
+
+
+ {i18n.translate('xpack.apm.customLink.empty', {
+ defaultMessage:
+ 'No custom links found. Set up your own custom links, e.g., a link to a specific Dashboard or external link.',
+ })}
+
+
+
+ {i18n.translate('xpack.apm.customLink.buttom.create', {
+ defaultMessage: 'Create custom link',
+ })}
+
+
+
+ );
+ }
+
+ // render button to toggle "Show all" / "Show fewer"
+ if (customLinks.length > DEFAULT_LINKS_TO_SHOW) {
+ return (
+
+
+
+
+ {showAllLinks
+ ? i18n.translate(
+ 'xpack.apm.transactionActionMenu.customLink.showFewer',
+ { defaultMessage: 'Show fewer' }
+ )
+ : i18n.translate(
+ 'xpack.apm.transactionActionMenu.customLink.showAll',
+ { defaultMessage: 'Show all' }
+ )}
+
+
+
+
+ );
+ }
+
+ return null;
+}
diff --git a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
index f5a57544209f5..15a85113406e1 100644
--- a/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
+++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
@@ -6,7 +6,7 @@
import { EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import React, { useMemo, useState } from 'react';
+import React, { useState } from 'react';
import { useLocation } from 'react-router-dom';
import {
ActionMenu,
@@ -17,16 +17,11 @@ import {
SectionSubtitle,
SectionTitle,
} from '../../../../../observability/public';
-import { Filter } from '../../../../common/custom_link/custom_link_types';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { useApmPluginContext } from '../../../hooks/useApmPluginContext';
-import { useFetcher } from '../../../hooks/useFetcher';
import { useLicense } from '../../../hooks/useLicense';
import { useUrlParams } from '../../../hooks/useUrlParams';
-import { CustomLinkFlyout } from '../../app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout';
-import { convertFiltersToQuery } from '../../app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper';
-import { CustomLink } from './CustomLink';
-import { CustomLinkPopover } from './CustomLink/CustomLinkPopover';
+import { CustomLinkMenuSection } from './CustomLinkMenuSection';
import { getSections } from './sections';
interface Props {
@@ -45,37 +40,13 @@ function ActionMenuButton({ onClick }: { onClick: () => void }) {
export function TransactionActionMenu({ transaction }: Props) {
const license = useLicense();
- const hasValidLicense = license?.isActive && license?.hasAtLeast('gold');
+ const hasGoldLicense = license?.isActive && license?.hasAtLeast('gold');
const { core } = useApmPluginContext();
const location = useLocation();
const { urlParams } = useUrlParams();
const [isActionPopoverOpen, setIsActionPopoverOpen] = useState(false);
- const [isCustomLinksPopoverOpen, setIsCustomLinksPopoverOpen] = useState(
- false
- );
- const [isCustomLinkFlyoutOpen, setIsCustomLinkFlyoutOpen] = useState(false);
-
- const filters = useMemo(
- () =>
- [
- { key: 'service.name', value: transaction?.service.name },
- { key: 'service.environment', value: transaction?.service.environment },
- { key: 'transaction.name', value: transaction?.transaction.name },
- { key: 'transaction.type', value: transaction?.transaction.type },
- ].filter((filter): filter is Filter => typeof filter.value === 'string'),
- [transaction]
- );
-
- const { data: customLinks = [], status, refetch } = useFetcher(
- (callApmApi) =>
- callApmApi({
- endpoint: 'GET /api/apm/settings/custom_links',
- params: { query: convertFiltersToQuery(filters) },
- }),
- [filters]
- );
const sections = getSections({
transaction,
@@ -84,39 +55,11 @@ export function TransactionActionMenu({ transaction }: Props) {
urlParams,
});
- const closePopover = () => {
- setIsActionPopoverOpen(false);
- setIsCustomLinksPopoverOpen(false);
- };
-
- const toggleCustomLinkFlyout = () => {
- closePopover();
- setIsCustomLinkFlyoutOpen((isOpen) => !isOpen);
- };
-
- const toggleCustomLinkPopover = () => {
- setIsCustomLinksPopoverOpen((isOpen) => !isOpen);
- };
-
return (
<>
- {isCustomLinkFlyoutOpen && (
- {
- toggleCustomLinkFlyout();
- refetch();
- }}
- onDelete={() => {
- toggleCustomLinkFlyout();
- refetch();
- }}
- />
- )}
diff --git a/x-pack/plugins/observability/public/components/shared/action_menu/index.tsx b/x-pack/plugins/observability/public/components/shared/action_menu/index.tsx
index 55746ff6576a9..4819a0760d88a 100644
--- a/x-pack/plugins/observability/public/components/shared/action_menu/index.tsx
+++ b/x-pack/plugins/observability/public/components/shared/action_menu/index.tsx
@@ -12,11 +12,11 @@ import {
EuiHorizontalRule,
EuiListGroupItem,
EuiPopoverProps,
+ EuiListGroupItemProps,
} from '@elastic/eui';
-
import React, { HTMLAttributes, ReactNode } from 'react';
-import { EuiListGroupItemProps } from '@elastic/eui/src/components/list_group/list_group_item';
import styled from 'styled-components';
+import { EuiListGroupProps } from '@elastic/eui';
type Props = EuiPopoverProps & HTMLAttributes;
@@ -42,9 +42,9 @@ export function SectionSubtitle({ children }: { children?: ReactNode }) {
);
}
-export function SectionLinks({ children }: { children?: ReactNode }) {
+export function SectionLinks({ children, ...props }: { children?: ReactNode } & EuiListGroupProps) {
return (
-
+
{children}
);
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index b5c6a4e3fd03f..cc91c0ccfb3bf 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -5190,9 +5190,7 @@
"xpack.apm.transactionActionMenu.actionsButtonLabel": "アクション",
"xpack.apm.transactionActionMenu.container.subtitle": "このコンテナーのログとインデックスを表示し、さらに詳細を確認できます。",
"xpack.apm.transactionActionMenu.container.title": "コンテナーの詳細",
- "xpack.apm.transactionActionMenu.customLink.popover.title": "カスタムリンク",
"xpack.apm.transactionActionMenu.customLink.section": "カスタムリンク",
- "xpack.apm.transactionActionMenu.customLink.seeMore": "詳細を表示",
"xpack.apm.transactionActionMenu.customLink.subtitle": "リンクは新しいウィンドウで開きます。",
"xpack.apm.transactionActionMenu.host.subtitle": "ホストログとメトリックを表示し、さらに詳細を確認できます。",
"xpack.apm.transactionActionMenu.host.title": "ホストの詳細",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index a2d42dcfcdc52..0fa33f57db59b 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -5194,9 +5194,7 @@
"xpack.apm.transactionActionMenu.actionsButtonLabel": "操作",
"xpack.apm.transactionActionMenu.container.subtitle": "查看此容器的日志和指标以获取进一步详情。",
"xpack.apm.transactionActionMenu.container.title": "容器详情",
- "xpack.apm.transactionActionMenu.customLink.popover.title": "定制链接",
"xpack.apm.transactionActionMenu.customLink.section": "定制链接",
- "xpack.apm.transactionActionMenu.customLink.seeMore": "查看更多内容",
"xpack.apm.transactionActionMenu.customLink.subtitle": "链接将在新窗口打开。",
"xpack.apm.transactionActionMenu.host.subtitle": "查看主机日志和指标以获取进一步详情。",
"xpack.apm.transactionActionMenu.host.title": "主机详情",