2018-04-11 23:58:04 +01:00
|
|
|
/*
|
2024-09-09 14:57:16 +01:00
|
|
|
Copyright 2024 New Vector Ltd.
|
2023-01-30 17:01:54 +00:00
|
|
|
Copyright 2018-2023 The Matrix.org Foundation C.I.C.
|
2024-09-09 14:57:16 +01:00
|
|
|
Copyright 2022 Michael Telatynski <7t3chguy@gmail.com>
|
2018-04-11 23:58:04 +01:00
|
|
|
|
2025-01-06 11:18:54 +00:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
2024-09-09 14:57:16 +01:00
|
|
|
Please see LICENSE files in the repository root for full details.
|
2018-04-11 23:58:04 +01:00
|
|
|
*/
|
|
|
|
|
|
2025-03-27 10:43:58 +00:00
|
|
|
import React, { type JSX, useState } from "react";
|
2025-12-04 15:46:21 +00:00
|
|
|
import { Form } from "@vector-im/compound-web";
|
2021-10-22 17:23:32 -05:00
|
|
|
|
2026-01-07 11:49:01 +00:00
|
|
|
import { _t, _td } from "../../../languageHandler";
|
2021-10-22 17:23:32 -05:00
|
|
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
2021-07-02 17:19:01 +02:00
|
|
|
import BaseDialog from "./BaseDialog";
|
2022-03-23 20:17:57 +00:00
|
|
|
import { TimelineEventEditor } from "./devtools/Event";
|
|
|
|
|
import ServersInRoom from "./devtools/ServersInRoom";
|
|
|
|
|
import SettingExplorer from "./devtools/SettingExplorer";
|
|
|
|
|
import { RoomStateExplorer } from "./devtools/RoomState";
|
2025-02-05 13:25:06 +00:00
|
|
|
import BaseTool, { DevtoolsContext, type IDevtoolsProps } from "./devtools/BaseTool";
|
2022-03-23 20:17:57 +00:00
|
|
|
import WidgetExplorer from "./devtools/WidgetExplorer";
|
2025-10-28 16:18:10 -04:00
|
|
|
import { UserList } from "./devtools/Users";
|
2022-03-23 20:17:57 +00:00
|
|
|
import { AccountDataExplorer, RoomAccountDataExplorer } from "./devtools/AccountData";
|
|
|
|
|
import SettingsFlag from "../elements/SettingsFlag";
|
|
|
|
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
|
|
|
|
import ServerInfo from "./devtools/ServerInfo";
|
2023-01-30 17:01:54 +00:00
|
|
|
import CopyableText from "../elements/CopyableText";
|
2023-02-03 10:07:24 +00:00
|
|
|
import RoomNotifications from "./devtools/RoomNotifications";
|
2025-01-24 11:51:27 +01:00
|
|
|
import { Crypto } from "./devtools/Crypto";
|
2025-03-28 20:34:32 +00:00
|
|
|
import SettingsField from "../elements/SettingsField.tsx";
|
2026-03-16 11:54:16 +01:00
|
|
|
import { StickyStateExplorer } from "./devtools/StickyEventState.tsx";
|
2020-02-21 17:15:53 +00:00
|
|
|
|
2022-03-23 20:17:57 +00:00
|
|
|
enum Category {
|
|
|
|
|
Room,
|
|
|
|
|
Other,
|
2021-05-18 15:20:08 +01:00
|
|
|
}
|
2018-04-11 23:58:04 +01:00
|
|
|
|
2023-08-22 16:32:05 +01:00
|
|
|
const categoryLabels: Record<Category, TranslationKey> = {
|
2023-09-05 17:52:06 +01:00
|
|
|
[Category.Room]: _td("devtools|category_room"),
|
|
|
|
|
[Category.Other]: _td("devtools|category_other"),
|
2020-02-24 10:17:33 +00:00
|
|
|
};
|
2020-02-21 17:15:53 +00:00
|
|
|
|
2023-02-03 10:07:24 +00:00
|
|
|
export type Tool = React.FC<IDevtoolsProps> | ((props: IDevtoolsProps) => JSX.Element);
|
2023-08-22 16:32:05 +01:00
|
|
|
const Tools: Record<Category, [label: TranslationKey, tool: Tool][]> = {
|
2022-03-23 20:17:57 +00:00
|
|
|
[Category.Room]: [
|
2023-09-04 10:20:34 +01:00
|
|
|
[_td("devtools|send_custom_timeline_event"), TimelineEventEditor],
|
|
|
|
|
[_td("devtools|explore_room_state"), RoomStateExplorer],
|
|
|
|
|
[_td("devtools|explore_room_account_data"), RoomAccountDataExplorer],
|
|
|
|
|
[_td("devtools|view_servers_in_room"), ServersInRoom],
|
|
|
|
|
[_td("devtools|notifications_debug"), RoomNotifications],
|
|
|
|
|
[_td("devtools|active_widgets"), WidgetExplorer],
|
2025-10-28 16:18:10 -04:00
|
|
|
[_td("devtools|users"), UserList],
|
2026-03-16 11:54:16 +01:00
|
|
|
[_td("devtools|explore_sticky_state"), StickyStateExplorer],
|
2022-03-23 20:17:57 +00:00
|
|
|
],
|
|
|
|
|
[Category.Other]: [
|
2023-09-04 10:20:34 +01:00
|
|
|
[_td("devtools|explore_account_data"), AccountDataExplorer],
|
|
|
|
|
[_td("devtools|settings_explorer"), SettingExplorer],
|
|
|
|
|
[_td("devtools|server_info"), ServerInfo],
|
2025-01-24 11:51:27 +01:00
|
|
|
[_td("devtools|crypto|title"), Crypto],
|
2022-03-23 20:17:57 +00:00
|
|
|
],
|
2021-06-29 13:11:58 +01:00
|
|
|
};
|
2020-02-21 17:15:53 +00:00
|
|
|
|
2021-05-18 15:20:08 +01:00
|
|
|
interface IProps {
|
|
|
|
|
roomId: string;
|
2023-07-07 08:40:25 -06:00
|
|
|
threadRootId?: string | null;
|
2026-02-23 15:37:58 +00:00
|
|
|
onFinished(this: void, finished?: boolean): void;
|
2021-05-18 15:20:08 +01:00
|
|
|
}
|
2018-04-11 23:58:04 +01:00
|
|
|
|
2023-10-11 23:21:03 +01:00
|
|
|
type ToolInfo = [label: TranslationKey, tool: Tool];
|
2021-05-18 15:20:08 +01:00
|
|
|
|
2023-07-07 08:40:25 -06:00
|
|
|
const DevtoolsDialog: React.FC<IProps> = ({ roomId, threadRootId, onFinished }) => {
|
2023-03-27 08:01:09 +01:00
|
|
|
const [tool, setTool] = useState<ToolInfo | null>(null);
|
2018-04-11 23:58:04 +01:00
|
|
|
|
2022-03-23 20:17:57 +00:00
|
|
|
let body: JSX.Element;
|
|
|
|
|
let onBack: () => void;
|
|
|
|
|
|
|
|
|
|
if (tool) {
|
|
|
|
|
onBack = () => {
|
|
|
|
|
setTool(null);
|
2018-04-11 23:58:04 +01:00
|
|
|
};
|
|
|
|
|
|
2022-03-23 20:17:57 +00:00
|
|
|
const Tool = tool[1];
|
|
|
|
|
body = <Tool onBack={onBack} setTool={(label, tool) => setTool([label, tool])} />;
|
|
|
|
|
} else {
|
2023-01-12 13:25:14 +00:00
|
|
|
const onBack = (): void => {
|
2022-03-23 20:17:57 +00:00
|
|
|
onFinished(false);
|
2018-04-11 23:58:04 +01:00
|
|
|
};
|
2022-03-23 20:17:57 +00:00
|
|
|
body = (
|
|
|
|
|
<BaseTool onBack={onBack}>
|
|
|
|
|
{Object.entries(Tools).map(([category, tools]) => (
|
|
|
|
|
<div key={category}>
|
2025-09-04 08:12:24 +01:00
|
|
|
<h2 className="mx_DevTools_toolHeading">
|
|
|
|
|
{_t(categoryLabels[category as unknown as Category])}
|
|
|
|
|
</h2>
|
2022-03-23 20:17:57 +00:00
|
|
|
{tools.map(([label, tool]) => {
|
2023-01-12 13:25:14 +00:00
|
|
|
const onClick = (): void => {
|
2022-03-23 20:17:57 +00:00
|
|
|
setTool([label, tool]);
|
|
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
<button className="mx_DevTools_button" key={label} onClick={onClick}>
|
|
|
|
|
{_t(label)}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
2022-12-12 12:24:14 +01:00
|
|
|
</div>
|
|
|
|
|
))}
|
2025-12-04 15:46:21 +00:00
|
|
|
<Form.Root
|
|
|
|
|
onSubmit={(evt) => {
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
evt.stopPropagation();
|
|
|
|
|
}}
|
|
|
|
|
className="mx_DevTools_toggleForm"
|
|
|
|
|
>
|
2025-09-04 08:12:24 +01:00
|
|
|
<h2 className="mx_DevTools_toolHeading">{_t("common|options")}</h2>
|
2022-03-23 20:17:57 +00:00
|
|
|
<SettingsFlag name="developerMode" level={SettingLevel.ACCOUNT} />
|
|
|
|
|
<SettingsFlag name="showHiddenEventsInTimeline" level={SettingLevel.DEVICE} />
|
2022-05-06 13:05:01 -06:00
|
|
|
<SettingsFlag name="enableWidgetScreenshots" level={SettingLevel.ACCOUNT} />
|
2026-04-07 13:16:35 +01:00
|
|
|
<SettingsFlag name="lowBandwidth" level={SettingLevel.DEVICE} />
|
2025-12-04 15:46:21 +00:00
|
|
|
</Form.Root>
|
2025-12-05 14:45:18 +01:00
|
|
|
{/* The settings field needs to be outside `Form.Root` because `SettingsField` will have a inner Form,
|
|
|
|
|
Otherwise we end up with a nester `Form` and that prohibits `preventDefault` so setting the value
|
|
|
|
|
will reload the page.
|
|
|
|
|
*/}
|
|
|
|
|
<SettingsField
|
|
|
|
|
settingKey="Developer.elementCallUrl"
|
|
|
|
|
level={SettingLevel.DEVICE}
|
|
|
|
|
aria-label="elementCallUrl"
|
|
|
|
|
/>
|
2022-03-23 20:17:57 +00:00
|
|
|
</BaseTool>
|
|
|
|
|
);
|
2018-04-11 23:58:04 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-11 23:21:03 +01:00
|
|
|
const label = tool ? _t(tool[0]) : _t("devtools|toolbox");
|
2022-03-23 20:17:57 +00:00
|
|
|
return (
|
2023-09-04 10:20:34 +01:00
|
|
|
<BaseDialog className="mx_QuestionDialog" onFinished={onFinished} title={_t("devtools|developer_tools")}>
|
2022-03-23 20:17:57 +00:00
|
|
|
<MatrixClientContext.Consumer>
|
|
|
|
|
{(cli) => (
|
|
|
|
|
<>
|
|
|
|
|
<div className="mx_DevTools_label_left">{label}</div>
|
2023-01-30 17:01:54 +00:00
|
|
|
<CopyableText className="mx_DevTools_label_right" getTextToCopy={() => roomId} border={false}>
|
2023-09-04 10:20:34 +01:00
|
|
|
{_t("devtools|room_id", { roomId })}
|
2023-01-30 17:01:54 +00:00
|
|
|
</CopyableText>
|
2023-07-07 08:40:25 -06:00
|
|
|
{!threadRootId ? null : (
|
|
|
|
|
<CopyableText
|
|
|
|
|
className="mx_DevTools_label_right"
|
|
|
|
|
getTextToCopy={() => threadRootId}
|
|
|
|
|
border={false}
|
|
|
|
|
>
|
2023-09-04 10:20:34 +01:00
|
|
|
{_t("devtools|thread_root_id", { threadRootId })}
|
2023-07-07 08:40:25 -06:00
|
|
|
</CopyableText>
|
|
|
|
|
)}
|
2018-04-11 23:58:04 +01:00
|
|
|
<div className="mx_DevTools_label_bottom" />
|
2023-01-30 17:01:54 +00:00
|
|
|
{cli.getRoom(roomId) && (
|
2023-07-07 08:40:25 -06:00
|
|
|
<DevtoolsContext.Provider value={{ room: cli.getRoom(roomId)!, threadRootId }}>
|
2023-01-30 17:01:54 +00:00
|
|
|
{body}
|
|
|
|
|
</DevtoolsContext.Provider>
|
|
|
|
|
)}
|
2022-03-23 20:17:57 +00:00
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</MatrixClientContext.Consumer>
|
|
|
|
|
</BaseDialog>
|
|
|
|
|
);
|
|
|
|
|
};
|
2018-04-11 23:58:04 +01:00
|
|
|
|
2022-03-23 20:17:57 +00:00
|
|
|
export default DevtoolsDialog;
|