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
This commit is contained in:
parent
285847560b
commit
706a42f390
4 changed files with 72 additions and 5 deletions
|
@ -31,6 +31,7 @@ export interface IDevtoolsProps {
|
|||
interface IMinProps extends Pick<IDevtoolsProps, "onBack"> {
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
extraButton?: ReactNode;
|
||||
}
|
||||
|
||||
interface IProps extends IMinProps {
|
||||
|
@ -38,7 +39,14 @@ interface IProps extends IMinProps {
|
|||
onAction(): Promise<string | void>;
|
||||
}
|
||||
|
||||
const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({ className, actionLabel, onBack, onAction, children }) => {
|
||||
const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({
|
||||
className,
|
||||
actionLabel,
|
||||
onBack,
|
||||
onAction,
|
||||
children,
|
||||
extraButton,
|
||||
}) => {
|
||||
const [message, setMessage] = useState<string | null>(null);
|
||||
|
||||
const onBackClick = (): void => {
|
||||
|
@ -68,6 +76,7 @@ const BaseTool: React.FC<XOR<IMinProps, IProps>> = ({ className, actionLabel, on
|
|||
<>
|
||||
<div className={classNames("mx_DevTools_content", className)}>{children}</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
{extraButton}
|
||||
<button onClick={onBackClick}>{_t("Back")}</button>
|
||||
{actionButton}
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, useContext, useMemo, useRef, useState } from "react";
|
||||
import React, { ChangeEvent, ReactNode, useContext, useMemo, useRef, useState } from "react";
|
||||
import { IContent, MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
import { _t, _td } from "../../../../languageHandler";
|
||||
|
@ -143,9 +143,10 @@ export interface IEditorProps extends Pick<IDevtoolsProps, "onBack"> {
|
|||
|
||||
interface IViewerProps extends Required<IEditorProps> {
|
||||
Editor: React.FC<IEditorProps>;
|
||||
extraButton?: ReactNode;
|
||||
}
|
||||
|
||||
export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor }) => {
|
||||
export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor, extraButton }) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
|
||||
if (editing) {
|
||||
|
@ -160,7 +161,7 @@ export const EventViewer: React.FC<IViewerProps> = ({ mxEvent, onBack, Editor })
|
|||
};
|
||||
|
||||
return (
|
||||
<BaseTool onBack={onBack} actionLabel={_t("Edit")} onAction={onAction}>
|
||||
<BaseTool onBack={onBack} actionLabel={_t("Edit")} onAction={onAction} extraButton={extraButton}>
|
||||
<SyntaxHighlight language="json">{stringify(mxEvent.event)}</SyntaxHighlight>
|
||||
</BaseTool>
|
||||
);
|
||||
|
|
|
@ -24,6 +24,9 @@ import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
|||
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
||||
import { EventEditor, EventViewer, eventTypeField, stateKeyField, IEditorProps, stringify } from "./Event";
|
||||
import FilteredList from "./FilteredList";
|
||||
import Spinner from "../../elements/Spinner";
|
||||
import SyntaxHighlight from "../../elements/SyntaxHighlight";
|
||||
import { useAsyncMemo } from "../../../../hooks/useAsyncMemo";
|
||||
|
||||
export const StateEventEditor: React.FC<IEditorProps> = ({ mxEvent, onBack }) => {
|
||||
const context = useContext(DevtoolsContext);
|
||||
|
@ -47,6 +50,48 @@ interface StateEventButtonProps {
|
|||
onClick(): void;
|
||||
}
|
||||
|
||||
const RoomStateHistory: React.FC<{
|
||||
mxEvent: MatrixEvent;
|
||||
onBack(): void;
|
||||
}> = ({ mxEvent, onBack }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const events = useAsyncMemo(
|
||||
async () => {
|
||||
const events = [mxEvent.event];
|
||||
while (!!events[0].unsigned?.replaces_state) {
|
||||
try {
|
||||
events.unshift(await cli.fetchRoomEvent(mxEvent.getRoomId()!, events[0].unsigned.replaces_state));
|
||||
} catch (e) {
|
||||
events.unshift({
|
||||
event_id: events[0].unsigned.replaces_state,
|
||||
unsigned: {
|
||||
error: e instanceof Error ? e.message : String(e),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
return events;
|
||||
},
|
||||
[cli, mxEvent],
|
||||
null,
|
||||
);
|
||||
|
||||
let body = <Spinner />;
|
||||
if (events !== null) {
|
||||
body = (
|
||||
<>
|
||||
{events.map((ev) => (
|
||||
<SyntaxHighlight language="json" key={ev.event_id}>
|
||||
{stringify(ev)}
|
||||
</SyntaxHighlight>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <BaseTool onBack={onBack}>{body}</BaseTool>;
|
||||
};
|
||||
|
||||
const StateEventButton: React.FC<StateEventButtonProps> = ({ label, onClick }) => {
|
||||
const trimmed = label.trim();
|
||||
|
||||
|
@ -71,6 +116,7 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
|
|||
const context = useContext(DevtoolsContext);
|
||||
const [query, setQuery] = useState("");
|
||||
const [event, setEvent] = useState<MatrixEvent | null>(null);
|
||||
const [history, setHistory] = useState(false);
|
||||
|
||||
const events = context.room.currentState.events.get(eventType)!;
|
||||
|
||||
|
@ -82,6 +128,12 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
|
|||
}
|
||||
}, [events]);
|
||||
|
||||
if (event && history) {
|
||||
const _onBack = (): void => {
|
||||
setHistory(false);
|
||||
};
|
||||
return <RoomStateHistory mxEvent={event} onBack={_onBack} />;
|
||||
}
|
||||
if (event) {
|
||||
const _onBack = (): void => {
|
||||
if (events?.size === 1 && events.has("")) {
|
||||
|
@ -90,7 +142,11 @@ const RoomStateExplorerEventType: React.FC<IEventTypeProps> = ({ eventType, onBa
|
|||
setEvent(null);
|
||||
}
|
||||
};
|
||||
return <EventViewer mxEvent={event} onBack={_onBack} Editor={StateEventEditor} />;
|
||||
const onHistoryClick = (): void => {
|
||||
setHistory(true);
|
||||
};
|
||||
const extraButton = <button onClick={onHistoryClick}>{_t("See history")}</button>;
|
||||
return <EventViewer mxEvent={event} onBack={_onBack} Editor={StateEventEditor} extraButton={extraButton} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -3224,6 +3224,7 @@
|
|||
"<%(count)s spaces>|other": "<%(count)s spaces>",
|
||||
"<%(count)s spaces>|one": "<space>",
|
||||
"<%(count)s spaces>|zero": "<empty string>",
|
||||
"See history": "See history",
|
||||
"Send custom state event": "Send custom state event",
|
||||
"Capabilities": "Capabilities",
|
||||
"Failed to load.": "Failed to load.",
|
||||
|
|
Loading…
Reference in a new issue