fix for #1273, added component for showing permission restricted acce… (#1422)

# What this PR does

- Removed unused code
- Added another component for displaying Error Messages based on
permissions access (so that we do not duplicate this code everywhere
it's needed)
- Fix for #1273 

## Which issue(s) this PR fixes

- #1273 

## Checklist

- [ ] Tests updated
- [ ] Documentation added
- [ ] `CHANGELOG.md` updated
This commit is contained in:
Rares Mardare 2023-03-02 17:32:59 +02:00 committed by GitHub
parent 2a311c6289
commit d182e71f62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 325 additions and 340 deletions

View file

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Fixed
- Show permission error for accessing Telegram as Viewer ([1273](https://github.com/grafana/oncall/issues/1273))
## v1.1.32 (2023-03-01)
### Fixed

View file

@ -13,7 +13,7 @@ import MonacoJinja2Editor from 'components/MonacoJinja2Editor/MonacoJinja2Editor
import SourceCode from 'components/SourceCode/SourceCode';
import Text from 'components/Text/Text';
import TemplatePreview from 'containers/TemplatePreview/TemplatePreview';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
import { Alert } from 'models/alertgroup/alertgroup.types';
import { makeRequest } from 'network';
@ -153,11 +153,11 @@ const AlertTemplatesForm = (props: AlertTemplatesFormProps) => {
<HorizontalGroup>
<Text type="secondary">There are no alerts from this monitoring yet.</Text>
{demoAlertEnabled ? (
<WithPermissionControl userAction={UserActions.IntegrationsTest}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsTest}>
<Button className={cx('button')} variant="primary" onClick={handleSendDemoAlertClick} size="sm">
Send demo alert
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
) : null}
</HorizontalGroup>
);
@ -240,11 +240,11 @@ const AlertTemplatesForm = (props: AlertTemplatesFormProps) => {
</div>
))}
<HorizontalGroup spacing="sm">
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button variant="primary" onClick={handleSubmit}>
Save Templates
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
<Button variant="destructive" onClick={handleReset}>
Reset Template
</Button>

View file

@ -6,7 +6,7 @@ import cn from 'classnames/bind';
import Block from 'components/GBlock/Block';
import Text from 'components/Text/Text';
import ScheduleForm from 'containers/ScheduleForm/ScheduleForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Schedule, ScheduleType } from 'models/schedule/schedule.types';
import { UserActions } from 'utils/authorization';
@ -49,11 +49,11 @@ const NewScheduleSelector: FC<NewScheduleSelectorProps> = (props) => {
<Text type="secondary">Configure rotations and shifts directly in Grafana On-Call</Text>
</VerticalGroup>
</HorizontalGroup>
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip userAction={UserActions.SchedulesWrite}>
<Button variant="primary" icon="plus" onClick={getCreateScheduleClickHandler(ScheduleType.API)}>
Create
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</Block>
<Block bordered withBackground className={cx('block')}>

View file

@ -12,7 +12,7 @@ import TimeRange from 'components/TimeRange/TimeRange';
import Timeline from 'components/Timeline/Timeline';
import GSelect from 'containers/GSelect/GSelect';
import UserTooltip from 'containers/UserTooltip/UserTooltip';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { prepareEscalationPolicy } from 'models/escalation_policy/escalation_policy.helpers';
import {
EscalationPolicy as EscalationPolicyType,
@ -53,14 +53,14 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
return (
<Timeline.Item key={id} contentClassName={cx('root')} number={number} color={color}>
<WithPermissionControl disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<DragHandle />
</WithPermissionControl>
</WithPermissionControlTooltip>
{escalationOption &&
reactStringReplace(escalationOption.display_name, /\{\{([^}]+)\}\}/g, this.replacePlaceholder)}
{this._renderNote()}
{is_final ? null : (
<WithPermissionControl className={cx('delete')} userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip className={cx('delete')} userAction={UserActions.EscalationChainsWrite}>
<IconButton
name="trash-alt"
className={cx('delete', 'control')}
@ -69,7 +69,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
tooltip="Delete"
tooltipPlacement="top"
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
</Timeline.Item>
);
@ -134,7 +134,11 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { notify_to_users_queue } = data;
return (
<WithPermissionControl key="users-multiple" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip
key="users-multiple"
disableByPaywall
userAction={UserActions.EscalationChainsWrite}
>
<GSelect
isMulti
showSearch
@ -148,7 +152,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
onChange={this._getOnChangeHandler('notify_to_users_queue')}
getOptionLabel={({ value }: SelectableValue) => <UserTooltip id={value} />}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -157,7 +161,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { important } = data;
return (
<WithPermissionControl key="importance" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip key="importance" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<Select
menuShouldPortal
className={cx('select', 'control')}
@ -169,7 +173,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
{ value: 1, label: 'Important', description: 'Manage "Important notifications" in personal settings' },
]}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -177,14 +181,14 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { data } = this.props;
return (
<WithPermissionControl key="time-range" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip key="time-range" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<TimeRange
from={data.from_time}
to={data.to_time}
onChange={this._getOnTimeRangeChangeHandler()}
className={cx('select', 'control')}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -193,7 +197,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { wait_delay } = data;
return (
<WithPermissionControl key="wait-delay" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip key="wait-delay" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<Select
menuShouldPortal
placeholder="Select Wait Delay"
@ -206,7 +210,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
label: waitDelay.display_name,
}))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -215,7 +219,11 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { num_alerts_in_window } = data;
return (
<WithPermissionControl key="num_alerts_in_window" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip
key="num_alerts_in_window"
disableByPaywall
userAction={UserActions.EscalationChainsWrite}
>
<Input
placeholder="Count"
className={cx('control')}
@ -228,7 +236,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
}
}}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -237,7 +245,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { num_minutes_in_window } = data;
return (
<WithPermissionControl
<WithPermissionControlTooltip
key="num_minutes_in_window"
disableByPaywall
userAction={UserActions.EscalationChainsWrite}
@ -254,7 +262,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
label: waitDelay.display_name,
}))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -263,7 +271,11 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { notify_schedule } = data;
return (
<WithPermissionControl key="notify_schedule" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip
key="notify_schedule"
disableByPaywall
userAction={UserActions.EscalationChainsWrite}
>
<GSelect
showSearch
allowClear
@ -276,7 +288,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
onChange={this._getOnChangeHandler('notify_schedule')}
fromOrganization
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -285,7 +297,11 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { notify_to_group } = data;
return (
<WithPermissionControl key="notify_to_group" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip
key="notify_to_group"
disableByPaywall
userAction={UserActions.EscalationChainsWrite}
>
<GSelect
modelName="userGroupStore"
displayField="name"
@ -295,7 +311,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
value={notify_to_group}
onChange={this._getOnChangeHandler('notify_to_group')}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -304,7 +320,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
const { custom_button_trigger } = data;
return (
<WithPermissionControl key="custom-button" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip key="custom-button" disableByPaywall userAction={UserActions.EscalationChainsWrite}>
<GSelect
modelName="outgoingWebhookStore"
displayField="name"
@ -315,7 +331,7 @@ export class EscalationPolicy extends React.Component<EscalationPolicyProps, any
onChange={this._getOnChangeHandler('custom_button_trigger')}
fromOrganization
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}

View file

@ -7,7 +7,7 @@ import { SortableElement } from 'react-sortable-hoc';
import PluginLink from 'components/PluginLink/PluginLink';
import Timeline from 'components/Timeline/Timeline';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Channel } from 'models/channel';
import { NotificationPolicyType, prepareNotificationPolicy } from 'models/notification_policy';
import { NotifyBy } from 'models/notify_by';
@ -51,26 +51,26 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
return (
<Timeline.Item className={cx('root')} number={number} color={color}>
<div className={cx('step')}>
<WithPermissionControl disableByPaywall userAction={userAction}>
<WithPermissionControlTooltip disableByPaywall userAction={userAction}>
<DragHandle />
</WithPermissionControl>
<WithPermissionControl disableByPaywall userAction={userAction}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip disableByPaywall userAction={userAction}>
<Select
className={cx('select', 'control')}
onChange={this._getOnChangeHandler('step')}
value={step}
options={notificationChoices.map((option: any) => ({ label: option.display_name, value: option.value }))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
{this._renderControls()}
<WithPermissionControl userAction={userAction}>
<WithPermissionControlTooltip userAction={userAction}>
<IconButton
className={cx('control')}
name="trash-alt"
onClick={this._getDeleteClickHandler(id)}
variant="secondary"
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
{this._renderNote()}
</div>
</Timeline.Item>
@ -163,7 +163,7 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
const { wait_delay } = data;
return (
<WithPermissionControl userAction={userAction} disableByPaywall>
<WithPermissionControlTooltip userAction={userAction} disableByPaywall>
<Select
key="wait-delay"
placeholder="Wait Delay"
@ -176,7 +176,7 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
value: waitDelay.value,
}))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}
@ -185,7 +185,7 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
const { notify_by } = data;
return (
<WithPermissionControl userAction={userAction} disableByPaywall>
<WithPermissionControlTooltip userAction={userAction} disableByPaywall>
<Select
key="notify_by"
placeholder="Notify by"
@ -198,7 +198,7 @@ export class NotificationPolicy extends React.Component<NotificationPolicyProps,
value: notifyByOption.value,
}))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}

View file

@ -28,7 +28,7 @@ import EscalationChainForm from 'containers/EscalationChainForm/EscalationChainF
import EscalationChainSteps from 'containers/EscalationChainSteps/EscalationChainSteps';
import GSelect from 'containers/GSelect/GSelect';
import { IntegrationSettingsTab } from 'containers/IntegrationSettings/IntegrationSettings.types';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { AlertReceiveChannel, MaintenanceMode } from 'models/alert_receive_channel/alert_receive_channel.types';
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
@ -181,7 +181,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
>
How to connect
</Button>
<WithPermissionControl userAction={UserActions.IntegrationsTest}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsTest}>
<Button
variant="secondary"
size="sm"
@ -189,7 +189,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
>
Send demo alert
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
<div className={cx('icons-container')}>
{maintenanceMode === MaintenanceMode.Debug || maintenanceMode === MaintenanceMode.Maintenance ? (
<Tooltip placement="top" content="Stop maintenance mode">
@ -210,7 +210,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
}}
disabled={!isUserActionAllowed(UserActions.MaintenanceWrite)}
>
<WithPermissionControl userAction={UserActions.MaintenanceWrite}>
<WithPermissionControlTooltip userAction={UserActions.MaintenanceWrite}>
<IconButton
name="pause"
size="sm"
@ -218,7 +218,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
tooltipPlacement="top"
disabled={!isUserActionAllowed(UserActions.MaintenanceWrite)}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</PluginLink>
)}
<IconButton
@ -230,7 +230,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
onShowSettings();
}}
/>
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<WithConfirm
title="Delete integration?"
body={
@ -248,7 +248,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
name="trash-alt"
/>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
</div>
</div>
@ -305,7 +305,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
Change alert template and grouping
</Button>
{!alertReceiveChannelIdToCreateChannelFilter && (
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button
icon="plus"
className={cx('add-new-chain-button', 'TEST-add-new-chain-button')}
@ -314,7 +314,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
>
Add Route
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
</div>
{alertReceiveChannelIdToCreateChannelFilter && (
@ -538,7 +538,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
<Text size="small" type="secondary">
{warningAboutModifyingEscalationChain}
You can{' '}
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<Button
fill="text"
size="sm"
@ -551,9 +551,9 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
>
Make a copy
</Button>
</WithPermissionControl>{' '}
</WithPermissionControlTooltip>{' '}
of the current chain or{' '}
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<Button
fill="text"
size="sm"
@ -565,7 +565,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
>
Create a new chain
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Text>
</div>
{this._renderEscalationPolicies(channelFilter.id)}
@ -621,7 +621,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
return (
<HorizontalGroup spacing="xs">
{Boolean(index > 0 && !channelFilter.is_default) && (
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<IconButton
size="sm"
name="arrow-up"
@ -632,11 +632,11 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
tooltip="Move up"
tooltipPlacement="top"
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{Boolean(index < channelFilterIds.length - 2 && !channelFilter.is_default) && (
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<IconButton
size="sm"
name="arrow-down"
@ -647,10 +647,10 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
tooltip="Move down"
tooltipPlacement="top"
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{!channelFilter.is_default && (
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<IconButton
size="md"
name="trash-alt"
@ -658,9 +658,9 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
tooltip="Delete"
tooltipPlacement="top"
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<IconButton
size="md"
name="pen"
@ -673,12 +673,12 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
tooltip="Edit"
tooltipPlacement="top"
/>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.IntegrationsTest}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsTest}>
<Button variant="secondary" size="sm" onClick={this.getSendDemoAlertToParticularRoute(channelFilterId)}>
Send demo alert
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
);
};
@ -710,7 +710,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
</>
)}
escalate to{' '}
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<div onClick={(e) => e.stopPropagation()}>
<GSelect
showSearch
@ -723,7 +723,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
showWarningIfEmptyValue={true}
/>
</div>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
<div onClick={(e) => e.stopPropagation()}>{this.renderChannelFilterButtons(channelFilterId, index)}</div>
</div>

View file

@ -6,7 +6,7 @@ import cn from 'classnames/bind';
import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import GSelect from 'containers/GSelect/GSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
import { PRIVATE_CHANNEL_NAME } from 'models/slack_channel/slack_channel.config';
import { getSlackChannelName } from 'models/slack_channel/slack_channel.helpers';
@ -43,16 +43,16 @@ const SlackConnector = (props: SlackConnectorProps) => {
<div className={cx('root')}>
<HorizontalGroup wrap spacing="sm">
<div className={cx('slack-channel-switch')}>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<InlineSwitch
value={channelFilter.notify_in_slack}
onChange={handleChannelFilterNotifyInSlackChange}
transparent
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
Post to slack channel
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<GSelect
showSearch
allowClear
@ -65,7 +65,7 @@ const SlackConnector = (props: SlackConnectorProps) => {
onChange={handleSlackChannelChange}
nullItemName={PRIVATE_CHANNEL_NAME}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
<HorizontalGroup>
{Boolean(
channelFilter.slack_channel?.id &&
@ -75,7 +75,7 @@ const SlackConnector = (props: SlackConnectorProps) => {
<Text type="secondary">
default slack channel is{' '}
<Text strong>#{getSlackChannelName(store.teamStore.currentTeam?.slack_channel)}</Text>{' '}
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button
variant="primary"
size="sm"
@ -89,17 +89,17 @@ const SlackConnector = (props: SlackConnectorProps) => {
>
Use it here
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Text>
) : teamStore.currentTeam?.slack_channel?.id ? (
<Text type="secondary">
This is the default slack channel{' '}
<PluginLink query={{ page: 'chat-ops' }} disabled={!isUserActionAllowed(UserActions.ChatOpsWrite)}>
<WithPermissionControl userAction={UserActions.ChatOpsUpdateSettings}>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
<Button variant="primary" size="sm" fill="text">
Change in Slack settings
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</PluginLink>
</Text>
) : null}

View file

@ -4,7 +4,7 @@ import { HorizontalGroup, InlineSwitch } from '@grafana/ui';
import cn from 'classnames/bind';
import GSelect from 'containers/GSelect/GSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
import { TelegramChannel } from 'models/telegram_channel/telegram_channel.types';
import { useStore } from 'state/useStore';
@ -36,16 +36,16 @@ const TelegramConnector = ({ channelFilterId }: TelegramConnectorProps) => {
<div className={cx('root')}>
<HorizontalGroup wrap spacing="sm">
<div className={cx('slack-channel-switch')}>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<InlineSwitch
value={channelFilter.notify_in_telegram}
onChange={handleChannelFilterNotifyInTelegramChange}
transparent
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
Post to telegram channel
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<GSelect
showSearch
allowClear
@ -57,7 +57,7 @@ const TelegramConnector = ({ channelFilterId }: TelegramConnectorProps) => {
value={channelFilter.telegram_channel}
onChange={handleTelegramChannelChange}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
);

View file

@ -8,7 +8,7 @@ import moment from 'moment-timezone';
import GTable from 'components/GTable/GTable';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { ApiToken } from 'models/api_token/api_token.types';
import { WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
@ -85,7 +85,7 @@ class ApiTokens extends React.Component<ApiTokensProps, any> {
<HorizontalGroup align="flex-end">
<Text.Title level={3}>API Tokens</Text.Title>
</HorizontalGroup>
<WithPermissionControl userAction={UserActions.APIKeysWrite}>
<WithPermissionControlTooltip userAction={UserActions.APIKeysWrite}>
<Button
icon="plus"
disabled={apiTokens && apiTokens.length >= MAX_TOKENS_PER_USER}
@ -95,7 +95,7 @@ class ApiTokens extends React.Component<ApiTokensProps, any> {
>
Create
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
)}
rowKey="id"
@ -120,13 +120,13 @@ class ApiTokens extends React.Component<ApiTokensProps, any> {
renderActionButtons = (record: ApiToken) => {
const revokeButton = (
<WithPermissionControl userAction={UserActions.APIKeysWrite}>
<WithPermissionControlTooltip userAction={UserActions.APIKeysWrite}>
<WithConfirm title={`Are you sure to revoke "${record.name}" API token?`} confirmText="Revoke token">
<Button fill="text" variant="destructive" onClick={this.getRevokeTokenClickHandler(record.id)}>
Revoke
</Button>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
return revokeButton;

View file

@ -8,7 +8,7 @@ import moment from 'moment-timezone';
import Text from 'components/Text/Text';
import GSelect from 'containers/GSelect/GSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Alert } from 'models/alertgroup/alertgroup.types';
import { useStore } from 'state/useStore';
import { UserActions } from 'utils/authorization';
@ -73,7 +73,7 @@ const AttachIncidentForm = observer(({ id, onUpdate, onHide }: AttachIncidentFor
label="Incident to be attached with"
description="Linking incidents together can help the team investigate the underlying issue."
>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<GSelect
showSearch
modelName="alertGroupStore"
@ -87,7 +87,7 @@ const AttachIncidentForm = observer(({ id, onUpdate, onHide }: AttachIncidentFor
getDescription={(item: Alert) => moment(item.started_at).format('MMM DD, YYYY hh:mm A')}
getOptionLabel={(item: SelectableValue) => <GroupedAlertNumber value={item.value} />}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Field>
<HorizontalGroup>
<Button onClick={onHide} variant="secondary">

View file

@ -8,7 +8,7 @@ import { observer } from 'mobx-react';
import EscalationPolicy from 'components/Policy/EscalationPolicy';
import SortableList from 'components/SortableList/SortableList';
import Timeline from 'components/Timeline/Timeline';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
import { EscalationPolicyOption } from 'models/escalation_policy/escalation_policy.types';
import { useStore } from 'state/useStore';
@ -96,7 +96,7 @@ const EscalationChainSteps = observer((props: EscalationChainStepsProps) => {
number={(escalationPolicyIds?.length || 0) + offset + 1}
color={getComputedStyle(document.documentElement).getPropertyValue('--tag-secondary')}
>
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<Select
isSearchable
menuShouldPortal
@ -108,7 +108,7 @@ const EscalationChainSteps = observer((props: EscalationChainStepsProps) => {
}))}
value={null}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Timeline.Item>
</SortableList>
);

View file

@ -9,7 +9,7 @@ import { observer } from 'mobx-react';
import Avatar from 'components/Avatar/Avatar';
import Text from 'components/Text/Text';
import UserWarning from 'containers/UserWarningModal/UserWarning';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { getTzOffsetString } from 'models/timezone/timezone.helpers';
import { User } from 'models/user/user.types';
import { UserActions } from 'utils/authorization';
@ -125,7 +125,7 @@ const EscalationVariants = observer(
)}
<div className={cx('assign-responders-button')}>
<ButtonGroup>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<ToolbarButton
icon="users-alt"
variant={variant}
@ -135,8 +135,8 @@ const EscalationVariants = observer(
>
Add responders
</ToolbarButton>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<ToolbarButton
isOpen={false}
narrow
@ -145,7 +145,7 @@ const EscalationVariants = observer(
setShowEscalationVariants(true);
}}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</ButtonGroup>
</div>
{showEscalationVariants && (

View file

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import ReactDOM from 'react-dom';
import GSelect from 'containers/GSelect/GSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { GrafanaTeam } from 'models/grafana_team/grafana_team.types';
import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { useStore } from 'state/useStore';
@ -44,11 +44,11 @@ const GrafanaTeamSelect = observer(() => {
</Tooltip>
</span>
</Label>
<WithPermissionControl userAction={UserActions.TeamsWrite}>
<WithPermissionControlTooltip userAction={UserActions.TeamsWrite}>
<a href="/org/teams" className={cx('teamSelectLink')}>
Edit teams
</a>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
<GSelect
modelName="grafanaTeamStore"

View file

@ -7,7 +7,7 @@ import { observer } from 'mobx-react';
import Emoji from 'react-emoji-render';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { HeartGreenIcon, HeartRedIcon } from 'icons';
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
import { SelectOption } from 'state/types';
@ -90,7 +90,7 @@ const HeartbeatForm = observer(({ alertReceveChannelId, onUpdate }: HeartBeatMod
</p>
<p>
<span>OnCall will issue an incident if no alert is received every</span>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Select
className={cx('select', 'timeout')}
onChange={handleTimeoutChange}
@ -101,7 +101,7 @@ const HeartbeatForm = observer(({ alertReceveChannelId, onUpdate }: HeartBeatMod
label: timeoutOption.display_name,
}))}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</p>
{heartbeat && (
<p>
@ -125,11 +125,11 @@ const HeartbeatForm = observer(({ alertReceveChannelId, onUpdate }: HeartBeatMod
</p>
)}
<HorizontalGroup className={cx('buttons')}>
<WithPermissionControl key="ok" userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip key="ok" userAction={UserActions.IntegrationsWrite}>
<Button variant="primary" onClick={handleOkClick}>
{heartbeat ? 'Save' : 'Create'}
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
);

View file

@ -7,7 +7,7 @@ import { get } from 'lodash-es';
import Block from 'components/GBlock/Block';
import Text from 'components/Text/Text';
import GSelect from 'containers/GSelect/GSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
import { Alert as AlertType } from 'models/alertgroup/alertgroup.types';
import { Team } from 'models/team/team.types';
@ -149,7 +149,7 @@ const Autoresolve = ({ alertReceiveChannelId, onSwitchToTemplate, alertGroupId }
</div>
</Label>
<div className={cx('team-select')}>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Select
className={cx('team-select')}
//@ts-ignore
@ -162,7 +162,7 @@ const Autoresolve = ({ alertReceiveChannelId, onSwitchToTemplate, alertGroupId }
{ value: 'false', label: 'Resolve manually' },
]}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
{autoresolveSelected && (
<>

View file

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import GForm from 'components/GForm/GForm';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
import { MaintenanceType } from 'models/maintenance/maintenance.types';
import { useStore } from 'state/useStore';
@ -65,11 +65,11 @@ const MaintenanceForm = observer((props: MaintenanceFormProps) => {
<div className={cx('content')}>
<VerticalGroup>
<GForm form={form} data={initialData} onSubmit={handleSubmit} />
<WithPermissionControl userAction={UserActions.MaintenanceWrite}>
<WithPermissionControlTooltip userAction={UserActions.MaintenanceWrite}>
<Button form={form.name} type="submit">
Start
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</VerticalGroup>
</div>
</Drawer>

View file

@ -8,10 +8,11 @@ import qrCodeImage from 'assets/img/qr-code.png';
import Block from 'components/GBlock/Block';
import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import { WithPermissionControlDisplay } from 'containers/WithPermissionControl/WithPermissionControlDisplay';
import { User } from 'models/user/user.types';
import { AppFeature } from 'state/features';
import { useStore } from 'state/useStore';
import { isUserActionAllowed, UserActions } from 'utils/authorization';
import { UserActions } from 'utils/authorization';
import { GRAFANA_LICENSE_OSS } from 'utils/consts';
import styles from './MobileAppConnection.module.scss';
@ -41,18 +42,17 @@ const MobileAppConnection = observer(({ userPk }: Props) => {
return (
<VerticalGroup spacing="lg">
<Text type="secondary">Please connect Cloud OnCall to use the mobile app</Text>
{isUserActionAllowed(UserActions.OtherSettingsWrite) ? (
<WithPermissionControlDisplay
userAction={UserActions.OtherSettingsWrite}
message="You do not have permission to perform this action. Ask an admin to connect Cloud OnCall or upgrade your
permissions."
>
<PluginLink query={{ page: 'cloud' }}>
<Button variant="secondary" icon="external-link-alt">
Connect Cloud OnCall
</Button>
</PluginLink>
) : (
<Text type="secondary">
You do not have permission to perform this action. Ask an admin to connect Cloud OnCall or upgrade your
permissions.
</Text>
)}
</WithPermissionControlDisplay>
</VerticalGroup>
);
}

View file

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import GForm from 'components/GForm/GForm';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { OutgoingWebhook } from 'models/outgoing_webhook/outgoing_webhook.types';
import { useStore } from 'state/useStore';
import { UserActions } from 'utils/authorization';
@ -56,11 +56,11 @@ const OutgoingWebhookForm = observer((props: OutgoingWebhookFormProps) => {
>
<div className={cx('content')} data-testid="test__outgoingWebhookEditForm">
<GForm form={form} data={data} onSubmit={handleSubmit} />
<WithPermissionControl userAction={UserActions.OutgoingWebhooksWrite}>
<WithPermissionControlTooltip userAction={UserActions.OutgoingWebhooksWrite}>
<Button form={form.name} type="submit">
{id === 'new' ? 'Create' : 'Update'} Webhook
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
</Drawer>
);

View file

@ -9,7 +9,7 @@ import NotificationPolicy from 'components/Policy/NotificationPolicy';
import SortableList from 'components/SortableList/SortableList';
import Text from 'components/Text/Text';
import Timeline from 'components/Timeline/Timeline';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { NotificationPolicyType } from 'models/notification_policy';
import { User as UserType } from 'models/user/user.types';
import { AppFeature } from 'state/features';
@ -154,11 +154,11 @@ const PersonalNotificationSettings = observer((props: PersonalNotificationSettin
))}
<Timeline.Item number={notificationPolicies.length + 1} color={getColor(notificationPolicies.length)}>
<div className={cx('step')}>
<WithPermissionControl userAction={userAction}>
<WithPermissionControlTooltip userAction={userAction}>
<Button icon="plus" variant="secondary" fill="text" onClick={getAddNotificationPolicyHandler()}>
Add Notification Step
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
</Timeline.Item>
</SortableList>

View file

@ -11,7 +11,7 @@ import Text from 'components/Text/Text';
import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
import Rotation from 'containers/Rotation/Rotation';
import RotationForm from 'containers/RotationForm/RotationForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { getColor, getFromString } from 'models/schedule/schedule.helpers';
import { Layer, Schedule, ScheduleType, Shift } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
@ -112,11 +112,11 @@ class Rotations extends Component<RotationsProps, RotationsState> {
</div>
</Tooltip>
) : (
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip userAction={UserActions.SchedulesWrite}>
<Button variant="primary" icon="plus" disabled>
Add rotation
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)
) : (
<ValuePicker

View file

@ -10,7 +10,7 @@ import Text from 'components/Text/Text';
import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
import Rotation from 'containers/Rotation/Rotation';
import ScheduleOverrideForm from 'containers/RotationForm/ScheduleOverrideForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { getOverrideColor, getOverridesFromStore } from 'models/schedule/schedule.helpers';
import { Schedule, ScheduleType, Shift, ShiftEvents } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
@ -94,11 +94,11 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
</div>
</Tooltip>
) : (
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip userAction={UserActions.SchedulesWrite}>
<Button disabled={disabled} icon="plus" onClick={this.handleAddOverride} variant="secondary">
Add override
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
</HorizontalGroup>
</div>

View file

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import GForm from 'components/GForm/GForm';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Schedule, ScheduleType } from 'models/schedule/schedule.types';
import { useStore } from 'state/useStore';
import { UserActions } from 'utils/authorization';
@ -77,11 +77,11 @@ const ScheduleForm = observer((props: ScheduleFormProps) => {
<div className={cx('content')}>
<VerticalGroup>
<GForm form={formConfig} data={data} onSubmit={handleSubmit} />
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip userAction={UserActions.SchedulesWrite}>
<Button form={formConfig.name} type="submit">
{id === 'new' ? 'Create' : 'Update'} Schedule
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</VerticalGroup>
</div>
</Drawer>

View file

@ -7,7 +7,7 @@ import CopyToClipboard from 'react-copy-to-clipboard';
import Block from 'components/GBlock/Block';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { useStore } from 'state/useStore';
import { openNotification } from 'utils';
import { UserActions } from 'utils/authorization';
@ -43,11 +43,11 @@ const TelegramIntegrationButton = observer((props: TelegramIntegrationProps) =>
return (
<>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button size={size} variant="primary" icon="plus" disabled={disabled} onClick={onInstallModalCallback}>
Add Telegram channel
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
{showModal && <TelegramModal onHide={onInstallModalHideCallback} onUpdate={onModalUpdateCallback} />}
</>
);

View file

@ -5,7 +5,7 @@ import cn from 'classnames/bind';
import CopyToClipboard from 'react-copy-to-clipboard';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { User } from 'models/user/user.types';
import { useStore } from 'state/useStore';
import { openNotification } from 'utils';
@ -88,7 +88,7 @@ const ICalConnector = (props: ICalConnectorProps) => {
<Text type="secondary">
In case you lost your iCal link you can revoke it and generate a new one.
</Text>
<WithPermissionControl userAction={UserActions.UserSettingsWrite}>
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
<Button
icon="trash-alt"
onClick={handleRevokeiCalLink}
@ -98,16 +98,16 @@ const ICalConnector = (props: ICalConnectorProps) => {
>
Revoke iCal link
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</>
)}
</>
) : (
<WithPermissionControl userAction={UserActions.UserSettingsWrite}>
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
<Button icon="plus" onClick={handleCreateiCalLink} className={cx('iCal-button')} variant="secondary">
Create iCal link
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
</>
)}

View file

@ -5,12 +5,13 @@ import { observer } from 'mobx-react';
import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import { WithPermissionControlDisplay } from 'containers/WithPermissionControl/WithPermissionControlDisplay';
import { User } from 'models/user/user.types';
import { AppFeature } from 'state/features';
import { WithStoreProps } from 'state/types';
import { useStore } from 'state/useStore';
import { withMobXProviderContext } from 'state/withStore';
import { isUserActionAllowed, UserActions } from 'utils/authorization';
import { UserActions } from 'utils/authorization';
interface CloudPhoneSettingsProps extends WithStoreProps {
userPk?: User['pk'];
@ -119,7 +120,11 @@ const CloudPhoneSettings = observer((props: CloudPhoneSettingsProps) => {
return (
<>
{isUserActionAllowed(UserActions.OtherSettingsWrite) ? (
<WithPermissionControlDisplay
userAction={UserActions.OtherSettingsWrite}
title="OnCall uses Grafana Cloud for SMS and phone call notifications"
message="You do not have permission to perform this action. Ask an admin to upgrade your permissions."
>
<VerticalGroup spacing="lg">
<HorizontalGroup justify="space-between">
<Text.Title level={3}>OnCall uses Grafana Cloud for SMS and phone call notifications</Text.Title>
@ -135,12 +140,7 @@ const CloudPhoneSettings = observer((props: CloudPhoneSettingsProps) => {
</HorizontalGroup>
{!syncing ? <UserCloudStatus /> : <LoadingPlaceholder text="Loading..." />}
</VerticalGroup>
) : (
<VerticalGroup spacing="lg">
<Text.Title level={3}>OnCall uses Grafana Cloud for SMS and phone call notifications</Text.Title>
<Text>You do not have permission to perform this action. Ask an admin to upgrade your permissions.</Text>
</VerticalGroup>
)}
</WithPermissionControlDisplay>
</>
);
});

View file

@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { User } from 'models/user/user.types';
import { rootStore } from 'state';
import { AppFeature } from 'state/features';
@ -180,7 +180,7 @@ const PhoneVerification = observer((props: PhoneVerificationProps) => {
invalid={showPhoneInputError}
error={showPhoneInputError ? 'Enter a valid phone number' : null}
>
<WithPermissionControl userAction={action}>
<WithPermissionControlTooltip userAction={action}>
<Input
autoFocus
id="phone"
@ -192,7 +192,7 @@ const PhoneVerification = observer((props: PhoneVerificationProps) => {
value={phone}
onChange={onChangePhoneCallback}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Field>
{!user.verified_phone_number && (
<Input
@ -301,15 +301,15 @@ function PhoneVerificationButtonsGroup({
return (
<HorizontalGroup>
{showVerifyOrSendCodeButton && (
<WithPermissionControl userAction={action}>
<WithPermissionControlTooltip userAction={action}>
<Button variant="primary" onClick={onSubmitCallback} disabled={isButtonDisabled}>
{isCodeSent ? 'Verify' : 'Send Code'}
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{showForgetNumber && (
<WithPermissionControl userAction={action}>
<WithPermissionControlTooltip userAction={action}>
<Button
disabled={(!user.verified_phone_number && !user.unverified_phone_number) || isTestCallInProgress}
onClick={onShowForgetScreen}
@ -317,19 +317,19 @@ function PhoneVerificationButtonsGroup({
>
{'Forget Phone Number'}
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{user.verified_phone_number && (
<>
<WithPermissionControl userAction={action}>
<WithPermissionControlTooltip userAction={action}>
<Button
disabled={!user?.verified_phone_number || !isTwilioConfigured || isTestCallInProgress}
onClick={handleMakeTestCallClick}
>
{isTestCallInProgress ? 'Making Test Call...' : 'Make Test Call'}
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
<Tooltip content={'Click "Make Test Call" to save a phone number and add it to DnD exceptions.'}>
<Icon
name="info-circle"

View file

@ -8,10 +8,12 @@ import CopyToClipboard from 'react-copy-to-clipboard';
import Block from 'components/GBlock/Block';
import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import { WithPermissionControlDisplay } from 'containers/WithPermissionControl/WithPermissionControlDisplay';
import { TelegramColorIcon } from 'icons';
import { AppFeature } from 'state/features';
import { useStore } from 'state/useStore';
import { openNotification } from 'utils';
import { UserActions } from 'utils/authorization';
import { DOCS_TELEGRAM_SETUP } from 'utils/consts';
import styles from './TelegramInfo.module.css';
@ -37,7 +39,10 @@ const TelegramInfo = observer((_props: TelegramInfoProps) => {
}, []);
return (
<>
<WithPermissionControlDisplay
userAction={UserActions.OtherSettingsWrite}
message="You do not have permission to perform this action. Ask an admin to upgrade your permissions."
>
{telegramConfigured || !store.hasFeature(AppFeature.LiveSettings) ? (
<VerticalGroup>
<Text.Title level={5}>Manual connection</Text.Title>
@ -96,7 +101,7 @@ const TelegramInfo = observer((_props: TelegramInfoProps) => {
)}
</VerticalGroup>
)}
</>
</WithPermissionControlDisplay>
);
});

View file

@ -0,0 +1,28 @@
import React, { ReactElement } from 'react';
import { VerticalGroup } from '@grafana/ui';
import Text from 'components/Text/Text';
import { isUserActionAllowed, UserAction } from 'utils/authorization';
interface WithPermissionControlDisplayProps {
userAction: UserAction;
children: ReactElement;
message: string;
title?: string;
}
export const WithPermissionControlDisplay: React.FC<WithPermissionControlDisplayProps> = (props) => {
const { userAction, children, title, message } = props;
const hasPermission = isUserActionAllowed(userAction);
return hasPermission ? (
children
) : (
<VerticalGroup spacing="lg">
{title && <Text.Title level={3}>{title}</Text.Title>}
<Text>{message}</Text>
</VerticalGroup>
);
};

View file

@ -6,18 +6,18 @@ import { observer } from 'mobx-react';
import { isUserActionAllowed, UserAction } from 'utils/authorization';
import styles from './WithPermissionControl.module.css';
import styles from './WithPermissionControlTooltip.module.css';
const cx = cn.bind(styles);
interface WithPermissionControlProps {
interface WithPermissionControlTooltipProps {
userAction: UserAction;
children: ReactElement;
disableByPaywall?: boolean;
className?: string;
}
export const WithPermissionControl = observer((props: WithPermissionControlProps) => {
export const WithPermissionControlTooltip = observer((props: WithPermissionControlTooltipProps) => {
const { userAction, children, className } = props;
const disabledByPermissions = !isUserActionAllowed(userAction);

View file

@ -1,30 +0,0 @@
import React, { ReactElement, useMemo } from 'react';
import { Tooltip } from '@grafana/ui';
import { observer } from 'mobx-react';
import { isUserActionAllowed, UserAction } from 'utils/authorization';
interface WithPermissionControlProps {
userAction: UserAction;
children: (disabled?: boolean) => ReactElement;
}
export const WithPermissionControl = observer((props: WithPermissionControlProps) => {
const { userAction, children } = props;
const disabled = !isUserActionAllowed(userAction);
const element = useMemo(() => children(disabled), [disabled]);
return disabled ? (
<Tooltip
content="You do not have permission to perform this action. Ask an admin to upgrade your permissions."
placement="top"
>
<span>{element}</span>
</Tooltip>
) : (
element
);
});

View file

@ -23,7 +23,7 @@ import WithConfirm from 'components/WithConfirm/WithConfirm';
import EscalationChainCard from 'containers/EscalationChainCard/EscalationChainCard';
import EscalationChainForm from 'containers/EscalationChainForm/EscalationChainForm';
import EscalationChainSteps from 'containers/EscalationChainSteps/EscalationChainSteps';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
import { PageProps, WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
@ -161,7 +161,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
{!searchResult || searchResult.length ? (
<div className={cx('escalations')}>
<div className={cx('left-column')}>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button
onClick={() => {
this.setState({ showCreateEscalationChainModal: true });
@ -171,7 +171,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
>
New Escalation Chain
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
<div className={cx('escalations-list')}>
{searchResult ? (
<GList
@ -196,7 +196,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No escalations found, check your filtering and current team.</Text>
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<Button
icon="plus"
variant="primary"
@ -207,7 +207,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
>
New Escalation Chain
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</VerticalGroup>
}
/>
@ -272,7 +272,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
</Text>
<div className={cx('buttons')}>
<HorizontalGroup>
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<IconButton
tooltip="Copy"
tooltipPlacement="top"
@ -284,8 +284,8 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
});
}}
/>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.EscalationChainsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.EscalationChainsWrite}>
<WithConfirm title={`Are you sure to remove "${escalationChain.name}"?`} confirmText="Remove">
<IconButton
disabled={escalationChain.number_of_integrations > 0}
@ -295,7 +295,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
name="trash-alt"
/>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
{escalationChain.number_of_integrations > 0 && (
<Tooltip content="Escalation chains linked to multiple integrations cannot be removed">
<Icon name="info-circle" />

View file

@ -8,7 +8,7 @@ import { MatchMediaTooltip } from 'components/MatchMediaTooltip/MatchMediaToolti
import PluginLink from 'components/PluginLink/PluginLink';
import Tag from 'components/Tag/Tag';
import Text from 'components/Text/Text';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { MaintenanceIntegration } from 'models/alert_receive_channel';
import { Alert as AlertType, Alert, IncidentStatus } from 'models/alertgroup/alertgroup.types';
import { User } from 'models/user/user.types';
@ -154,35 +154,35 @@ export function getActionButtons(incident: AlertType, cx: any, callbacks: { [key
const { onResolve, onUnresolve, onAcknowledge, onUnacknowledge, onSilence, onUnsilence } = callbacks;
const resolveButton = (
<WithPermissionControl key="resolve" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="resolve" userAction={UserActions.AlertGroupsWrite}>
<Button disabled={incident.loading} onClick={onResolve} variant="primary">
Resolve
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
const unacknowledgeButton = (
<WithPermissionControl key="unacknowledge" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="unacknowledge" userAction={UserActions.AlertGroupsWrite}>
<Button disabled={incident.loading} onClick={onUnacknowledge} variant="secondary">
Unacknowledge
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
const unresolveButton = (
<WithPermissionControl key="unacknowledge" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="unacknowledge" userAction={UserActions.AlertGroupsWrite}>
<Button disabled={incident.loading} onClick={onUnresolve} variant="primary">
Unresolve
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
const acknowledgeButton = (
<WithPermissionControl key="acknowledge" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="acknowledge" userAction={UserActions.AlertGroupsWrite}>
<Button disabled={incident.loading} onClick={onAcknowledge} variant="secondary">
Acknowledge
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
const buttons = [];
@ -201,11 +201,11 @@ export function getActionButtons(incident: AlertType, cx: any, callbacks: { [key
if (incident.status === IncidentStatus.Silenced) {
buttons.push(
<WithPermissionControl key="silence" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="silence" userAction={UserActions.AlertGroupsWrite}>
<Button disabled={incident.loading} variant="secondary" onClick={onUnsilence}>
Unsilence
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
}

View file

@ -39,7 +39,7 @@ import EscalationVariants from 'containers/EscalationVariants/EscalationVariants
import { prepareForEdit, prepareForUpdate } from 'containers/EscalationVariants/EscalationVariants.helpers';
import IntegrationSettings from 'containers/IntegrationSettings/IntegrationSettings';
import { IntegrationSettingsTab } from 'containers/IntegrationSettings/IntegrationSettings.types';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import {
Alert as AlertType,
Alert,
@ -260,11 +260,11 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
#{incident.root_alert_group.inside_organization_number}{' '}
{incident.root_alert_group.render_for_web.title}
</PluginLink>{' '}
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<Button variant="secondary" onClick={this.getUnattachClickHandler(incident.pk)} size="sm">
Unattach
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Text>
)}
</HorizontalGroup>
@ -764,11 +764,11 @@ function AttachedIncidentsList({
<PluginLink query={{ page: 'incident', id: incident.pk }}>
#{incident.inside_organization_number} {incident.render_for_web.title}
</PluginLink>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<Button size="sm" onClick={() => getUnattachClickHandler(incident.pk)} variant="secondary">
Unattach
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
);
})}

View file

@ -6,7 +6,7 @@ import cn from 'classnames/bind';
import Avatar from 'components/Avatar/Avatar';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Alert } from 'models/alertgroup/alertgroup.types';
import { User } from 'models/user/user.types';
import { UserActions } from 'utils/authorization';
@ -46,7 +46,7 @@ const PagedUsers = (props: PagedUsersProps) => {
<Avatar size="big" src={pagedUser.avatar} />
<Text strong>{pagedUser.username}</Text>
</HorizontalGroup>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<WithConfirm
title={`Are you sure to remove "${pagedUser.username}" from responders?`}
confirmText="Remove"
@ -57,7 +57,7 @@ const PagedUsers = (props: PagedUsersProps) => {
name="trash-alt"
/>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</li>
))}

View file

@ -18,7 +18,7 @@ import Tutorial from 'components/Tutorial/Tutorial';
import { TutorialStep } from 'components/Tutorial/Tutorial.types';
import { IncidentsFiltersType } from 'containers/IncidentsFilters/IncidentFilters.types';
import IncidentsFilters from 'containers/IncidentsFilters/IncidentsFilters';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Alert, Alert as AlertType, AlertAction } from 'models/alertgroup/alertgroup.types';
import { renderRelatedUsers } from 'pages/incident/Incident.helpers';
import { PageProps, WithStoreProps } from 'state/types';
@ -109,11 +109,11 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
<div className={cx('title')}>
<HorizontalGroup justify="space-between">
<Text.Title level={3}>Alert Groups</Text.Title>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<Button icon="plus" onClick={this.handleOnClickEscalateTo}>
Manual alert group
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
{this.renderIncidentFilters()}
@ -233,7 +233,7 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
<div className={cx('bulk-actions')}>
<HorizontalGroup>
{'resolve' in store.alertGroupStore.bulkActions && (
<WithPermissionControl key="resolve" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="resolve" userAction={UserActions.AlertGroupsWrite}>
<Button
disabled={!hasSelected}
variant="primary"
@ -241,10 +241,10 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
>
Resolve
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{'acknowledge' in store.alertGroupStore.bulkActions && (
<WithPermissionControl key="resolve" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="resolve" userAction={UserActions.AlertGroupsWrite}>
<Button
disabled={!hasSelected}
variant="secondary"
@ -252,10 +252,10 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
>
Acknowledge
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{'silence' in store.alertGroupStore.bulkActions && (
<WithPermissionControl key="restart" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="restart" userAction={UserActions.AlertGroupsWrite}>
<Button
disabled={!hasSelected}
variant="secondary"
@ -263,15 +263,15 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
>
Restart
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
{'restart' in store.alertGroupStore.bulkActions && (
<WithPermissionControl key="silence" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="silence" userAction={UserActions.AlertGroupsWrite}>
<SilenceButtonCascader
disabled={!hasSelected}
onSelect={(ev) => this.getBulkActionClickHandler('silence', ev)}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
)}
<Text type="secondary">
{hasSelected

View file

@ -6,7 +6,7 @@ import cn from 'classnames/bind';
import Tag from 'components/Tag/Tag';
import Text from 'components/Text/Text';
import { WithContextMenu } from 'components/WithContextMenu/WithContextMenu';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Alert, AlertAction, IncidentStatus } from 'models/alertgroup/alertgroup.types';
import styles from 'pages/incidents/parts/IncidentDropdown.module.scss';
import { UserActions } from 'utils/authorization';
@ -92,7 +92,7 @@ export const IncidentDropdown: FC<{
forceIsOpen={forcedOpenAction === AlertAction.Resolve}
renderMenuItems={() => (
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--firing')}
onClick={(e) => onClickFn(e, AlertAction.Resolve, onUnresolve, IncidentStatus.Firing)}
@ -104,7 +104,7 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
)}
>
@ -119,7 +119,7 @@ export const IncidentDropdown: FC<{
forceIsOpen={forcedOpenAction === AlertAction.Acknowledge}
renderMenuItems={() => (
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--unacknowledge')}
onClick={(e) => onClickFn(e, AlertAction.Acknowledge, onUnacknowledge, IncidentStatus.Firing)}
@ -131,8 +131,8 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--resolve')}
onClick={(e) => onClickFn(e, AlertAction.Acknowledge, onResolve, IncidentStatus.Resolved)}
@ -144,7 +144,7 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
)}
>
@ -159,7 +159,7 @@ export const IncidentDropdown: FC<{
forceIsOpen={forcedOpenAction === AlertAction.unResolve}
renderMenuItems={() => (
<div className={cx('incident__options', { 'u-disabled': isLoading })}>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--acknowledge')}
onClick={(e) => onClickFn(e, AlertAction.unResolve, onAcknowledge, IncidentStatus.Acknowledged)}
@ -171,8 +171,8 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--resolve')}
onClick={(e) => onClickFn(e, AlertAction.unResolve, onResolve, IncidentStatus.Resolved)}
@ -184,7 +184,7 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
</WithPermissionControlTooltip>
<div className={cx('incident__option-item')}>
<SilenceSelect
@ -217,7 +217,7 @@ export const IncidentDropdown: FC<{
forceIsOpen={forcedOpenAction === AlertAction.Silence}
renderMenuItems={() => (
<div className={cx('incident_options', { 'u-disabled': isLoading })}>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item')}
onClick={(e) => onClickFn(e, AlertAction.Silence, onUnsilence, IncidentStatus.Firing)}
@ -229,8 +229,8 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--acknowledge')}
onClick={(e) => onClickFn(e, AlertAction.Silence, onAcknowledge, IncidentStatus.Acknowledged)}
@ -242,8 +242,8 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.AlertGroupsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<div
className={cx('incident__option-item', 'incident__option-item--resolve')}
onClick={(e) => onClickFn(e, AlertAction.Silence, onAcknowledge, IncidentStatus.Resolved)}
@ -255,7 +255,7 @@ export const IncidentDropdown: FC<{
</span>
)}
</div>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
)}
>

View file

@ -3,7 +3,7 @@ import React from 'react';
import { ButtonCascader, ComponentSize } from '@grafana/ui';
import { observer } from 'mobx-react';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { SelectOption } from 'state/types';
import { useStore } from 'state/useStore';
import { UserActions } from 'utils/authorization';
@ -23,7 +23,7 @@ export const SilenceButtonCascader = observer((props: SilenceButtonCascaderProps
const silenceOptions = alertGroupStore.silenceOptions || [];
return (
<WithPermissionControl key="silence" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="silence" userAction={UserActions.AlertGroupsWrite}>
<ButtonCascader
variant="secondary"
className={className}
@ -35,7 +35,7 @@ export const SilenceButtonCascader = observer((props: SilenceButtonCascaderProps
>
Silence
</ButtonCascader>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
function getOptions() {

View file

@ -3,7 +3,7 @@ import React from 'react';
import { Select } from '@grafana/ui';
import { observer } from 'mobx-react';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { SelectOption } from 'state/types';
import { useStore } from 'state/useStore';
import { UserActions } from 'utils/authorization';
@ -24,7 +24,7 @@ export const SilenceSelect = observer((props: SilenceSelectProps) => {
const silenceOptions = alertGroupStore.silenceOptions || [];
return (
<WithPermissionControl key="silence" userAction={UserActions.AlertGroupsWrite}>
<WithPermissionControlTooltip key="silence" userAction={UserActions.AlertGroupsWrite}>
<Select
menuShouldPortal
placeholder={placeholder}
@ -32,7 +32,7 @@ export const SilenceSelect = observer((props: SilenceSelectProps) => {
onChange={({ value }) => onSelect(Number(value))}
options={getOptions()}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
function getOptions() {

View file

@ -21,7 +21,7 @@ import AlertRules from 'containers/AlertRules/AlertRules';
import CreateAlertReceiveChannelContainer from 'containers/CreateAlertReceiveChannelContainer/CreateAlertReceiveChannelContainer';
import IntegrationSettings from 'containers/IntegrationSettings/IntegrationSettings';
import { IntegrationSettingsTab } from 'containers/IntegrationSettings/IntegrationSettings.types';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { AlertReceiveChannel } from 'models/alert_receive_channel';
import { AlertReceiveChannelOption } from 'models/alert_receive_channel/alert_receive_channel.types';
import { PageProps, WithStoreProps } from 'state/types';
@ -161,7 +161,7 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
{searchResult?.length ? (
<div className={cx('integrations')}>
<div className={cx('integrationsList')}>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button
onClick={() => {
this.setState({ showCreateIntegrationModal: true });
@ -171,7 +171,7 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
>
New integration for receiving alerts
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
<div className={cx('alert-receive-channels-list')}>
<GList
autoScroll
@ -215,7 +215,7 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
title={
<VerticalGroup align="center" spacing="lg">
<Text type="secondary">No integrations found. Review your filter and team settings.</Text>
<WithPermissionControl userAction={UserActions.IntegrationsWrite}>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<Button
icon="plus"
variant="primary"
@ -226,7 +226,7 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
>
New integration for receiving alerts
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</VerticalGroup>
}
/>

View file

@ -11,7 +11,7 @@ import GTable from 'components/GTable/GTable';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import MaintenanceForm from 'containers/MaintenanceForm/MaintenanceForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { getAlertReceiveChannelDisplayName } from 'models/alert_receive_channel/alert_receive_channel.helpers';
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
import { Maintenance, MaintenanceMode, MaintenanceType } from 'models/maintenance/maintenance.types';
@ -131,7 +131,7 @@ class MaintenancePage extends React.Component<MaintenancePageProps, MaintenanceP
</Text>
</VerticalGroup>
</div>
<WithPermissionControl userAction={UserActions.MaintenanceWrite}>
<WithPermissionControlTooltip userAction={UserActions.MaintenanceWrite}>
<Button
onClick={() => {
this.setState({ maintenanceData: {} });
@ -141,7 +141,7 @@ class MaintenancePage extends React.Component<MaintenancePageProps, MaintenanceP
>
Create
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
)}
rowKey="id"
@ -185,13 +185,13 @@ class MaintenancePage extends React.Component<MaintenancePageProps, MaintenanceP
renderActionButtons = (maintenance: Maintenance) => {
return (
<div className={cx('buttons')}>
<WithPermissionControl userAction={UserActions.MaintenanceWrite}>
<WithPermissionControlTooltip userAction={UserActions.MaintenanceWrite}>
<WithConfirm title="Are you sure to stop?" confirmText="Stop">
<Button variant="destructive" fill="text" onClick={this.getStopMaintenanceHandler(maintenance)}>
Stop
</Button>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
);
};

View file

@ -16,7 +16,7 @@ import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import OutgoingWebhookForm from 'containers/OutgoingWebhookForm/OutgoingWebhookForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { ActionDTO } from 'models/action';
import { OutgoingWebhook } from 'models/outgoing_webhook/outgoing_webhook.types';
import { PageProps, WithStoreProps } from 'state/types';
@ -133,11 +133,11 @@ class OutgoingWebhooks extends React.Component<OutgoingWebhooksProps, OutgoingWe
query={{ page: 'outgoing_webhooks', id: 'new' }}
disabled={!isUserActionAllowed(UserActions.OutgoingWebhooksWrite)}
>
<WithPermissionControl userAction={UserActions.OutgoingWebhooksWrite}>
<WithPermissionControlTooltip userAction={UserActions.OutgoingWebhooksWrite}>
<Button variant="primary" icon="plus">
Create
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</PluginLink>
</div>
</div>
@ -163,18 +163,18 @@ class OutgoingWebhooks extends React.Component<OutgoingWebhooksProps, OutgoingWe
renderActionButtons = (record: ActionDTO) => {
return (
<HorizontalGroup justify="flex-end">
<WithPermissionControl key={'edit_action'} userAction={UserActions.OutgoingWebhooksWrite}>
<WithPermissionControlTooltip key={'edit_action'} userAction={UserActions.OutgoingWebhooksWrite}>
<Button onClick={this.getEditClickHandler(record.id)} fill="text">
Edit
</Button>
</WithPermissionControl>
<WithPermissionControl key={'delete_action'} userAction={UserActions.OutgoingWebhooksWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip key={'delete_action'} userAction={UserActions.OutgoingWebhooksWrite}>
<WithConfirm>
<Button onClick={this.getDeleteClickHandler(record.id)} fill="text" variant="destructive">
Delete
</Button>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
);
};

View file

@ -11,7 +11,6 @@ import SettingsPage from 'pages/settings/SettingsPage';
import ChatOpsPage from 'pages/settings/tabs/ChatOps/ChatOps';
import CloudPage from 'pages/settings/tabs/Cloud/CloudPage';
import LiveSettingsPage from 'pages/settings/tabs/LiveSettings/LiveSettingsPage';
import Test from 'pages/test/Test';
import UsersPage from 'pages/users/Users';
export interface NavRoute {
@ -76,10 +75,6 @@ export const routes: { [id: string]: NavRoute } = [
component: CloudPage,
id: 'cloud',
},
{
component: Test,
id: 'test',
},
].reduce((prev, current) => {
prev[current.id] = {
id: current.id,

View file

@ -22,7 +22,7 @@ import UserTimezoneSelect from 'components/UserTimezoneSelect/UserTimezoneSelect
import WithConfirm from 'components/WithConfirm/WithConfirm';
import ScheduleFinal from 'containers/Rotations/ScheduleFinal';
import ScheduleForm from 'containers/ScheduleForm/ScheduleForm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { Schedule, ScheduleType } from 'models/schedule/schedule.types';
import { getSlackChannelName } from 'models/slack_channel/slack_channel.helpers';
import { Timezone } from 'models/timezone/timezone.types';
@ -159,11 +159,11 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
onChange={this.handleTimezoneChange}
/>
)}
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip userAction={UserActions.SchedulesWrite}>
<Button variant="primary" onClick={this.handleCreateScheduleClick}>
+ New schedule
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</div>
</div>
<Table
@ -376,14 +376,14 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
/* Wrapper div for onClick event to prevent expanding schedule view on delete/edit click */
<div onClick={(event: SyntheticEvent) => event.stopPropagation()}>
<HorizontalGroup>
<WithPermissionControl key="edit" userAction={UserActions.SchedulesWrite}>
<WithPermissionControlTooltip key="edit" userAction={UserActions.SchedulesWrite}>
<IconButton tooltip="Settings" name="cog" onClick={this.getEditScheduleClickHandler(item.id)} />
</WithPermissionControl>
<WithPermissionControl key="edit" userAction={UserActions.SchedulesWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip key="edit" userAction={UserActions.SchedulesWrite}>
<WithConfirm>
<IconButton tooltip="Delete" name="trash-alt" onClick={this.getDeleteScheduleClickHandler(item.id)} />
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
);

View file

@ -10,7 +10,7 @@ import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import GSelect from 'containers/GSelect/GSelect';
import RemoteSelect from 'containers/RemoteSelect/RemoteSelect';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { SlackNewIcon } from 'icons';
import { PRIVATE_CHANNEL_NAME } from 'models/slack_channel/slack_channel.config';
import { SlackChannel } from 'models/slack_channel/slack_channel.types';
@ -109,7 +109,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
</div>
</Field>
<Field label="Default channel for Slack notifications">
<WithPermissionControl userAction={UserActions.ChatOpsUpdateSettings}>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
<GSelect
showSearch
className={cx('select', 'control')}
@ -121,10 +121,10 @@ class SlackSettings extends Component<SlackProps, SlackState> {
onChange={this.handleSlackChannelChange}
nullItemName={PRIVATE_CHANNEL_NAME}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Field>
</HorizontalGroup>
<WithPermissionControl userAction={UserActions.ChatOpsUpdateSettings}>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
<WithConfirm
title="Remove Slack Integration for all of OnCall"
description={
@ -152,7 +152,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
Disconnect
</Button>
</WithConfirm>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
<div className={cx('slack-settings')}>
@ -161,7 +161,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
</Text.Title>
<Field label="Timeout for acknowledged alerts">
<HorizontalGroup>
<WithPermissionControl userAction={UserActions.ChatOpsWrite}>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsWrite}>
<RemoteSelect
className={cx('select')}
showSearch={false}
@ -169,8 +169,8 @@ class SlackSettings extends Component<SlackProps, SlackState> {
value={slackStore.slackSettings?.acknowledge_remind_timeout}
onChange={this.getSlackSettingsChangeHandler('acknowledge_remind_timeout')}
/>
</WithPermissionControl>
<WithPermissionControl userAction={UserActions.ChatOpsWrite}>
</WithPermissionControlTooltip>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsWrite}>
<RemoteSelect
className={cx('select')}
disabled={slackStore.slackSettings?.acknowledge_remind_timeout === 0}
@ -179,7 +179,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
value={slackStore.slackSettings?.unacknowledge_timeout}
onChange={this.getSlackSettingsChangeHandler('unacknowledge_timeout')}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</Field>
</div>
@ -195,7 +195,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
renderSlackChannels = () => {
const { store } = this.props;
return (
<WithPermissionControl userAction={UserActions.ChatOpsUpdateSettings}>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
<GSelect
showSearch
className={cx('select', 'control')}
@ -207,7 +207,7 @@ class SlackSettings extends Component<SlackProps, SlackState> {
onChange={this.handleSlackChannelChange}
nullItemName={PRIVATE_CHANNEL_NAME}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
);
};

View file

@ -9,7 +9,7 @@ import { Lambda } from 'mobx/lib/internal';
import GTable from 'components/GTable/GTable';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { GlobalSetting } from 'models/global_setting/global_setting.types';
import { WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
@ -119,7 +119,7 @@ class LiveSettings extends React.Component<LiveSettingsProps, LiveSettingsState>
<Text.Title level={3}>Env Variables</Text.Title>
</HorizontalGroup>
<HorizontalGroup justify="flex-end">
<WithPermissionControl userAction={UserActions.OtherSettingsWrite}>
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
<Button
variant="primary"
icon={hideValues ? 'eye' : 'eye-slash'}
@ -127,7 +127,7 @@ class LiveSettings extends React.Component<LiveSettingsProps, LiveSettingsState>
>
{hideValues ? 'Show values' : 'Hide values'}
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</HorizontalGroup>
</div>
)}

View file

@ -7,7 +7,7 @@ import LegacyNavHeading from 'navbar/LegacyNavHeading';
import Text from 'components/Text/Text';
import ApiTokenSettings from 'containers/ApiTokenSettings/ApiTokenSettings';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
import { UserActions } from 'utils/authorization';
@ -53,7 +53,7 @@ class SettingsPage extends React.Component<SettingsPageProps, SettingsPageState>
label="Require a resolution note when resolving Alert Groups"
description={`Once user clicks "Resolve" for an Alert Group, they will be required to fill in a resolution note about the Alert Group`}
>
<WithPermissionControl userAction={UserActions.OtherSettingsWrite}>
<WithPermissionControlTooltip userAction={UserActions.OtherSettingsWrite}>
<Switch
value={teamStore.currentTeam?.is_resolution_note_required}
onChange={(event) => {
@ -62,7 +62,7 @@ class SettingsPage extends React.Component<SettingsPageProps, SettingsPageState>
});
}}
/>
</WithPermissionControl>
</WithPermissionControlTooltip>
</Field>
</div>
<Text.Title level={3} className={cx('title')}>

View file

@ -1,3 +0,0 @@
.select {
width: 400px;
}

View file

@ -1,28 +0,0 @@
import React from 'react';
import { Button } from '@grafana/ui';
import cn from 'classnames/bind';
import { observer } from 'mobx-react';
import { WithPermissionControl } from 'containers/WithPermissionControl2/WithPermissionControl';
import { withMobXProviderContext } from 'state/withStore';
import { UserActions } from 'utils/authorization';
import styles from './Test.module.css';
const cx = cn.bind(styles);
@observer
class Test extends React.Component<any, any> {
render() {
return (
<div className={cx('root')}>
<WithPermissionControl userAction={UserActions.SchedulesWrite}>
{(disabled) => <Button disabled={disabled}>Click me!</Button>}
</WithPermissionControl>
</div>
);
}
}
export default withMobXProviderContext(Test);

View file

@ -18,7 +18,7 @@ import PluginLink from 'components/PluginLink/PluginLink';
import Text from 'components/Text/Text';
import UsersFilters from 'components/UsersFilters/UsersFilters';
import UserSettings from 'containers/UserSettings/UserSettings';
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
import { User as UserType } from 'models/user/user.types';
import { PageProps, WithStoreProps } from 'state/types';
import { withMobXProviderContext } from 'state/withStore';
@ -298,7 +298,7 @@ class Users extends React.Component<UsersProps, UsersState> {
return (
<VerticalGroup justify="center">
<PluginLink query={{ page: 'users', id: user.pk }} disabled={!isUserActionAllowed(action)}>
<WithPermissionControl userAction={action}>
<WithPermissionControlTooltip userAction={action}>
<Button
className={cx({
'TEST-edit-my-own-settings-button': isCurrent,
@ -307,7 +307,7 @@ class Users extends React.Component<UsersProps, UsersState> {
>
Edit
</Button>
</WithPermissionControl>
</WithPermissionControlTooltip>
</PluginLink>
</VerticalGroup>
);

View file

@ -34,7 +34,6 @@ import SettingsPage from 'pages/settings/SettingsPage';
import ChatOps from 'pages/settings/tabs/ChatOps/ChatOps';
import CloudPage from 'pages/settings/tabs/Cloud/CloudPage';
import LiveSettings from 'pages/settings/tabs/LiveSettings/LiveSettingsPage';
import Test from 'pages/test/Test';
import Users from 'pages/users/Users';
import 'interceptors';
import { rootStore } from 'state';
@ -180,9 +179,6 @@ export const Root = observer((props: AppRootProps) => {
<Route path={getRoutesForPage('cloud')} exact>
<CloudPage />
</Route>
<Route path={getRoutesForPage('test')} exact>
<Test />
</Route>
<Route path="*">
<NoMatch />
</Route>