Polish unified slack ui (#4819)

# What this PR does

polish ui of unified slack:
- [x] New deprecation banner
- [x] Move install/uninstall button to the top right corner
- [x] New texts in migrate modal
- [x] New text and layout in uninstall modal.

## Which issue(s) this PR closes

Related to https://github.com/grafana/oncall-gateway/issues/299

<!--
*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
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] 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.
This commit is contained in:
Dominik Broj 2024-08-14 14:52:55 +02:00 committed by GitHub
parent a1c67cdfe7
commit 854dfd56a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 150 additions and 117 deletions

View file

@ -36,6 +36,10 @@
margin-right: 4px;
}
.u-margin-left-xs {
margin-left: 4px;
}
.u-margin-bottom-none {
margin-bottom: 0;
}
@ -44,6 +48,10 @@
margin-bottom: 12px;
}
.u-margin-bottom-xxs {
margin-bottom: 2px;
}
.u-margin-top-xs {
margin-top: 4px;
}

View file

@ -17,6 +17,7 @@ export const WithConfirm: React.FC<WithConfirmProps> = ({
children,
disabled,
skip = false,
modalClass,
}) => {
const [showConfirmation, setShowConfirmation] = useState<boolean>(false);
@ -57,6 +58,7 @@ export const WithConfirm: React.FC<WithConfirmProps> = ({
onDismiss={() => {
setShowConfirmation(false);
}}
modalClass={modalClass}
/>
)}
{React.cloneElement(children, {

View file

@ -18,7 +18,7 @@
.slack-infoblock {
text-align: center;
width: 725px;
width: 100%;
}
.external-link-style {
@ -33,10 +33,9 @@
.infoblock-text {
margin-left: 48px;
margin-right: 48px;
margin-top: 24px;
}
.infoblock-icon {
.marginTop {
margin-top: 24px;
}
@ -47,10 +46,18 @@
transform: translateY(-50%);
}
.upgradeSlackAlert svg {
display: none;
.upgradeSlackAlertText {
margin-right: 110px;
a {
font-weight: 600;
}
}
.linkToIncidentWrapper {
margin-top: 16px;
}
.confirmUninstallModal input {
min-width: 300px;
}

View file

@ -4,13 +4,13 @@ import {
Alert,
HorizontalGroup,
LoadingPlaceholder,
VerticalGroup,
Icon,
Button,
InlineField,
Input,
Legend,
ConfirmModal,
Stack,
} from '@grafana/ui';
import cn from 'classnames/bind';
import { observer } from 'mobx-react';
@ -31,7 +31,7 @@ import { WithStoreProps } from 'state/types';
import { useStore } from 'state/useStore';
import { withMobXProviderContext } from 'state/withStore';
import { UserActions } from 'utils/authorization/authorization';
import { DOCS_SLACK_SETUP, getPluginId } from 'utils/consts';
import { DOCS_ROOT, DOCS_SLACK_SETUP, getPluginId } from 'utils/consts';
import { useConfirmModal } from 'utils/hooks';
import { showApiError } from 'utils/utils';
@ -122,9 +122,74 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
const isUnifiedSlackInstalled = !currentOrganization.slack_team_identity.needs_reinstall;
const uninstallSlackButton = (
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
{isUnifiedSlackInstalled ? (
<WithConfirm
title="Uninstall IRM Slack integration"
modalClass={styles.confirmUninstallModal}
description={
<div>
<Alert severity="error" title="">
Are you sure you want to remove this integration from OnCall and Incident?
</Alert>
<p>
This action will uninstall the IRM Slack integration from OnCall and Incident. The following IRM data
will be permanently deleted:
</p>
<ul style={{ marginLeft: '20px' }}>
<li>OnCall default Slack channel</li>
<li>Slack channels for OnCall escalation policies</li>
<li>Slack channels and user groups for OnCall schedules</li>
<li>Linked Slack profiles for OnCall users</li>
<li>Incident announcement and automatic Slack channel creation</li>
</ul>
<br />
</div>
}
confirmationText="UNINSTALL"
confirmText="Uninstall"
>
<Button variant="destructive" fill="outline" onClick={() => this.removeSlackIntegration()}>
Uninstall
</Button>
</WithConfirm>
) : (
<WithConfirm
title="Remove Slack Integration for all of OnCall"
description={
<Alert severity="error" title="WARNING">
<p>Are you sure to delete this Slack Integration?</p>
<p>Removing the integration will also irreverisbly remove the following data for your OnCall plugin:</p>
<ul style={{ marginLeft: '20px' }}>
<li>default organization Slack channel</li>
<li>default Slack channels for OnCall Integrations</li>
<li>Slack channels & Slack user groups for OnCall Schedules</li>
<li>linked Slack usernames for OnCall Users</li>
</ul>
<br />
<p>
If you would like to instead remove your linked Slack username, please head{' '}
<PluginLink query={{ page: 'users/me' }}>here</PluginLink>.
</p>
</Alert>
}
confirmationText="DELETE"
>
<Button variant="destructive" fill="outline" onClick={() => this.removeSlackIntegration()}>
Uninstall
</Button>
</WithConfirm>
)}
</WithPermissionControlTooltip>
);
return (
<div className={cx('root')}>
<Legend>Slack App settings</Legend>
<Stack>
<Legend>Slack OnCall settings</Legend>
{uninstallSlackButton}
</Stack>
{currentOrganization.slack_team_identity.needs_reinstall && <UpgradeToUnifiedSlackBanner />}
<InlineField label="Slack Workspace" grow disabled>
<Input value={currentOrganization?.slack_team_identity?.cached_name} />
@ -152,62 +217,6 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
severity="info"
title="Tip: Create a separate channel for OnCall Slack App notifications (catch-all). Avoid using #general, etc."
/>
<InlineField>
<WithPermissionControlTooltip userAction={UserActions.ChatOpsUpdateSettings}>
{isUnifiedSlackInstalled ? (
<WithConfirm
title="Remove IRM Slack integration"
description={
<Alert severity="error" title="WARNING">
<p>Are you sure to delete this Slack Integration? It will affect both OnCall & Incident.</p>
<p>Removing the integration will irreverisbly remove the following data for IRM;</p>
<ul style={{ marginLeft: '20px' }}>
<li>OnCall default Slack channel</li>
<li>Slack channels for OnCall escalation policies</li>
<li>Slack channels & Slack user groups for OnCall Schedules</li>
<li>linked Slack usernames for OnCall Users</li>
<li>Incident hooks</li>
</ul>
<br />
</Alert>
}
confirmationText="DELETE"
>
<Button variant="destructive" onClick={() => this.removeSlackIntegration()}>
Disconnect Slack App
</Button>
</WithConfirm>
) : (
<WithConfirm
title="Remove Slack Integration for all of OnCall"
description={
<Alert severity="error" title="WARNING">
<p>Are you sure to delete this Slack Integration?</p>
<p>
Removing the integration will also irreverisbly remove the following data for your OnCall plugin:
</p>
<ul style={{ marginLeft: '20px' }}>
<li>default organization Slack channel</li>
<li>default Slack channels for OnCall Integrations</li>
<li>Slack channels & Slack user groups for OnCall Schedules</li>
<li>linked Slack usernames for OnCall Users</li>
</ul>
<br />
<p>
If you would like to instead remove your linked Slack username, please head{' '}
<PluginLink query={{ page: 'users/me' }}>here</PluginLink>.
</p>
</Alert>
}
confirmationText="DELETE"
>
<Button variant="destructive" onClick={() => this.removeSlackIntegration()}>
Disconnect Slack App
</Button>
</WithConfirm>
)}
</WithPermissionControlTooltip>
</InlineField>
<Legend>Additional settings</Legend>
<InlineField
label="Timeout for acknowledged alerts"
@ -287,56 +296,53 @@ class _SlackSettings extends Component<SlackProps, SlackState> {
const isUnifiedSlackEnabled = store.hasFeature(AppFeature.UnifiedSlack);
return (
<VerticalGroup spacing="lg">
<Text.Title level={2}>Connect Slack workspace</Text.Title>
<Stack gap={4} direction="column">
<Stack justifyContent={'space-between'}>
<Text.Title level={2}>Slack</Text.Title>
{isLiveSettingAvailable ? (
<PluginLink query={{ page: 'live-settings' }}>
<Button variant="primary">Setup ENV Variables</Button>
</PluginLink>
) : (
<Stack grow={0}>
<Button onClick={this.handleOpenSlackInstructions}>Install integration</Button>
{store.hasFeature(AppFeature.LiveSettings) && (
<PluginLink query={{ page: 'live-settings' }}>
<Button variant="secondary">See ENV Variables</Button>
</PluginLink>
)}
</Stack>
)}
</Stack>
<Block bordered withBackground className={cx('slack-infoblock')}>
<VerticalGroup align="center">
<div className={cx('infoblock-icon')}>
<Stack direction="column" alignItems="center" gap={0}>
<div className={cx('marginTop')}>
<SlackNewIcon />
</div>
<Text className={cx('infoblock-text')}>
<Text className={cx(['infoblock-text', 'marginTop'])}>
{isUnifiedSlackEnabled
? 'Connecting Slack App will allow you to manage alert groups and incidents in your team Slack workspace.'
: 'Connecting Slack App will allow you to manage alert groups in your team Slack workspace.'}
</Text>
<Text className={cx('infoblock-text')}>
After a basic workspace connection your team members need to connect their personal Slack accounts in
order to be allowed to manage alert groups.
Once the workspace is connected, team members need to link their Slack accounts to their IRM users to
start using the app.
</Text>
{isLiveSettingAvailable && (
<Text type="secondary" className={cx('infoblock-text')}>
<Text type="secondary" className={cx('infoblock-text', 'marginTop')}>
For bot creating instructions and additional information please read{' '}
<a href={DOCS_SLACK_SETUP} target="_blank" rel="noreferrer">
<Text type="link">our documentation</Text>
</a>
</Text>
)}
<img
style={{ height: '350px', display: 'block', margin: '0 auto' }}
src={`public/plugins/${getPluginId()}/assets/img/slack_instructions.png`}
/>
</VerticalGroup>
</Stack>
</Block>
{isLiveSettingAvailable ? (
<PluginLink query={{ page: 'live-settings' }}>
<Button variant="primary">Setup ENV Variables</Button>
</PluginLink>
) : (
<HorizontalGroup>
<Button onClick={this.handleOpenSlackInstructions}>
<HorizontalGroup spacing="xs" align="center">
<Icon name="external-link-alt" className={cx('external-link-style')} /> Open Slack connection page
</HorizontalGroup>
</Button>
{store.hasFeature(AppFeature.LiveSettings) && (
<PluginLink query={{ page: 'live-settings' }}>
<Button variant="secondary">See ENV Variables</Button>
</PluginLink>
)}
</HorizontalGroup>
)}
</VerticalGroup>
</Stack>
);
};
}
@ -350,48 +356,58 @@ const UpgradeToUnifiedSlackBanner = observer(() => {
return (
<>
<ConfirmModal {...modalProps} />
<Alert
className={styles.upgradeSlackAlert}
severity="success"
title="Upgrade to Grafana IRM unified Slack app"
buttonContent={<div>Upgrade</div>}
>
We've rebranded the OnCall Slack app as the Grafana IRM Slack app, now with incident management features.
<p>Click "Upgrade" to reviewn and approve the new permissions and complete the process.</p>
<p>For more details, check our documentation.</p>
<Alert severity="warning" title="This integration is outdated" buttonContent="Migrate">
<div className={styles.upgradeSlackAlertText}>
The OnCall Slack app is now a Grafana IRM app with new incident management features. Migrate now to access the
enhanced capabilities.{' '}
<a href={`${DOCS_ROOT}`} target="_blank" rel="noreferrer">
{/* TODO: update link to docs */}
Learn more
</a>
</div>
<Button
variant="secondary"
className={styles.upgradeSlackBtn}
variant="secondary"
onClick={() =>
openModal({
confirmText: 'Confirm',
confirmText: 'Migrate',
onConfirm: installSlackIntegration,
confirmButtonVariant: 'primary',
title: `Upgrade to Grafana IRM Slack app`,
title: `Migrate to Grafana IRM Slack integration`,
description: (
<div>
<p>
You will be redirected to Slack to approve additional permissions for the Grafana IRM Slack app.{' '}
You will be redirected to Slack to approve additional permissions for the Grafana IRM Slack app. New
permissions are necessary for incident management features.
</p>
<p>After the migration, you can use OnCall and Incident features in a single app:</p>
<p>
These permissions are necessary for incident management. You can view the detailed list of new
permissions here.[LINK]
<ul style={{ marginLeft: '20px' }}>
<li>The OnCall Slack configuration will remain intact.</li>
<li>
The Incident Slack integration will be upgraded to Grafana IRM Slack. Announcement and Create
Slack Channel hooks will be migrated, active incident can still be managed.
</li>
</ul>
</p>
<p>After the upgrade, you'll be able to manage incidents in Slack using the Grafana IRM Slack app.</p>
<ul style={{ marginLeft: '20px' }}>
<li>Your OnCall Slack configuration will remain unchanged. </li>
<li>
Your Incident Slack integration will be upgraded to use the Grafana IRM Slack app. Please refer to
the documentation for more details.[LINK]
</li>
</ul>
<a
href={`${DOCS_ROOT}`} // TODO: update link to docs
target="_blank"
rel="noreferrer"
className={styles.marginTop}
>
<Text type="link">
<span>Learn more in the docs</span>
<Icon name="external-link-alt" className="u-margin-left-xs u-margin-bottom-xxs" />
</Text>
</a>
</div>
),
confirmVariant: 'secondary',
})
}
>
Upgrade
Migrate
</Button>
</Alert>
</>