Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 706a42f

Browse files
authored
Quick and dirty devtool to explore state history (#11197)
* Quick and dirty devtool to explore state history * Include error in unsigned * iterate * Fix silly copy paste
1 parent 2858475 commit 706a42f

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

src/components/views/dialogs/devtools/BaseTool.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,22 @@ export interface IDevtoolsProps {
3131
interface IMinProps extends Pick<IDevtoolsProps, "onBack"> {
3232
className?: string;
3333
children?: ReactNode;
34+
extraButton?: ReactNode;
3435
}
3536

3637
interface IProps extends IMinProps {
3738
actionLabel: string;
3839
onAction(): Promise<string | void>;
3940
}
4041

41-
const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({ className, actionLabel, onBack, onAction, children }) => {
42+
const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({
43+
className,
44+
actionLabel,
45+
onBack,
46+
onAction,
47+
children,
48+
extraButton,
49+
}) => {
4250
const [message, setMessage] = useState<string | null>(null);
4351

4452
const onBackClick = (): void => {
@@ -68,6 +76,7 @@ const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({ className, actionLabel, on
6876
<>
6977
<div className={classNames("mx_DevTools_content", className)}>{children}</div>
7078
<div className="mx_Dialog_buttons">
79+
{extraButton}
7180
<button onClick={onBackClick}>{_t("Back")}</button>
7281
{actionButton}
7382
</div>

src/components/views/dialogs/devtools/Event.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
1515
limitations under the License.
1616
*/
1717

18-
import React, { ChangeEvent, useContext, useMemo, useRef, useState } from "react";
18+
import React, { ChangeEvent, ReactNode, useContext, useMemo, useRef, useState } from "react";
1919
import { IContent, MatrixEvent } from "matrix-js-sdk/src/models/event";
2020

2121
import { _t, _td } from "../../../../languageHandler";
@@ -143,9 +143,10 @@ export interface IEditorProps extends Pick<IDevtoolsProps, "onBack"> {
143143

144144
interface IViewerProps extends Required<IEditorProps> {
145145
Editor: React.FC<IEditorProps>;
146+
extraButton?: ReactNode;
146147
}
147148

148-
export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor }) => {
149+
export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor, extraButton }) => {
149150
const [editing, setEditing] = useState(false);
150151

151152
if (editing) {
@@ -160,7 +161,7 @@ export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor })
160161
};
161162

162163
return (
163-
<BaseTool onBack={onBack} actionLabel={_t("Edit")} onAction={onAction}>
164+
<BaseTool onBack={onBack} actionLabel={_t("Edit")} onAction={onAction} extraButton={extraButton}>
164165
<SyntaxHighlight language="json">{stringify(mxEvent.event)}</SyntaxHighlight>
165166
</BaseTool>
166167
);

src/components/views/dialogs/devtools/RoomState.tsx

+57-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
2424
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
2525
import { EventEditor, EventViewer, eventTypeField, stateKeyField, IEditorProps, stringify } from "./Event";
2626
import FilteredList from "./FilteredList";
27+
import Spinner from "../../elements/Spinner";
28+
import SyntaxHighlight from "../../elements/SyntaxHighlight";
29+
import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
2730

2831
export const StateEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack }) => {
2932
const context = useContext(DevtoolsContext);
@@ -47,6 +50,48 @@ interface StateEventButtonProps {
4750
onClick(): void;
4851
}
4952

53+
const RoomStateHistory: React.FC<{
54+
mxEvent: MatrixEvent;
55+
onBack(): void;
56+
}> = ({ mxEvent, onBack }) => {
57+
const cli = useContext(MatrixClientContext);
58+
const events = useAsyncMemo(
59+
async () => {
60+
const events = [mxEvent.event];
61+
while (!!events[0].unsigned?.replaces_state) {
62+
try {
63+
events.unshift(await cli.fetchRoomEvent(mxEvent.getRoomId()!, events[0].unsigned.replaces_state));
64+
} catch (e) {
65+
events.unshift({
66+
event_id: events[0].unsigned.replaces_state,
67+
unsigned: {
68+
error: e instanceof Error ? e.message : String(e),
69+
},
70+
});
71+
}
72+
}
73+
return events;
74+
},
75+
[cli, mxEvent],
76+
null,
77+
);
78+
79+
let body = <Spinner />;
80+
if (events !== null) {
81+
body = (
82+
<>
83+
{events.map((ev) => (
84+
<SyntaxHighlight language="json" key={ev.event_id}>
85+
{stringify(ev)}
86+
</SyntaxHighlight>
87+
))}
88+
</>
89+
);
90+
}
91+
92+
return <BaseTool onBack={onBack}>{body}</BaseTool>;
93+
};
94+
5095
const StateEventButton: React.FC<StateEventButtonProps> = ({ label, onClick }) => {
5196
const trimmed = label.trim();
5297

@@ -71,6 +116,7 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
71116
const context = useContext(DevtoolsContext);
72117
const [query, setQuery] = useState("");
73118
const [event, setEvent] = useState<MatrixEvent | null>(null);
119+
const [history, setHistory] = useState(false);
74120

75121
const events = context.room.currentState.events.get(eventType)!;
76122

@@ -82,6 +128,12 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
82128
}
83129
}, [events]);
84130

131+
if (event && history) {
132+
const _onBack = (): void => {
133+
setHistory(false);
134+
};
135+
return <RoomStateHistory mxEvent={event} onBack={_onBack} />;
136+
}
85137
if (event) {
86138
const _onBack = (): void => {
87139
if (events?.size === 1 && events.has("")) {
@@ -90,7 +142,11 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
90142
setEvent(null);
91143
}
92144
};
93-
return <EventViewer mxEvent={event} onBack={_onBack} Editor={StateEventEditor} />;
145+
const onHistoryClick = (): void => {
146+
setHistory(true);
147+
};
148+
const extraButton = <button onClick={onHistoryClick}>{_t("See history")}</button>;
149+
return <EventViewer mxEvent={event} onBack={_onBack} Editor={StateEventEditor} extraButton={extraButton} />;
94150
}
95151

96152
return (

src/i18n/strings/en_EN.json

+1
Original file line numberDiff line numberDiff line change
@@ -3224,6 +3224,7 @@
32243224
"<%(count)s spaces>|other": "<%(count)s spaces>",
32253225
"<%(count)s spaces>|one": "<space>",
32263226
"<%(count)s spaces>|zero": "<empty string>",
3227+
"See history": "See history",
32273228
"Send custom state event": "Send custom state event",
32283229
"Capabilities": "Capabilities",
32293230
"Failed to load.": "Failed to load.",

0 commit comments

Comments
 (0)