Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Disable Create custom link button on Transaction details page for read-only users #88485

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions x-pack/plugins/apm/common/custom_link/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ export const INVALID_LICENSE = i18n.translate(
"To create custom links, you must be subscribed to an Elastic Gold license or above. With it, you'll have the ability to create custom links to improve your workflow when analyzing your services.",
}
);

export const NO_PERMISSION_LABEL = i18n.translate(
'xpack.apm.settings.customizeUI.customLink.noPermissionTooltipLabel',
{
defaultMessage:
"Your user role doesn't have permissions to create custom links",
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,14 @@
import { EuiButton, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { NO_PERMISSION_LABEL } from '../../../../../../common/custom_link';
import { useApmPluginContext } from '../../../../../context/apm_plugin/use_apm_plugin_context';

export function CreateCustomLinkButton({ onClick }: { onClick: () => void }) {
const { core } = useApmPluginContext();
const canSave = core.application.capabilities.apm.save;
return (
<EuiToolTip
content={
!canSave &&
i18n.translate(
'xpack.apm.settings.customizeUI.customLink.noPermissionTooltipLabel',
{
defaultMessage:
"Your user role doesn't have permissions to create custom links",
}
)
}
>
<EuiToolTip content={!canSave && NO_PERMISSION_LABEL}>
<EuiButton
color="primary"
fill
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,33 @@
import { act, fireEvent, render } from '@testing-library/react';
import React, { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context';
import { ApmPluginContextValue } from '../../../../context/apm_plugin/apm_plugin_context';
import {
mockApmPluginContextValue,
MockApmPluginContextWrapper,
} from '../../../../context/apm_plugin/mock_apm_plugin_context';
import {
expectTextsInDocument,
expectTextsNotInDocument,
} from '../../../../utils/testHelpers';
import { CustomLinkToolbar } from './CustomLinkToolbar';

function getMockAPMContext({ canSave }: { canSave: boolean }) {
return ({
...mockApmPluginContextValue,
core: {
...mockApmPluginContextValue.core,
application: { capabilities: { apm: { save: canSave }, ml: {} } },
},
} as unknown) as ApmPluginContextValue;
}

function Wrapper({ children }: { children?: ReactNode }) {
return (
<MemoryRouter>
<MockApmPluginContextWrapper>{children}</MockApmPluginContextWrapper>
<MockApmPluginContextWrapper value={getMockAPMContext({ canSave: true })}>
{children}
</MockApmPluginContextWrapper>
</MemoryRouter>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
EuiIcon,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { NO_PERMISSION_LABEL } from '../../../../../common/custom_link';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import { APMLink } from '../../Links/apm/APMLink';

export function CustomLinkToolbar({
Expand All @@ -21,6 +23,9 @@ export function CustomLinkToolbar({
onClickCreate: () => void;
showCreateButton?: boolean;
}) {
const { core } = useApmPluginContext();
const canSave = !!core.application.capabilities.apm.save;

return (
<EuiFlexGroup>
<EuiFlexItem>
Expand All @@ -42,17 +47,20 @@ export function CustomLinkToolbar({
</EuiToolTip>
</EuiFlexItem>
{showCreateButton && (
<EuiFlexItem grow={false}>
<EuiButtonEmpty
iconType="plusInCircle"
size="xs"
onClick={onClickCreate}
>
{i18n.translate('xpack.apm.customLink.buttom.create.title', {
defaultMessage: 'Create',
})}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiToolTip content={!canSave && NO_PERMISSION_LABEL}>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
isDisabled={!canSave}
iconType="plusInCircle"
size="xs"
onClick={onClickCreate}
>
{i18n.translate('xpack.apm.customLink.buttom.create.title', {
defaultMessage: 'Create',
})}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiToolTip>
)}
</EuiFlexGroup>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isEmpty } from 'lodash';
import { EuiToolTip } from '@elastic/eui';
import { NO_PERMISSION_LABEL } from '../../../../../common/custom_link';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import {
ActionMenuDivider,
Section,
Expand Down Expand Up @@ -147,14 +150,17 @@ function BottomSection({
toggleShowAll: () => void;
onClickCreate: () => void;
}) {
const { core } = useApmPluginContext();
const canSave = !!core.application.capabilities.apm.save;

if (status === FETCH_STATUS.LOADING) {
return <LoadingStatePrompt />;
}

// render empty prompt if there are no custom links
if (isEmpty(customLinks)) {
return (
<EuiFlexGroup>
<EuiFlexGroup responsive={false} direction="column" gutterSize="none">
<EuiFlexItem>
<EuiText size="xs" grow={false} style={{ width: px(300) }}>
{i18n.translate('xpack.apm.customLink.empty', {
Expand All @@ -163,15 +169,20 @@ function BottomSection({
})}
</EuiText>
<EuiSpacer size="s" />
<EuiButtonEmpty
iconType="plusInCircle"
size="xs"
onClick={onClickCreate}
>
{i18n.translate('xpack.apm.customLink.buttom.create', {
defaultMessage: 'Create custom link',
})}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem style={{ alignItems: 'center' }}>
<EuiToolTip content={!canSave && NO_PERMISSION_LABEL}>
<EuiButtonEmpty
isDisabled={!canSave}
iconType="plusInCircle"
size="xs"
onClick={onClickCreate}
>
{i18n.translate('xpack.apm.customLink.buttom.create', {
defaultMessage: 'Create custom link',
})}
</EuiButtonEmpty>
</EuiToolTip>
</EuiFlexItem>
</EuiFlexGroup>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { License } from '../../../../../licensing/common/license';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context';
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
import {
mockApmPluginContextValue,
MockApmPluginContextWrapper,
} from '../../../context/apm_plugin/mock_apm_plugin_context';
import { LicenseContext } from '../../../context/license/license_context';
import * as hooks from '../../../hooks/use_fetcher';
import * as apmApi from '../../../services/rest/createCallApmApi';
Expand All @@ -20,10 +24,22 @@ import {
import { TransactionActionMenu } from './TransactionActionMenu';
import * as Transactions from './__fixtures__/mockData';

function getMockAPMContext({ canSave }: { canSave: boolean }) {
return ({
...mockApmPluginContextValue,
core: {
...mockApmPluginContextValue.core,
application: { capabilities: { apm: { save: canSave }, ml: {} } },
},
} as unknown) as ApmPluginContextValue;
}

function Wrapper({ children }: { children?: React.ReactNode }) {
return (
<MemoryRouter>
<MockApmPluginContextWrapper>{children}</MockApmPluginContextWrapper>
<MockApmPluginContextWrapper value={getMockAPMContext({ canSave: true })}>
{children}
</MockApmPluginContextWrapper>
</MemoryRouter>
);
}
Expand Down