Skip to content

Commit 4d48d1b

Browse files
authored
Open the proper integration settings on integrations disabled error (#30538)
* Open the proper integration settings on integrations disabled error. * Convert to functional component. * Add test * update snap
1 parent f75d410 commit 4d48d1b

File tree

4 files changed

+149
-37
lines changed

4 files changed

+149
-37
lines changed
Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,53 @@
11
/*
2-
Copyright 2024 New Vector Ltd.
2+
Copyright 2024, 2025 New Vector Ltd.
33
Copyright 2019 The Matrix.org Foundation C.I.C.
44
55
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
66
Please see LICENSE files in the repository root for full details.
77
*/
88

9-
import React from "react";
9+
import React, { useCallback } from "react";
1010

1111
import { _t } from "../../../languageHandler";
1212
import dis from "../../../dispatcher/dispatcher";
1313
import { Action } from "../../../dispatcher/actions";
1414
import BaseDialog from "./BaseDialog";
1515
import DialogButtons from "../elements/DialogButtons";
16+
import { UserTab } from "./UserTab";
1617

1718
interface IProps {
1819
onFinished(): void;
1920
}
2021

21-
export default class IntegrationsDisabledDialog extends React.Component<IProps> {
22-
private onAcknowledgeClick = (): void => {
23-
this.props.onFinished();
24-
};
22+
export const IntegrationsDisabledDialog: React.FC<IProps> = ({ onFinished }) => {
23+
const onOpenSettingsClick = useCallback(() => {
24+
onFinished();
25+
dis.dispatch({
26+
action: Action.ViewUserSettings,
27+
initialTabId: UserTab.Security,
28+
});
29+
}, [onFinished]);
2530

26-
private onOpenSettingsClick = (): void => {
27-
this.props.onFinished();
28-
dis.fire(Action.ViewUserSettings);
29-
};
30-
31-
public render(): React.ReactNode {
32-
return (
33-
<BaseDialog
34-
className="mx_IntegrationsDisabledDialog"
35-
hasCancel={true}
36-
onFinished={this.props.onFinished}
37-
title={_t("integrations|disabled_dialog_title")}
38-
>
39-
<div className="mx_IntegrationsDisabledDialog_content">
40-
<p>
41-
{_t("integrations|disabled_dialog_description", {
42-
manageIntegrations: _t("integration_manager|manage_title"),
43-
})}
44-
</p>
45-
</div>
46-
<DialogButtons
47-
primaryButton={_t("common|settings")}
48-
onPrimaryButtonClick={this.onOpenSettingsClick}
49-
cancelButton={_t("action|ok")}
50-
onCancel={this.onAcknowledgeClick}
51-
/>
52-
</BaseDialog>
53-
);
54-
}
55-
}
31+
return (
32+
<BaseDialog
33+
className="mx_IntegrationsDisabledDialog"
34+
hasCancel={true}
35+
onFinished={onFinished}
36+
title={_t("integrations|disabled_dialog_title")}
37+
>
38+
<div className="mx_IntegrationsDisabledDialog_content">
39+
<p>
40+
{_t("integrations|disabled_dialog_description", {
41+
manageIntegrations: _t("integration_manager|manage_title"),
42+
})}
43+
</p>
44+
</div>
45+
<DialogButtons
46+
primaryButton={_t("common|settings")}
47+
onPrimaryButtonClick={onOpenSettingsClick}
48+
cancelButton={_t("action|ok")}
49+
onCancel={onFinished}
50+
/>
51+
</BaseDialog>
52+
);
53+
};

src/integrations/IntegrationManagers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import SdkConfig from "../SdkConfig";
1313
import Modal from "../Modal";
1414
import { IntegrationManagerInstance, Kind } from "./IntegrationManagerInstance";
1515
import IntegrationsImpossibleDialog from "../components/views/dialogs/IntegrationsImpossibleDialog";
16-
import IntegrationsDisabledDialog from "../components/views/dialogs/IntegrationsDisabledDialog";
16+
import { IntegrationsDisabledDialog } from "../components/views/dialogs/IntegrationsDisabledDialog";
1717
import WidgetUtils from "../utils/WidgetUtils";
1818
import { MatrixClientPeg } from "../MatrixClientPeg";
1919

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
5+
* Please see LICENSE files in the repository root for full details.
6+
*/
7+
8+
import React from "react";
9+
import { fireEvent, render } from "jest-matrix-react";
10+
11+
import { IntegrationsDisabledDialog } from "../../../../../src/components/views/dialogs/IntegrationsDisabledDialog.tsx";
12+
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher.ts";
13+
import { Action } from "../../../../../src/dispatcher/actions.ts";
14+
import { UserTab } from "../../../../../src/components/views/dialogs/UserTab.ts";
15+
16+
describe("<IntegrationsDisabledDialog />", () => {
17+
const onFinished = jest.fn();
18+
19+
afterEach(() => {
20+
jest.restoreAllMocks();
21+
});
22+
23+
function renderComponent() {
24+
return render(<IntegrationsDisabledDialog onFinished={onFinished} />);
25+
}
26+
27+
it("should render as expected", () => {
28+
const { asFragment } = renderComponent();
29+
expect(asFragment()).toMatchSnapshot();
30+
});
31+
it("should do nothing on clicking OK", () => {
32+
const { getByText } = renderComponent();
33+
fireEvent.click(getByText("OK"));
34+
expect(onFinished).toHaveBeenCalled();
35+
});
36+
it("should open the correct user settings tab on clicking Settings", () => {
37+
jest.spyOn(defaultDispatcher, "dispatch").mockImplementation(() => {});
38+
const { getByText } = renderComponent();
39+
fireEvent.click(getByText("Settings"));
40+
expect(onFinished).toHaveBeenCalled();
41+
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
42+
action: Action.ViewUserSettings,
43+
initialTabId: UserTab.Security,
44+
});
45+
});
46+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<IntegrationsDisabledDialog /> should render as expected 1`] = `
4+
<DocumentFragment>
5+
<div
6+
data-focus-guard="true"
7+
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
8+
tabindex="0"
9+
/>
10+
<div
11+
aria-labelledby="mx_BaseDialog_title"
12+
class="mx_IntegrationsDisabledDialog mx_Dialog_fixedWidth"
13+
data-focus-lock-disabled="false"
14+
role="dialog"
15+
tabindex="-1"
16+
>
17+
<div
18+
class="mx_Dialog_header"
19+
>
20+
<h1
21+
class="mx_Heading_h3 mx_Dialog_title"
22+
id="mx_BaseDialog_title"
23+
>
24+
Integrations are disabled
25+
</h1>
26+
</div>
27+
<div
28+
class="mx_IntegrationsDisabledDialog_content"
29+
>
30+
<p>
31+
Enable 'Manage integrations' in Settings to do this.
32+
</p>
33+
</div>
34+
<div
35+
class="mx_Dialog_buttons"
36+
>
37+
<span
38+
class="mx_Dialog_buttons_row"
39+
>
40+
<button
41+
data-testid="dialog-cancel-button"
42+
type="button"
43+
>
44+
OK
45+
</button>
46+
<button
47+
class="mx_Dialog_primary"
48+
data-testid="dialog-primary-button"
49+
type="button"
50+
>
51+
Settings
52+
</button>
53+
</span>
54+
</div>
55+
<div
56+
aria-label="Close dialog"
57+
class="mx_AccessibleButton mx_Dialog_cancelButton"
58+
role="button"
59+
tabindex="0"
60+
/>
61+
</div>
62+
<div
63+
data-focus-guard="true"
64+
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
65+
tabindex="0"
66+
/>
67+
</DocumentFragment>
68+
`;

0 commit comments

Comments
 (0)