Skip to content

Commit a332011

Browse files
adjust to unified slack (#4776)
# What this PR does Introduce OnCall UI for Unified Slack migration. It's mostly banners and text adjustments. Changes are behind feature flag. <!-- *Note*: If you want the issue to be auto-closed once the PR is merged, change "Related to" to "Closes" in the line above. If you have more than one GitHub issue that this PR closes, be sure to preface each issue link with a [closing keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue). This ensures that the issue(s) are auto-closed once the PR has been merged. --> ## Checklist - [ ] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] Added the relevant release notes label (see labels prefixed w/ `release:`). These labels dictate how your PR will show up in the autogenerated release notes. --------- Co-authored-by: Innokentii Konstantinov <[email protected]>
1 parent fbd68b1 commit a332011

File tree

5 files changed

+155
-42
lines changed

5 files changed

+155
-42
lines changed

engine/apps/api/views/features.py

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
class Feature(enum.StrEnum):
1616
MSTEAMS = "msteams"
1717
SLACK = "slack"
18+
UNIFIED_SLACK = "unified_slack"
1819
TELEGRAM = "telegram"
1920
LIVE_SETTINGS = "live_settings"
2021
GRAFANA_CLOUD_NOTIFICATIONS = "grafana_cloud_notifications"
@@ -46,6 +47,9 @@ def _get_enabled_features(self, request):
4647
if settings.FEATURE_SLACK_INTEGRATION_ENABLED:
4748
enabled_features.append(Feature.SLACK)
4849

50+
if settings.UNIFIED_SLACK_APP_ENABLED:
51+
enabled_features.append(Feature.UNIFIED_SLACK)
52+
4953
if settings.FEATURE_TELEGRAM_INTEGRATION_ENABLED:
5054
enabled_features.append(Feature.TELEGRAM)
5155

grafana-plugin/src/models/slack/slack.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ export class SlackStore extends BaseStore {
8282
window.location = url_for_redirect;
8383
}
8484

85+
@action.bound
8586
async installSlackIntegration() {
8687
try {
8788
const response = await makeRequestRaw('/login/slack-install-free/', {});
88-
8989
if (response.status === 201) {
9090
this.rootStore.organizationStore.loadCurrentOrganization();
9191
} else if (response.status === 200) {

grafana-plugin/src/pages/settings/tabs/ChatOps/tabs/SlackSettings/SlackSettings.module.css

+15
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,18 @@
3939
.infoblock-icon {
4040
margin-top: 24px;
4141
}
42+
43+
.upgradeSlackBtn {
44+
position: absolute;
45+
right: 20px;
46+
top: 50%;
47+
transform: translateY(-50%);
48+
}
49+
50+
.upgradeSlackAlert svg {
51+
display: none;
52+
}
53+
54+
.linkToIncidentWrapper {
55+
margin-top: 16px;
56+
}

grafana-plugin/src/pages/settings/tabs/ChatOps/tabs/SlackSettings/SlackSettings.tsx

+134-41
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import {
1010
InlineField,
1111
Input,
1212
Legend,
13+
ConfirmModal,
1314
} from '@grafana/ui';
1415
import cn from 'classnames/bind';
1516
import { observer } from 'mobx-react';
1617

1718
import { Block } from 'components/GBlock/Block';
19+
import { PluginBridge, SupportedPlugin } from 'components/PluginBridge/PluginBridge';
1820
import { PluginLink } from 'components/PluginLink/PluginLink';
1921
import { Text } from 'components/Text/Text';
2022
import { WithConfirm } from 'components/WithConfirm/WithConfirm';
@@ -26,9 +28,11 @@ import { PRIVATE_CHANNEL_NAME } from 'models/slack_channel/slack_channel.config'
2628
import { SlackChannel } from 'models/slack_channel/slack_channel.types';
2729
import { AppFeature } from 'state/features';
2830
import { WithStoreProps } from 'state/types';
31+
import { useStore } from 'state/useStore';
2932
import { withMobXProviderContext } from 'state/withStore';
3033
import { UserActions } from 'utils/authorization/authorization';
3134
import { DOCS_SLACK_SETUP, getPluginId } from 'utils/consts';
35+
import { useConfirmModal } from 'utils/hooks';
3236
import { showApiError } from 'utils/utils';
3337

3438
import styles from './SlackSettings.module.css';
@@ -116,9 +120,12 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
116120
slackChannelStore: { items: slackChannelItems },
117121
} = store;
118122

123+
const isUnifiedSlackInstalled = !currentOrganization.slack_team_identity.needs_reinstall;
124+
119125
return (
120126
<div className={cx('root')}>
121127
<Legend>Slack App settings</Legend>
128+
{currentOrganization.slack_team_identity.needs_reinstall && <UpgradeToUnifiedSlackBanner />}
122129
<InlineField label="Slack Workspace" grow disabled>
123130
<Input value={currentOrganization?.slack_team_identity?.cached_name} />
124131
</InlineField>
@@ -147,33 +154,58 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
147154
/>
148155
<InlineField>
149156
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
150-
<WithConfirm
151-
title="Remove Slack Integration for all of OnCall"
152-
description={
153-
<Alert severity="error" title="WARNING">
154-
<p>Are you sure to delete this Slack Integration?</p>
155-
<p>
156-
Removing the integration will also irreverisbly remove the following data for your OnCall plugin:
157-
</p>
158-
<ul style={{ marginLeft: '20px' }}>
159-
<li>default organization Slack channel</li>
160-
<li>default Slack channels for OnCall Integrations</li>
161-
<li>Slack channels & Slack user groups for OnCall Schedules</li>
162-
<li>linked Slack usernames for OnCall Users</li>
163-
</ul>
164-
<br />
165-
<p>
166-
If you would like to instead remove your linked Slack username, please head{' '}
167-
<PluginLink query={{ page: 'users/me' }}>here</PluginLink>.
168-
</p>
169-
</Alert>
170-
}
171-
confirmationText="DELETE"
172-
>
173-
<Button variant="destructive" onClick={() => this.removeSlackIntegration()}>
174-
Disconnect Slack App
175-
</Button>
176-
</WithConfirm>
157+
{isUnifiedSlackInstalled ? (
158+
<WithConfirm
159+
title="Remove IRM Slack integration"
160+
description={
161+
<Alert severity="error" title="WARNING">
162+
<p>Are you sure to delete this Slack Integration? It will affect both OnCall & Incident.</p>
163+
<p>Removing the integration will irreverisbly remove the following data for IRM;</p>
164+
<ul style={{ marginLeft: '20px' }}>
165+
<li>OnCall default Slack channel</li>
166+
<li>Slack channels for OnCall escalation policies</li>
167+
<li>Slack channels & Slack user groups for OnCall Schedules</li>
168+
<li>linked Slack usernames for OnCall Users</li>
169+
<li>Incident hooks</li>
170+
</ul>
171+
<br />
172+
</Alert>
173+
}
174+
confirmationText="DELETE"
175+
>
176+
<Button variant="destructive" onClick={() => this.removeSlackIntegration()}>
177+
Disconnect Slack App
178+
</Button>
179+
</WithConfirm>
180+
) : (
181+
<WithConfirm
182+
title="Remove Slack Integration for all of OnCall"
183+
description={
184+
<Alert severity="error" title="WARNING">
185+
<p>Are you sure to delete this Slack Integration?</p>
186+
<p>
187+
Removing the integration will also irreverisbly remove the following data for your OnCall plugin:
188+
</p>
189+
<ul style={{ marginLeft: '20px' }}>
190+
<li>default organization Slack channel</li>
191+
<li>default Slack channels for OnCall Integrations</li>
192+
<li>Slack channels & Slack user groups for OnCall Schedules</li>
193+
<li>linked Slack usernames for OnCall Users</li>
194+
</ul>
195+
<br />
196+
<p>
197+
If you would like to instead remove your linked Slack username, please head{' '}
198+
<PluginLink query={{ page: 'users/me' }}>here</PluginLink>.
199+
</p>
200+
</Alert>
201+
}
202+
confirmationText="DELETE"
203+
>
204+
<Button variant="destructive" onClick={() => this.removeSlackIntegration()}>
205+
Disconnect Slack App
206+
</Button>
207+
</WithConfirm>
208+
)}
177209
</WithPermissionControlTooltip>
178210
</InlineField>
179211
<Legend>Additional settings</Legend>
@@ -201,19 +233,20 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
201233
</WithPermissionControlTooltip>
202234
</HorizontalGroup>
203235
</InlineField>
204-
{currentOrganization.slack_team_identity.needs_reinstall && (
205-
<>
206-
<Legend>Unified Slack App</Legend>
207-
<InlineField>
208-
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
209-
<Button onClick={this.handleOpenSlackInstructions}>
210-
<HorizontalGroup spacing="xs" align="center">
211-
<Icon name="external-link-alt" className={cx('external-link-style')} /> Reinstall Slack App
212-
</HorizontalGroup>
213-
</Button>
214-
</WithPermissionControlTooltip>
215-
</InlineField>
216-
</>
236+
{isUnifiedSlackInstalled && (
237+
<div className={styles.linkToIncidentWrapper}>
238+
<PluginBridge plugin={SupportedPlugin.Incident}>
239+
<Text type="secondary">
240+
<a
241+
href={`/a/${SupportedPlugin.Incident}/integrations/grate.irm.slack`}
242+
target="_blank"
243+
rel="noreferrer"
244+
>
245+
<Text type="link">Open Slack Incident settings</Text>
246+
</a>
247+
</Text>
248+
</PluginBridge>
249+
</div>
217250
)}
218251
</div>
219252
);
@@ -251,6 +284,7 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
251284
const { store } = this.props;
252285
const { showENVVariablesButton } = this.state;
253286
const isLiveSettingAvailable = store.hasFeature(AppFeature.LiveSettings) && showENVVariablesButton;
287+
const isUnifiedSlackEnabled = store.hasFeature(AppFeature.UnifiedSlack);
254288

255289
return (
256290
<VerticalGroup spacing="lg">
@@ -261,7 +295,9 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
261295
<SlackNewIcon />
262296
</div>
263297
<Text className={cx('infoblock-text')}>
264-
Connecting Slack App will allow you to manage alert groups in your team Slack workspace.
298+
{isUnifiedSlackEnabled
299+
? 'Connecting Slack App will allow you to manage alert groups and incidents in your team Slack workspace.'
300+
: 'Connecting Slack App will allow you to manage alert groups in your team Slack workspace.'}
265301
</Text>
266302
<Text className={cx('infoblock-text')}>
267303
After a basic workspace connection your team members need to connect their personal Slack accounts in
@@ -305,4 +341,61 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
305341
};
306342
}
307343

344+
const UpgradeToUnifiedSlackBanner = observer(() => {
345+
const {
346+
slackStore: { installSlackIntegration },
347+
} = useStore();
348+
const { modalProps, openModal } = useConfirmModal();
349+
350+
return (
351+
<>
352+
<ConfirmModal {...modalProps} />
353+
<Alert
354+
className={styles.upgradeSlackAlert}
355+
severity="success"
356+
title="Upgrade to Grafana IRM unified Slack app"
357+
buttonContent={<div>Upgrade</div>}
358+
>
359+
We've rebranded the OnCall Slack app as the Grafana IRM Slack app, now with incident management features.
360+
<p>Click "Upgrade" to reviewn and approve the new permissions and complete the process.</p>
361+
<p>For more details, check our documentation.</p>
362+
<Button
363+
variant="secondary"
364+
className={styles.upgradeSlackBtn}
365+
onClick={() =>
366+
openModal({
367+
confirmText: 'Confirm',
368+
onConfirm: installSlackIntegration,
369+
confirmButtonVariant: 'primary',
370+
title: `Upgrade to Grafana IRM Slack app`,
371+
description: (
372+
<div>
373+
<p>
374+
You will be redirected to Slack to approve additional permissions for the Grafana IRM Slack app.{' '}
375+
</p>
376+
<p>
377+
These permissions are necessary for incident management. You can view the detailed list of new
378+
permissions here.[LINK]
379+
</p>
380+
<p>After the upgrade, you'll be able to manage incidents in Slack using the Grafana IRM Slack app.</p>
381+
<ul style={{ marginLeft: '20px' }}>
382+
<li>Your OnCall Slack configuration will remain unchanged. </li>
383+
<li>
384+
Your Incident Slack integration will be upgraded to use the Grafana IRM Slack app. Please refer to
385+
the documentation for more details.[LINK]
386+
</li>
387+
</ul>
388+
</div>
389+
),
390+
confirmVariant: 'secondary',
391+
})
392+
}
393+
>
394+
Upgrade
395+
</Button>
396+
</Alert>
397+
</>
398+
);
399+
});
400+
308401
export const SlackSettings = withMobXProviderContext(_SlackSettings);

grafana-plugin/src/state/features.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export enum AppFeature {
22
Slack = 'slack',
3+
UnifiedSlack = 'unified_slack',
34
Telegram = 'telegram',
45
LiveSettings = 'live_settings',
56
CloudNotifications = 'grafana_cloud_notifications',

0 commit comments

Comments
 (0)