diff --git a/grafana-plugin/src/containers/TelegramIntegrationButton/TelegramIntegrationButton.tsx b/grafana-plugin/src/containers/TelegramIntegrationButton/TelegramIntegrationButton.tsx
index 1d1494cb6c..6c993f9947 100644
--- a/grafana-plugin/src/containers/TelegramIntegrationButton/TelegramIntegrationButton.tsx
+++ b/grafana-plugin/src/containers/TelegramIntegrationButton/TelegramIntegrationButton.tsx
@@ -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 (
<>
-
+
Add Telegram channel
-
+
{showModal && }
>
);
diff --git a/grafana-plugin/src/containers/UserSettings/parts/connectors/ICalConnector.tsx b/grafana-plugin/src/containers/UserSettings/parts/connectors/ICalConnector.tsx
index d9fe2d3add..db7c46df78 100644
--- a/grafana-plugin/src/containers/UserSettings/parts/connectors/ICalConnector.tsx
+++ b/grafana-plugin/src/containers/UserSettings/parts/connectors/ICalConnector.tsx
@@ -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) => {
In case you lost your iCal link you can revoke it and generate a new one.
-
+ {
>
Revoke iCal link
-
+
>
)}
>
) : (
-
+
Create iCal link
-
+
)}
>
)}
diff --git a/grafana-plugin/src/containers/UserSettings/parts/tabs/CloudPhoneSettings/CloudPhoneSettings.tsx b/grafana-plugin/src/containers/UserSettings/parts/tabs/CloudPhoneSettings/CloudPhoneSettings.tsx
index e6502cc5e4..a500ff34e4 100644
--- a/grafana-plugin/src/containers/UserSettings/parts/tabs/CloudPhoneSettings/CloudPhoneSettings.tsx
+++ b/grafana-plugin/src/containers/UserSettings/parts/tabs/CloudPhoneSettings/CloudPhoneSettings.tsx
@@ -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) ? (
+ OnCall uses Grafana Cloud for SMS and phone call notifications
@@ -135,12 +140,7 @@ const CloudPhoneSettings = observer((props: CloudPhoneSettingsProps) => {
{!syncing ? : }
- ) : (
-
- OnCall uses Grafana Cloud for SMS and phone call notifications
- You do not have permission to perform this action. Ask an admin to upgrade your permissions.
-
- )}
+
>
);
});
diff --git a/grafana-plugin/src/containers/UserSettings/parts/tabs/PhoneVerification/PhoneVerification.tsx b/grafana-plugin/src/containers/UserSettings/parts/tabs/PhoneVerification/PhoneVerification.tsx
index b28fbe5a8c..8393a2c84b 100644
--- a/grafana-plugin/src/containers/UserSettings/parts/tabs/PhoneVerification/PhoneVerification.tsx
+++ b/grafana-plugin/src/containers/UserSettings/parts/tabs/PhoneVerification/PhoneVerification.tsx
@@ -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}
>
-
+
{
value={phone}
onChange={onChangePhoneCallback}
/>
-
+
{!user.verified_phone_number && (
{showVerifyOrSendCodeButton && (
-
+
{isCodeSent ? 'Verify' : 'Send Code'}
-
+
)}
{showForgetNumber && (
-
+
{'Forget Phone Number'}
-
+
)}
{user.verified_phone_number && (
<>
-
+
{isTestCallInProgress ? 'Making Test Call...' : 'Make Test Call'}
-
+
{
}, []);
return (
- <>
+
{telegramConfigured || !store.hasFeature(AppFeature.LiveSettings) ? (
Manual connection
@@ -96,7 +101,7 @@ const TelegramInfo = observer((_props: TelegramInfoProps) => {
)}
)}
- >
+
);
});
diff --git a/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlDisplay.tsx b/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlDisplay.tsx
new file mode 100644
index 0000000000..c8ffed9ca8
--- /dev/null
+++ b/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlDisplay.tsx
@@ -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 = (props) => {
+ const { userAction, children, title, message } = props;
+
+ const hasPermission = isUserActionAllowed(userAction);
+
+ return hasPermission ? (
+ children
+ ) : (
+
+ {title && {title}}
+ {message}
+
+ );
+};
diff --git a/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControl.module.css b/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlTooltip.module.css
similarity index 100%
rename from grafana-plugin/src/containers/WithPermissionControl/WithPermissionControl.module.css
rename to grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlTooltip.module.css
diff --git a/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControl.tsx b/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlTooltip.tsx
similarity index 85%
rename from grafana-plugin/src/containers/WithPermissionControl/WithPermissionControl.tsx
rename to grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlTooltip.tsx
index 1165d37641..4d419215b6 100644
--- a/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControl.tsx
+++ b/grafana-plugin/src/containers/WithPermissionControl/WithPermissionControlTooltip.tsx
@@ -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);
diff --git a/grafana-plugin/src/containers/WithPermissionControl2/WithPermissionControl.tsx b/grafana-plugin/src/containers/WithPermissionControl2/WithPermissionControl.tsx
deleted file mode 100644
index a3dd5b0bbd..0000000000
--- a/grafana-plugin/src/containers/WithPermissionControl2/WithPermissionControl.tsx
+++ /dev/null
@@ -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 ? (
-
- {element}
-
- ) : (
- element
- );
-});
diff --git a/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx b/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx
index 61274d4a97..71b7cfa840 100644
--- a/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx
+++ b/grafana-plugin/src/pages/escalation-chains/EscalationChains.tsx
@@ -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
-
+ {
this.setState({ showCreateEscalationChainModal: true });
@@ -171,7 +171,7 @@ class EscalationChainsPage extends React.Component
New Escalation Chain
-
+
{searchResult ? (
No escalations found, check your filtering and current team.
-
+
New Escalation Chain
-
+
}
/>
@@ -272,7 +272,7 @@ class EscalationChainsPage extends React.Component
-
+
-
-
+
+ 0}
@@ -295,7 +295,7 @@ class EscalationChainsPage extends React.Component
-
+
{escalationChain.number_of_integrations > 0 && (
diff --git a/grafana-plugin/src/pages/incident/Incident.helpers.tsx b/grafana-plugin/src/pages/incident/Incident.helpers.tsx
index cd3e70b15b..25908a4872 100644
--- a/grafana-plugin/src/pages/incident/Incident.helpers.tsx
+++ b/grafana-plugin/src/pages/incident/Incident.helpers.tsx
@@ -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 = (
-
+
Resolve
-
+
);
const unacknowledgeButton = (
-
+
Unacknowledge
-
+
);
const unresolveButton = (
-
+
Unresolve
-
+
);
const acknowledgeButton = (
-
+
Acknowledge
-
+
);
const buttons = [];
@@ -201,11 +201,11 @@ export function getActionButtons(incident: AlertType, cx: any, callbacks: { [key
if (incident.status === IncidentStatus.Silenced) {
buttons.push(
-
+
Unsilence
-
+
);
}
diff --git a/grafana-plugin/src/pages/incident/Incident.tsx b/grafana-plugin/src/pages/incident/Incident.tsx
index aec75be1ac..cb728f7e5e 100644
--- a/grafana-plugin/src/pages/incident/Incident.tsx
+++ b/grafana-plugin/src/pages/incident/Incident.tsx
@@ -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
#{incident.root_alert_group.inside_organization_number}{' '}
{incident.root_alert_group.render_for_web.title}
{' '}
-
+
Unattach
-
+
)}
@@ -764,11 +764,11 @@ function AttachedIncidentsList({
#{incident.inside_organization_number} {incident.render_for_web.title}
-
+ getUnattachClickHandler(incident.pk)} variant="secondary">
Unattach
-
+
);
})}
diff --git a/grafana-plugin/src/pages/incident/parts/PagedUsers.tsx b/grafana-plugin/src/pages/incident/parts/PagedUsers.tsx
index 41aa7f6183..8fcf8824d5 100644
--- a/grafana-plugin/src/pages/incident/parts/PagedUsers.tsx
+++ b/grafana-plugin/src/pages/incident/parts/PagedUsers.tsx
@@ -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) => {
{pagedUser.username}
-
+ {
name="trash-alt"
/>
-
+
))}
diff --git a/grafana-plugin/src/pages/incidents/Incidents.tsx b/grafana-plugin/src/pages/incidents/Incidents.tsx
index 7a3b36335d..4938664705 100644
--- a/grafana-plugin/src/pages/incidents/Incidents.tsx
+++ b/grafana-plugin/src/pages/incidents/Incidents.tsx
@@ -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
Alert Groups
-
+
Manual alert group
-
+
{this.renderIncidentFilters()}
@@ -233,7 +233,7 @@ class Incidents extends React.Component
{'resolve' in store.alertGroupStore.bulkActions && (
-
+
>
Resolve
-
+
)}
{'acknowledge' in store.alertGroupStore.bulkActions && (
-
+
>
Acknowledge
-
+
)}
{'silence' in store.alertGroupStore.bulkActions && (
-
+
>
Restart
-
+
)}
{'restart' in store.alertGroupStore.bulkActions && (
-
+ this.getBulkActionClickHandler('silence', ev)}
/>
-
+
)}
{hasSelected
diff --git a/grafana-plugin/src/pages/incidents/parts/IncidentDropdown.tsx b/grafana-plugin/src/pages/incidents/parts/IncidentDropdown.tsx
index 59b552e890..0167ad5870 100644
--- a/grafana-plugin/src/pages/incidents/parts/IncidentDropdown.tsx
+++ b/grafana-plugin/src/pages/incidents/parts/IncidentDropdown.tsx
@@ -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={() => (