Skip to content

Commit 343d59c

Browse files
authored
Merge pull request #373 from TypeCellOS/staging
add devtools
2 parents f5e4abc + 4029b91 commit 343d59c

File tree

9 files changed

+318
-28
lines changed

9 files changed

+318
-28
lines changed

package-lock.json

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/editor/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"mobx-react-lite": "^3.2.0",
4747
"penpal": "^6.1.0",
4848
"react": "^18.2.0",
49+
"react-rnd": "^10.4.1",
4950
"react-avatar": "^5.0.3",
5051
"react-dnd": "^14.0.2",
5152
"react-dnd-html5-backend": "^14.0.0",
@@ -57,7 +58,8 @@
5758
"web-vitals": "^1.0.1",
5859
"y-indexeddb": "9.0.6",
5960
"y-protocols": "^1.0.5",
60-
"yjs": "^13.6.4"
61+
"yjs": "^13.6.4",
62+
"react-inspector": "^6.0.1"
6163
},
6264
"scripts": {
6365
"copytypes:self": "tsc --declaration --emitDeclarationOnly --noEmit false --composite false --declarationDir ./public/types/@typecell-org/editor",
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
.devtools {
2+
/* position: absolute;
3+
right: 0;
4+
top: 100px;
5+
left: 100px;
6+
right: 100px;
7+
bottom: 50px; */
8+
/* width: 400px; */
9+
/* border: 1px solid black; */
10+
/* height: 100%; */
11+
background: white;
12+
opacity: 0.95;
13+
z-index: 99999999;
14+
border: 1px solid #f3f1f3;
15+
height: 100%;
16+
width: 100%;
17+
}
18+
19+
.devtools h1 {
20+
margin-bottom: 0.5em;
21+
}
22+
23+
.devtools label {
24+
margin-bottom: 1em;
25+
}
26+
27+
.selectContainer {
28+
width: 500px;
29+
margin-bottom: 0.5em;
30+
}
31+
32+
.content {
33+
padding: 10px;
34+
}
35+
.tableContainer th:nth-child(1),
36+
.tableContainer td:nth-child(1) {
37+
width: 50px;
38+
}
39+
40+
.tableContainer th:nth-child(2),
41+
.tableContainer td:nth-child(2) {
42+
width: 300px;
43+
}
44+
45+
.header {
46+
padding: 10px 5px;
47+
background-color: #f6f6f6;
48+
height: 30px;
49+
/* border-top: 1px solid #f3f1f3; */
50+
/* border-bottom: 1px solid #b1aeb1; */
51+
border-top-left-radius: 6px;
52+
border-top-right-radius: 6px;
53+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import Select from "@atlaskit/select";
2+
import { observer } from "mobx-react-lite";
3+
import { useEffect, useRef, useState } from "react";
4+
import { Inspector } from "react-inspector";
5+
import { Rnd } from "react-rnd";
6+
import { DocConnection } from "../../store/DocConnection";
7+
import { SessionStore } from "../../store/local/SessionStore";
8+
import { DocumentInfo } from "../../store/yjs-sync/DocumentCoordinator";
9+
import { TypeCellRemote } from "../../store/yjs-sync/remote/TypeCellRemote";
10+
import styles from "./DevTools.module.css";
11+
12+
export const DevTools = observer((props: { sessionStore: SessionStore }) => {
13+
const [offline, setOffline] = useState(false);
14+
const [flaky, setFlaky] = useState(false);
15+
const flakyInterval = useRef<ReturnType<typeof setInterval> | undefined>(
16+
undefined,
17+
);
18+
19+
useEffect(() => {
20+
TypeCellRemote.Offline = offline;
21+
}, [offline]);
22+
23+
useEffect(() => {
24+
clearInterval(flakyInterval.current);
25+
if (flaky) {
26+
flakyInterval.current = setInterval(() => {
27+
setOffline((o) => !o);
28+
}, 5000);
29+
}
30+
}, [flaky]);
31+
32+
const [selectedResource, setSelectedResource] = useState<
33+
string | undefined
34+
>();
35+
36+
const [onlyLoaded, setOnlyLoaded] = useState(true);
37+
38+
if (!props.sessionStore.documentCoordinator) {
39+
return <div>Loading</div>;
40+
}
41+
42+
let documentCoordinatorEntries = [
43+
...(props.sessionStore.documentCoordinator.documents.entries() as IterableIterator<
44+
[string, DocumentInfo]
45+
>),
46+
].map(([key, value]) => {
47+
const resource = DocConnection.get(key, props.sessionStore);
48+
return {
49+
// id: key,
50+
...value,
51+
loaded: props.sessionStore.documentCoordinator?.loadedDocuments.has(key),
52+
created_at: new Date(value.created_at),
53+
needs_save_since: value.needs_save_since
54+
? new Date(value.needs_save_since)
55+
: undefined,
56+
type: resource?.tryDoc?.type,
57+
title:
58+
resource?.tryDoc?.type === "!richtext"
59+
? resource?.tryDoc.doc.title
60+
: resource?.tryDoc?.title,
61+
};
62+
});
63+
64+
if (onlyLoaded) {
65+
documentCoordinatorEntries = documentCoordinatorEntries.filter(
66+
(d) => d.loaded,
67+
);
68+
}
69+
70+
const selectOptions = documentCoordinatorEntries
71+
.filter((d) => d.loaded)
72+
.map((d) => ({
73+
label: d.title + " (" + d.id + ")",
74+
value: d.id,
75+
}));
76+
// const resourceEntries = [...cache.entries()].map(([key, value]) => {
77+
// return {
78+
// id: key,
79+
// identifier: value.identifier.toString(),
80+
// type: value.tryDoc?.type,
81+
// title: value.tryDoc?.title,
82+
// ydoc: JSON.stringify(value.tryDoc?.ydoc.toJSON()),
83+
// };
84+
// });
85+
86+
const ydoc = selectedResource
87+
? DocConnection.get(
88+
selectedResource,
89+
props.sessionStore,
90+
)?.tryDoc?.ydoc.toJSON()
91+
: undefined;
92+
93+
return (
94+
<Rnd
95+
style={{ zIndex: 19999000 }}
96+
default={{
97+
x: 50,
98+
y: 50,
99+
width: window.innerWidth - 100,
100+
height: window.innerHeight - 100,
101+
}}
102+
dragHandleClassName={styles.header}>
103+
<div className={styles.devtools}>
104+
<div className={styles.header}>DevTools</div>
105+
<div className={styles.content}>
106+
<h1>Network</h1>
107+
<label>
108+
<input
109+
type="checkbox"
110+
onChange={(e) => {
111+
setFlaky(false);
112+
setOffline(e.target.checked);
113+
}}
114+
checked={offline}
115+
/>{" "}
116+
Offline
117+
</label>
118+
<label>
119+
<input
120+
type="checkbox"
121+
onChange={(e) => setFlaky(e.target.checked)}
122+
checked={flaky}
123+
/>{" "}
124+
Flaky (offline / online every 5s)
125+
</label>
126+
<h1>Documents</h1>
127+
<div className={styles.tableContainer}>
128+
<label>
129+
<input
130+
type="checkbox"
131+
onChange={(e) => setOnlyLoaded(e.target.checked)}
132+
checked={onlyLoaded}
133+
/>{" "}
134+
Only show loaded
135+
</label>
136+
<Inspector
137+
className="test"
138+
table={true}
139+
data={documentCoordinatorEntries}
140+
/>
141+
</div>
142+
<h1>Resources</h1>
143+
<div className={styles.selectContainer}>
144+
<Select
145+
// cacheOptions
146+
// onChange={onChange}
147+
// loadOptions={searchUsers}
148+
// menuPosition="fixed"
149+
backspaceRemovesValue
150+
isClearable
151+
placeholder="Select resource…"
152+
onChange={(v) => setSelectedResource(v?.value)}
153+
options={selectOptions}
154+
/>
155+
</div>
156+
{selectedResource && <Inspector table={false} data={ydoc} />}
157+
</div>
158+
</div>
159+
</Rnd>
160+
);
161+
});

packages/editor/src/app/main/Main.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,33 @@ import { HTML5Backend } from "react-dnd-html5-backend";
66
import { Outlet, useLocation } from "react-router-dom";
77
import { DocumentResource } from "../../store/DocumentResource";
88
import { SessionStore } from "../../store/local/SessionStore";
9+
import { DevTools } from "./DevTools";
910
import styles from "./Main.module.css";
1011
import { Navigation } from "./components/Navigation";
1112

1213
const Main = observer((props: { sessionStore: SessionStore }) => {
1314
const location = useLocation();
14-
// const navigate = useNavigate();
15-
15+
const [devToolsVisible, setDevToolsVisible] = useState(
16+
localStorage.getItem("devToolsVisible") === "true",
17+
);
18+
useEffect(() => {
19+
const listener = (e: KeyboardEvent) => {
20+
// if f9 pressed
21+
if (e.key === "F9") {
22+
if (devToolsVisible) {
23+
setDevToolsVisible(false);
24+
localStorage.removeItem("devToolsVisible");
25+
} else {
26+
setDevToolsVisible(true);
27+
localStorage.setItem("devToolsVisible", "true");
28+
}
29+
}
30+
};
31+
window.addEventListener("keydown", listener);
32+
return () => {
33+
window.removeEventListener("keydown", listener);
34+
};
35+
}, [devToolsVisible]);
1636
const [top, setTop] = useState(true);
1737

1838
const controlNavbar = useCallback(() => {
@@ -46,6 +66,8 @@ const Main = observer((props: { sessionStore: SessionStore }) => {
4666
)}>
4767
<Navigation sessionStore={props.sessionStore} />
4868
<Outlet />
69+
70+
{devToolsVisible && <DevTools sessionStore={props.sessionStore} />}
4971
</div>
5072
</DndProvider>
5173
);

packages/editor/src/app/main/components/startscreen/StartScreen.module.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,11 @@ form {
191191
}
192192

193193
.footer > div {
194-
/* grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); */
194+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
195195
padding: 90px 40px;
196196
max-width: calc(var(--vp-layout-max-width) + 16px);
197-
/* display: grid; */
198-
display: flex;
197+
display: grid;
198+
/* display: flex; */
199199
gap: 100px;
200200
margin: 0 auto;
201201
justify-content: center;
@@ -279,7 +279,7 @@ form {
279279
@media (max-width: 500px) {
280280
.header,
281281
.content {
282-
padding-left: 0;
282+
padding-left: 12px;
283283
padding-right: 12px;
284284
}
285285
}

0 commit comments

Comments
 (0)