From 4cd3b4c4e84e36f89cf1098a866008fc999d15ab Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 30 Sep 2022 16:26:57 +0100 Subject: [PATCH 1/6] add react-virtualised --- cli/.vscode/settings.json | 3 + cli/app/index.html | 2 +- cli/app/src/components/Factory/Factory.css | 4 +- .../GraphInspector/GraphInspector.tsx | 80 ++++++------- .../GraphInspector/RowVirtualizerDynamic.tsx | 108 ++++++++++++++++++ .../components/GraphInspector/graphReducer.ts | 12 +- .../src/components/GraphInspector/types.ts | 11 ++ cli/app/src/css/global.css | 5 +- cli/app/src/index.tsx | 5 +- cli/graphql/server.ts | 6 +- cli/package-lock.json | 104 +++++++++++++++++ cli/package.json | 5 +- cli/vite.config.ts | 2 +- 13 files changed, 279 insertions(+), 68 deletions(-) create mode 100644 cli/.vscode/settings.json create mode 100644 cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx diff --git a/cli/.vscode/settings.json b/cli/.vscode/settings.json new file mode 100644 index 0000000..035012d --- /dev/null +++ b/cli/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deno.enable": false +} \ No newline at end of file diff --git a/cli/app/index.html b/cli/app/index.html index b9d745b..c32d059 100644 --- a/cli/app/index.html +++ b/cli/app/index.html @@ -9,7 +9,7 @@ -
+
\ No newline at end of file diff --git a/cli/app/src/components/Factory/Factory.css b/cli/app/src/components/Factory/Factory.css index afc0254..7ccc1a8 100644 --- a/cli/app/src/components/Factory/Factory.css +++ b/cli/app/src/components/Factory/Factory.css @@ -1,6 +1,6 @@ -#main { +main { display: grid; - grid-template-rows: [top] 2.125rem [main] 1fr; + grid-template-rows: [top] 2.125rem [main] auto; } .app { diff --git a/cli/app/src/components/GraphInspector/GraphInspector.tsx b/cli/app/src/components/GraphInspector/GraphInspector.tsx index 6625c82..886d9f4 100644 --- a/cli/app/src/components/GraphInspector/GraphInspector.tsx +++ b/cli/app/src/components/GraphInspector/GraphInspector.tsx @@ -9,25 +9,29 @@ import { VertexNode } from "../../../../graphql/types"; import { MinusSquare, PlusSquare } from "./icons"; import { StyledTreeItem } from "./StyledTreeItem"; import { fetchGraphQL } from "../../graphql/fetchGraphql"; -import { Loader } from "../Loader/Loader"; import { useQuery } from 'urql'; import type { Page } from '../../../../graphql/relay'; +import { RowVirtualizerDynamic } from './RowVirtualizerDynamic'; +import useBoundingclientrectRef from '@rooks/use-boundingclientrect-ref'; + const emptyGraph = { graph: {} }; const limit = 5; export function GraphInspector(): JSX.Element { - // TODO: call setAfter when scrolling - const [after] = useState(''); + const [after, setAfter] = useState(''); const [typename, setTypename] = useState(); + const [expanderRef, boundingClientRect] = useBoundingclientrectRef(); + const height = Math.round(boundingClientRect?.height); + const [result] = useQuery<{ all: Page }, { typename: string; first: number; after: string; }>({ query: allQuery, - pause: !typename, + pause: !typename && !after, variables: { typename, first: limit, @@ -36,9 +40,8 @@ export function GraphInspector(): JSX.Element { }); const [{ graph }, dispatch] = useReducer(graphReducer, emptyGraph); - const expandedNodes = useRef(new Set()); - const { data, error } = result; + const { data, error, fetching } = result; useEffect(() => { const edges = data?.all?.edges ?? []; @@ -64,13 +67,6 @@ export function GraphInspector(): JSX.Element { const nodeId = nodeIds[0]; - if (expandedNodes.current.has(nodeId)) { - console.log(`${nodeId} has previously been opened`); - return; - } - - expandedNodes.current.add(nodeId); - if (nodeId.indexOf(".") > -1) { const path = nodeId.split("."); @@ -118,6 +114,7 @@ export function GraphInspector(): JSX.Element { return; } + setAfter(''); setTypename(nodeId); }, [], ); @@ -150,36 +147,31 @@ export function GraphInspector(): JSX.Element { } return ( - } - defaultExpandIcon={} - onNodeToggle={handleChange} - multiSelect={false} - > - {Object.values(graph).map(({ typename, label, nodes }) => ( - {label}} - > - {nodes.length > 0 - ? nodes.map((vertexNode, i) => ( - - } - /> - ) - ) - : } - - ))} - +
+ } + defaultExpandIcon={} + onNodeToggle={handleChange} + multiSelect={false} + > + {Object.values(graph).map(({ typename, label, nodes }) => ( + {label}
} + > + setAfter(data.all.pageInfo.endCursor)} + height={height} + /> + + ))} + + ); } diff --git a/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx b/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx new file mode 100644 index 0000000..8d750b5 --- /dev/null +++ b/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx @@ -0,0 +1,108 @@ +import { useRef, useEffect } from 'react'; +import { useVirtualizer } from '@tanstack/react-virtual'; +import { StyledTreeItem } from './StyledTreeItem'; +import { Node } from './Node'; +import { VertexNode } from "../../../../graphql/types"; + +interface RowVirtualizerDynamicProps { + nodes: VertexNode[]; + typename: string; + hasNextPage: boolean; + fetching: boolean; + fetchNextPage: () => void; + height: number; +} + +export function RowVirtualizerDynamic({ nodes, typename, hasNextPage, fetching, fetchNextPage, height }: RowVirtualizerDynamicProps): JSX.Element { + const expanderRef = useRef(); + + const rowVirtualizer = useVirtualizer({ + count: nodes.length, + getScrollElement: () => expanderRef.current, + estimateSize: () => 250, + }); + + useEffect(() => { + const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse() + + if (!lastItem) { + return + } + + if ( + lastItem.index >= nodes.length - 1 && + hasNextPage && + !fetching + ) { + fetchNextPage() + } + }, [ + hasNextPage, + fetchNextPage, + nodes.length, + fetching, + rowVirtualizer.getVirtualItems(), + ]); + + // useEffect(() => { + // if(isNaN(height)) { + // return; + // } + + // const timeout = setTimeout(() => { + // console.log(height) + + // rowVirtualizer.measure() + // }, 500); + + // return () => clearTimeout(timeout); + // }, [rowVirtualizer, height]); + + return ( +
+
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => { + const vertexNode = nodes[virtualRow.index]; + + return ( +
+ + } + /> +
+ ) + })} +
+
+ ) +} \ No newline at end of file diff --git a/cli/app/src/components/GraphInspector/graphReducer.ts b/cli/app/src/components/GraphInspector/graphReducer.ts index 5350ad1..f88d74c 100644 --- a/cli/app/src/components/GraphInspector/graphReducer.ts +++ b/cli/app/src/components/GraphInspector/graphReducer.ts @@ -2,17 +2,7 @@ import produce from "immer"; import { assert } from "../../assert/assert"; import { match } from "ts-pattern"; import type { VertexNode } from "../../../../graphql/types"; - -interface Type { - typename: string; - size: number; - label: string; - nodes: VertexNode[]; -} - -interface State { - graph: Record; -} +import { State, Type } from './types'; type Actions = | { diff --git a/cli/app/src/components/GraphInspector/types.ts b/cli/app/src/components/GraphInspector/types.ts index 6ec4130..d4be863 100644 --- a/cli/app/src/components/GraphInspector/types.ts +++ b/cli/app/src/components/GraphInspector/types.ts @@ -28,3 +28,14 @@ export interface VertexNode extends Node { typename: string; fields: FieldEntry[]; } + +export interface Type { + typename: string; + size: number; + label: string; + nodes: VertexNode[]; +} + +export interface State { + graph: Record; +} diff --git a/cli/app/src/css/global.css b/cli/app/src/css/global.css index d3bbc9c..e9c82b4 100644 --- a/cli/app/src/css/global.css +++ b/cli/app/src/css/global.css @@ -10,7 +10,7 @@ html { body { font-family: "Lucida Console", Monaco, monospace; - margin: 1rem; + margin: 0; } html, body, #root, main { @@ -20,12 +20,13 @@ html, body, #root, main { ul { padding: 0 !important; margin: 0 !important; + margin-left: 0 !important; + border: 0 !important; } main { display: grid; - border-style: solid; grid-template-rows: 1fr; grid-template-columns: 1fr; } diff --git a/cli/app/src/index.tsx b/cli/app/src/index.tsx index 3fc5baa..6cb87d4 100644 --- a/cli/app/src/index.tsx +++ b/cli/app/src/index.tsx @@ -1,9 +1,8 @@ import "./css/global.css"; -import React from "react"; import { createRoot } from "react-dom/client"; -import { Factory } from "./components/Factory/Factory.tsx"; +import { Factory } from "./components/Factory/Factory"; -export const container = document.getElementById("main"); +export const container = document.querySelector("main"); const root = createRoot(container); diff --git a/cli/graphql/server.ts b/cli/graphql/server.ts index cae4bfd..148d043 100644 --- a/cli/graphql/server.ts +++ b/cli/graphql/server.ts @@ -14,13 +14,13 @@ export async function main(options: MainOptions) { maskedErrors: false, logging: { debug(...args) { - console.debug(...args); + console.dir(...args, { depth: 12 }); }, warn(...args) { - console.warn(...args); + console.dir(...args, { depth: 12 }); }, info(...args) { - console.info(...args); + console.dir(...args, { depth: 12 }); }, error(...args) { console.error(...args); diff --git a/cli/package-lock.json b/cli/package-lock.json index 782625f..3c45e1e 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -13,6 +13,9 @@ "@mui/icons-material": "5.10.6", "@mui/lab": "5.0.0-alpha.100", "@mui/material": "5.10.6", + "@rooks/use-boundingclientrect-ref": "4.11.2", + "@tanstack/react-table": "8.5.13", + "@tanstack/react-virtual": "3.0.0-beta.18", "@urql/exchange-graphcache": "5.0.1", "graphql": "15.5.0", "immer": "9.0.15", @@ -2597,6 +2600,75 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rooks/use-boundingclientrect-ref": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@rooks/use-boundingclientrect-ref/-/use-boundingclientrect-ref-4.11.2.tgz", + "integrity": "sha512-QRP+kQ6689mf6tE2b+5UjfxLFIPq4U7fHuD+Ya0iJua5oSPV5CvUI7AwyVRzPWSh0jrekvB+t/3kdWbFhKj9BA==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.5.13.tgz", + "integrity": "sha512-k52HsnonKwDZMCIy59HfehTnkJYlqkqyvC+BAV0DyWdN9WmSbVq+Kf+luJVENQnXcnEX47dBHiHAjqZu592ZLQ==", + "dependencies": { + "@tanstack/table-core": "8.5.13" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.0-beta.18.tgz", + "integrity": "sha512-mnyCZT6htcRNw1jVb+WyfMUMbd1UmXX/JWPuMf6Bmj92DB/V7Ogk5n5rby5Y5aste7c7mlsBeMF8HtpwERRvEQ==", + "dependencies": { + "@tanstack/virtual-core": "3.0.0-beta.18" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.5.13.tgz", + "integrity": "sha512-kvDRjC7LrLNNNgUMfsBz3nHOwbBLFdosWQ16dfbD9D/OJrvFHRXoUIPzF0MNqqSPghaj7/18fnwXHGypvzoh9Q==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0-beta.18.tgz", + "integrity": "sha512-tcXutY05NpN9lp3+AXI9Sn85RxSPV0EJC0XMim9oeQj/E7bjXoL0qZ4Er4wwnvIbv/hZjC91EmbIQGjgdr6nZg==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -9277,6 +9349,38 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" }, + "@rooks/use-boundingclientrect-ref": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@rooks/use-boundingclientrect-ref/-/use-boundingclientrect-ref-4.11.2.tgz", + "integrity": "sha512-QRP+kQ6689mf6tE2b+5UjfxLFIPq4U7fHuD+Ya0iJua5oSPV5CvUI7AwyVRzPWSh0jrekvB+t/3kdWbFhKj9BA==", + "requires": {} + }, + "@tanstack/react-table": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.5.13.tgz", + "integrity": "sha512-k52HsnonKwDZMCIy59HfehTnkJYlqkqyvC+BAV0DyWdN9WmSbVq+Kf+luJVENQnXcnEX47dBHiHAjqZu592ZLQ==", + "requires": { + "@tanstack/table-core": "8.5.13" + } + }, + "@tanstack/react-virtual": { + "version": "3.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.0.0-beta.18.tgz", + "integrity": "sha512-mnyCZT6htcRNw1jVb+WyfMUMbd1UmXX/JWPuMf6Bmj92DB/V7Ogk5n5rby5Y5aste7c7mlsBeMF8HtpwERRvEQ==", + "requires": { + "@tanstack/virtual-core": "3.0.0-beta.18" + } + }, + "@tanstack/table-core": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.5.13.tgz", + "integrity": "sha512-kvDRjC7LrLNNNgUMfsBz3nHOwbBLFdosWQ16dfbD9D/OJrvFHRXoUIPzF0MNqqSPghaj7/18fnwXHGypvzoh9Q==" + }, + "@tanstack/virtual-core": { + "version": "3.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0-beta.18.tgz", + "integrity": "sha512-tcXutY05NpN9lp3+AXI9Sn85RxSPV0EJC0XMim9oeQj/E7bjXoL0qZ4Er4wwnvIbv/hZjC91EmbIQGjgdr6nZg==" + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", diff --git a/cli/package.json b/cli/package.json index 4fe7dfa..ea81f59 100644 --- a/cli/package.json +++ b/cli/package.json @@ -6,12 +6,15 @@ "codegen": "graphql-codegen" }, "dependencies": { - "@urql/exchange-graphcache": "5.0.1", + "@tanstack/react-table": "8.5.13", "@emotion/styled": "11.10.4", "@emotion/react": "11.10.4", "@mui/material": "5.10.6", "@mui/lab": "5.0.0-alpha.100", "@mui/icons-material": "5.10.6", + "@rooks/use-boundingclientrect-ref": "4.11.2", + "@tanstack/react-virtual": "3.0.0-beta.18", + "@urql/exchange-graphcache": "5.0.1", "graphql": "15.5.0", "immer": "9.0.15", "react": "18.2.0", diff --git a/cli/vite.config.ts b/cli/vite.config.ts index 10121db..80701ac 100644 --- a/cli/vite.config.ts +++ b/cli/vite.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ root: "app", plugins: [react(), tsconfigPaths()], build: { - watch: isDevelopment ? {} : undefined, + watch: {}, emptyOutDir: true, outDir: "../dist", sourcemap: "inline", From 354538efaa4bfa852e8cd5776bf19748b99f25b4 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Mon, 3 Oct 2022 19:04:00 +0100 Subject: [PATCH 2/6] use better keys --- .../GraphInspector/GraphInspector.tsx | 13 +- .../GraphInspector/RowVirtualizerDynamic.tsx | 58 +----- .../GraphInspector/StyledTreeItem.tsx | 2 - .../components/GraphInspector/VirtualRow.tsx | 31 +++ cli/app/src/css/global.css | 1 + cli/package-lock.json | 191 +++++++++++++++++- 6 files changed, 237 insertions(+), 59 deletions(-) create mode 100644 cli/app/src/components/GraphInspector/VirtualRow.tsx diff --git a/cli/app/src/components/GraphInspector/GraphInspector.tsx b/cli/app/src/components/GraphInspector/GraphInspector.tsx index 886d9f4..dd2a795 100644 --- a/cli/app/src/components/GraphInspector/GraphInspector.tsx +++ b/cli/app/src/components/GraphInspector/GraphInspector.tsx @@ -12,7 +12,6 @@ import { fetchGraphQL } from "../../graphql/fetchGraphql"; import { useQuery } from 'urql'; import type { Page } from '../../../../graphql/relay'; import { RowVirtualizerDynamic } from './RowVirtualizerDynamic'; -import useBoundingclientrectRef from '@rooks/use-boundingclientrect-ref'; const emptyGraph = { graph: {} }; @@ -21,10 +20,8 @@ const limit = 5; export function GraphInspector(): JSX.Element { const [after, setAfter] = useState(''); const [typename, setTypename] = useState(); - const [expanderRef, boundingClientRect] = useBoundingclientrectRef(); + const [state, forceUpdate] = useReducer((x => x + 1), 0); - const height = Math.round(boundingClientRect?.height); - const [result] = useQuery<{ all: Page }, { typename: string; first: number; @@ -116,6 +113,7 @@ export function GraphInspector(): JSX.Element { setAfter(''); setTypename(nodeId); + forceUpdate(); }, [], ); @@ -147,7 +145,7 @@ export function GraphInspector(): JSX.Element { } return ( -
+
} @@ -161,14 +159,13 @@ export function GraphInspector(): JSX.Element { nodeId={typename} label={
{label}
} > - 0 ? setAfter(data.all.pageInfo.endCursor)} - height={height} - /> + /> :
loading....
} ))}
diff --git a/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx b/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx index 8d750b5..178e0e0 100644 --- a/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx +++ b/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx @@ -1,8 +1,7 @@ import { useRef, useEffect } from 'react'; import { useVirtualizer } from '@tanstack/react-virtual'; -import { StyledTreeItem } from './StyledTreeItem'; -import { Node } from './Node'; -import { VertexNode } from "../../../../graphql/types"; +import type { VertexNode } from "../../../../graphql/types"; +import { VirtualRow } from './VirtualRow'; interface RowVirtualizerDynamicProps { nodes: VertexNode[]; @@ -10,16 +9,16 @@ interface RowVirtualizerDynamicProps { hasNextPage: boolean; fetching: boolean; fetchNextPage: () => void; - height: number; } -export function RowVirtualizerDynamic({ nodes, typename, hasNextPage, fetching, fetchNextPage, height }: RowVirtualizerDynamicProps): JSX.Element { +export function RowVirtualizerDynamic({ nodes, typename, hasNextPage, fetching, fetchNextPage }: RowVirtualizerDynamicProps): JSX.Element { const expanderRef = useRef(); - const rowVirtualizer = useVirtualizer({ count: nodes.length, getScrollElement: () => expanderRef.current, - estimateSize: () => 250, + estimateSize: () => nodes[0].fields.length * 30, + overscan: 1, + enableSmoothScroll: true, }); useEffect(() => { @@ -44,25 +43,11 @@ export function RowVirtualizerDynamic({ nodes, typename, hasNextPage, fetching, rowVirtualizer.getVirtualItems(), ]); - // useEffect(() => { - // if(isNaN(height)) { - // return; - // } - - // const timeout = setTimeout(() => { - // console.log(height) - - // rowVirtualizer.measure() - // }, 500); - - // return () => clearTimeout(timeout); - // }, [rowVirtualizer, height]); - return (
{ const vertexNode = nodes[virtualRow.index]; - return ( -
- - } - /> -
- ) + console.log(`${nodes[virtualRow.index].id}`); + return })}
) -} \ No newline at end of file +} + diff --git a/cli/app/src/components/GraphInspector/StyledTreeItem.tsx b/cli/app/src/components/GraphInspector/StyledTreeItem.tsx index 8606eed..5f5d7f9 100644 --- a/cli/app/src/components/GraphInspector/StyledTreeItem.tsx +++ b/cli/app/src/components/GraphInspector/StyledTreeItem.tsx @@ -11,8 +11,6 @@ export const StyledTreeItem: FC = styled((props: TreeItemProps) = }, }, [`& .${treeItemClasses.group}`]: { - marginLeft: `15px !important`, - paddingLeft: `18px !important`, borderLeft: `1px dashed ${alpha(theme.palette.text.primary, 0.4)}`, }, [`& .${treeItemClasses.selected}`]: { diff --git a/cli/app/src/components/GraphInspector/VirtualRow.tsx b/cli/app/src/components/GraphInspector/VirtualRow.tsx new file mode 100644 index 0000000..d8fd860 --- /dev/null +++ b/cli/app/src/components/GraphInspector/VirtualRow.tsx @@ -0,0 +1,31 @@ +import { StyledTreeItem } from './StyledTreeItem'; +import { Node } from './Node'; +import { VirtualItem } from '@tanstack/react-virtual'; +import type { VertexNode } from "../../../../graphql/types"; + +export function VirtualRow({ virtualRow, vertexNode, typename }: { virtualRow: VirtualItem, vertexNode: VertexNode, typename: string }): JSX.Element { + return ( +
+ + } + /> +
+ ) +} \ No newline at end of file diff --git a/cli/app/src/css/global.css b/cli/app/src/css/global.css index e9c82b4..05f6ac1 100644 --- a/cli/app/src/css/global.css +++ b/cli/app/src/css/global.css @@ -11,6 +11,7 @@ html { body { font-family: "Lucida Console", Monaco, monospace; margin: 0; + overflow: hidden; } html, body, #root, main { diff --git a/cli/package-lock.json b/cli/package-lock.json index 3c45e1e..39d6a1c 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@emotion/react": "11.10.4", "@emotion/styled": "11.10.4", + "@headlessui/react": "1.7.3", "@mui/icons-material": "5.10.6", "@mui/lab": "5.0.0-alpha.100", "@mui/material": "5.10.6", @@ -22,6 +23,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "ts-pattern": "4.0.5", + "twind": "0.16.17", "urql": "2.0.2" }, "devDependencies": { @@ -2170,6 +2172,18 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@headlessui/react": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.3.tgz", + "integrity": "sha512-LGp06SrGv7BMaIQlTs8s2G06moqkI0cb0b8stgq7KZ3xcHdH3qMP+cRyV7qe5x4XEW/IGY48BW4fLesD6NQLng==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" + } + }, "node_modules/@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", @@ -3747,6 +3761,57 @@ "csstype": "^3.0.2" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -3801,6 +3866,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4694,6 +4767,24 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -6776,6 +6867,11 @@ "node": ">=4" } }, + "node_modules/style-vendorizer": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.2.3.tgz", + "integrity": "sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==" + }, "node_modules/stylis": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", @@ -6951,6 +7047,27 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/twind": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/twind/-/twind-0.16.17.tgz", + "integrity": "sha512-dBKm8+ncJcIALiqBRLxA/krFEwUSjnzR+N73eKgqPtVPJqfLpkajWwKWL5xEpEQ5ypS3ffa0jJjH3/eIeuA3pw==", + "dependencies": { + "csstype": "^3.0.5", + "htmlparser2": "^6.0.0", + "style-vendorizer": "^2.0.0" + }, + "engines": { + "node": ">=10.13" + }, + "peerDependencies": { + "typescript": "^4.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -6967,7 +7084,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true, + "devOptional": true, "peer": true, "bin": { "tsc": "bin/tsc", @@ -9107,6 +9224,12 @@ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", "requires": {} }, + "@headlessui/react": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.3.tgz", + "integrity": "sha512-LGp06SrGv7BMaIQlTs8s2G06moqkI0cb0b8stgq7KZ3xcHdH3qMP+cRyV7qe5x4XEW/IGY48BW4fLesD6NQLng==", + "requires": {} + }, "@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", @@ -10236,6 +10359,39 @@ "csstype": "^3.0.2" } }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, "dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -10286,6 +10442,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -10877,6 +11038,17 @@ } } }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -12472,6 +12644,11 @@ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, + "style-vendorizer": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.2.3.tgz", + "integrity": "sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==" + }, "stylis": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", @@ -12608,6 +12785,16 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "twind": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/twind/-/twind-0.16.17.tgz", + "integrity": "sha512-dBKm8+ncJcIALiqBRLxA/krFEwUSjnzR+N73eKgqPtVPJqfLpkajWwKWL5xEpEQ5ypS3ffa0jJjH3/eIeuA3pw==", + "requires": { + "csstype": "^3.0.5", + "htmlparser2": "^6.0.0", + "style-vendorizer": "^2.0.0" + } + }, "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -12618,7 +12805,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "dev": true, + "devOptional": true, "peer": true }, "ua-parser-js": { From 0ac63d51116523e02400ed03df6ff8984afe3358 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Tue, 4 Oct 2022 08:23:22 +0100 Subject: [PATCH 3/6] force re-render --- cli/.vscode/settings.json | 2 +- cli/app/src/components/Factory/Factory.css | 5 - cli/app/src/components/Factory/Factory.tsx | 10 +- .../GraphInspector/DynamicRowVirtualizer.tsx | 89 ++++++++ .../GraphInspector/GraphInspector.tsx | 55 +++-- .../src/components/GraphInspector/Node.tsx | 2 +- .../GraphInspector/RowVirtualizerDynamic.tsx | 72 ------- .../GraphInspector/StyledTreeItem.tsx | 8 +- .../components/GraphInspector/VirtualRow.tsx | 34 +++- .../components/GraphInspector/graphReducer.ts | 7 +- .../src/components/GraphInspector/queries.ts | 4 +- cli/app/src/components/Loader/Loader.tsx | 11 +- cli/app/src/css/global.css | 5 +- cli/graphql/relay.ts | 4 +- cli/graphql/schema.ts | 4 +- cli/package-lock.json | 191 +----------------- 16 files changed, 184 insertions(+), 319 deletions(-) create mode 100644 cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx delete mode 100644 cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx diff --git a/cli/.vscode/settings.json b/cli/.vscode/settings.json index 035012d..974a2b4 100644 --- a/cli/.vscode/settings.json +++ b/cli/.vscode/settings.json @@ -1,3 +1,3 @@ { "deno.enable": false -} \ No newline at end of file +} diff --git a/cli/app/src/components/Factory/Factory.css b/cli/app/src/components/Factory/Factory.css index 7ccc1a8..0cb6210 100644 --- a/cli/app/src/components/Factory/Factory.css +++ b/cli/app/src/components/Factory/Factory.css @@ -6,9 +6,4 @@ main { .app { grid-row: main; margin-top: .5rem; -} - -.app section:first-of-type { - display: flex; - justify-content: flex-start; } \ No newline at end of file diff --git a/cli/app/src/components/Factory/Factory.tsx b/cli/app/src/components/Factory/Factory.tsx index feea5c6..04ee991 100644 --- a/cli/app/src/components/Factory/Factory.tsx +++ b/cli/app/src/components/Factory/Factory.tsx @@ -3,9 +3,15 @@ import { StrictMode, Suspense } from "react"; import { StyledEngineProvider } from "@mui/material/styles"; import { GraphInspector } from "../GraphInspector/GraphInspector"; import { Topbar } from "../Topbar/Topbar"; -import { createClient, dedupExchange, Exchange, fetchExchange, Provider } from "urql"; +import { + createClient, + dedupExchange, + Exchange, + fetchExchange, + Provider, +} from "urql"; import { cacheExchange } from "@urql/exchange-graphcache"; -import { relayPagination } from '@urql/exchange-graphcache/extras'; +import { relayPagination } from "@urql/exchange-graphcache/extras"; const client = createClient({ url: "/graphql", diff --git a/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx b/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx new file mode 100644 index 0000000..d8384b7 --- /dev/null +++ b/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx @@ -0,0 +1,89 @@ +import { useCallback, useEffect, useRef } from "react"; +import { useVirtualizer } from "@tanstack/react-virtual"; +import type { VertexNode } from "../../../../graphql/types"; +import { VirtualRow } from "./VirtualRow"; + +interface DynamicRowVirtualizerProps { + nodes: VertexNode[]; + typename: string; + hasNextPage: boolean; + fetching: boolean; + fetchNextPage: () => void; + update: number; +} + +const RowSize = 30; + +export function DynamicRowVirtualizer( + { nodes, typename, hasNextPage, fetching, fetchNextPage, update }: + DynamicRowVirtualizerProps, +): JSX.Element { + const expanderRef = useRef(); + + const rowVirtualizer = useVirtualizer({ + count: nodes.length, + getScrollElement: () => expanderRef.current, + // we need useCallback to force the update + estimateSize: useCallback(() => nodes[0].fields.length * RowSize, [update]), + overscan: 3, + enableSmoothScroll: false, + getItemKey: (index) => nodes[index].id, + // nuking this for now. Default does too much + scrollToFn: () => ({}), + }); + + useEffect(() => { + const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse(); + + if (!lastItem) { + return; + } + + if ( + lastItem.index >= nodes.length - 1 && + hasNextPage && + !fetching + ) { + fetchNextPage(); + } + }, [ + hasNextPage, + fetchNextPage, + nodes.length, + fetching, + rowVirtualizer.getVirtualItems(), + ]); + + return ( +
+
+ {rowVirtualizer.getVirtualItems().map((virtualRow) => { + const vertexNode = nodes[virtualRow.index]; + + return ( + + ); + })} +
+
+ ); +} diff --git a/cli/app/src/components/GraphInspector/GraphInspector.tsx b/cli/app/src/components/GraphInspector/GraphInspector.tsx index dd2a795..b721d7d 100644 --- a/cli/app/src/components/GraphInspector/GraphInspector.tsx +++ b/cli/app/src/components/GraphInspector/GraphInspector.tsx @@ -1,26 +1,30 @@ import "./GraphInspector.css"; import type { SyntheticEvent } from "react"; -import { useCallback, useEffect, useReducer, useRef, useState } from "react"; +import { useCallback, useEffect, useReducer, useState } from "react"; import TreeView from "@mui/lab/TreeView"; -import { Node } from "./Node"; import { allQuery, node } from "./queries"; import { graphReducer } from "./graphReducer"; import { VertexNode } from "../../../../graphql/types"; import { MinusSquare, PlusSquare } from "./icons"; import { StyledTreeItem } from "./StyledTreeItem"; import { fetchGraphQL } from "../../graphql/fetchGraphql"; -import { useQuery } from 'urql'; -import type { Page } from '../../../../graphql/relay'; -import { RowVirtualizerDynamic } from './RowVirtualizerDynamic'; +import { useQuery } from "urql"; +import type { Page } from "../../../../graphql/relay"; +import { DynamicRowVirtualizer } from "./DynamicRowVirtualizer"; const emptyGraph = { graph: {} }; const limit = 5; export function GraphInspector(): JSX.Element { - const [after, setAfter] = useState(''); + const [after, setAfter] = useState(""); const [typename, setTypename] = useState(); - const [state, forceUpdate] = useReducer((x => x + 1), 0); + // TODO: this really needs to go at some point and the rangeExtractor prop of + // useVirtualized seems a better way to go + // https://tanstack.com/virtual/v3/docs/api/virtualizer#rangeextractor + // measureElement might be useful here too + // https://tanstack.com/virtual/v3/docs/api/virtualizer#measureelement + const [update, forceUpdate] = useReducer((x) => x + 1, 0); const [result] = useQuery<{ all: Page }, { typename: string; @@ -32,7 +36,7 @@ export function GraphInspector(): JSX.Element { variables: { typename, first: limit, - after + after, }, }); @@ -51,10 +55,10 @@ export function GraphInspector(): JSX.Element { type: "ALL", payload: { typename, - nodes: edges.map(edge => edge.node), + nodes: edges.map((edge) => edge.node), }, }); - }, [data, typename]) + }, [data, typename]); const handleChange = useCallback( async (_: SyntheticEvent, nodeIds: string[]) => { @@ -108,13 +112,17 @@ export function GraphInspector(): JSX.Element { } } + setTimeout(forceUpdate, 300); + return; } - setAfter(''); + setAfter(""); setTypename(nodeId); - forceUpdate(); - }, [], + + setTimeout(forceUpdate, 300); + }, + [], ); useEffect(() => { @@ -141,7 +149,7 @@ export function GraphInspector(): JSX.Element { } if (error) { - return

Oh no... {error?.message}

+ return

Oh no... {error?.message}

; } return ( @@ -159,13 +167,18 @@ export function GraphInspector(): JSX.Element { nodeId={typename} label={
{label}
} > - {nodes.length > 0 ? setAfter(data.all.pageInfo.endCursor)} - /> :
loading....
} + {nodes.length > 0 + ? ( + setAfter(data.all.pageInfo.endCursor)} + update={update} + /> + ) + :
loading....
} ))} diff --git a/cli/app/src/components/GraphInspector/Node.tsx b/cli/app/src/components/GraphInspector/Node.tsx index 859bfa5..2cc5455 100644 --- a/cli/app/src/components/GraphInspector/Node.tsx +++ b/cli/app/src/components/GraphInspector/Node.tsx @@ -93,7 +93,7 @@ export function Node({ parentId, node }: NodeProps): JSX.Element { } /> )) - : } + : } ); })} diff --git a/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx b/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx deleted file mode 100644 index 178e0e0..0000000 --- a/cli/app/src/components/GraphInspector/RowVirtualizerDynamic.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useRef, useEffect } from 'react'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import type { VertexNode } from "../../../../graphql/types"; -import { VirtualRow } from './VirtualRow'; - -interface RowVirtualizerDynamicProps { - nodes: VertexNode[]; - typename: string; - hasNextPage: boolean; - fetching: boolean; - fetchNextPage: () => void; -} - -export function RowVirtualizerDynamic({ nodes, typename, hasNextPage, fetching, fetchNextPage }: RowVirtualizerDynamicProps): JSX.Element { - const expanderRef = useRef(); - const rowVirtualizer = useVirtualizer({ - count: nodes.length, - getScrollElement: () => expanderRef.current, - estimateSize: () => nodes[0].fields.length * 30, - overscan: 1, - enableSmoothScroll: true, - }); - - useEffect(() => { - const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse() - - if (!lastItem) { - return - } - - if ( - lastItem.index >= nodes.length - 1 && - hasNextPage && - !fetching - ) { - fetchNextPage() - } - }, [ - hasNextPage, - fetchNextPage, - nodes.length, - fetching, - rowVirtualizer.getVirtualItems(), - ]); - - return ( -
-
- {rowVirtualizer.getVirtualItems().map((virtualRow) => { - const vertexNode = nodes[virtualRow.index]; - - console.log(`${nodes[virtualRow.index].id}`); - return - })} -
-
- ) -} - diff --git a/cli/app/src/components/GraphInspector/StyledTreeItem.tsx b/cli/app/src/components/GraphInspector/StyledTreeItem.tsx index 5f5d7f9..8b244f2 100644 --- a/cli/app/src/components/GraphInspector/StyledTreeItem.tsx +++ b/cli/app/src/components/GraphInspector/StyledTreeItem.tsx @@ -1,10 +1,10 @@ import { alpha, styled } from "@mui/material/styles"; import TreeItem, { treeItemClasses, TreeItemProps } from "@mui/lab/TreeItem"; -import { FC } from 'react'; +import { FC } from "react"; -export const StyledTreeItem: FC = styled((props: TreeItemProps) => ( - -))(({ theme }) => ({ +export const StyledTreeItem: FC = styled(( + props: TreeItemProps, +) => )(({ theme }) => ({ [`& .${treeItemClasses.iconContainer}`]: { "& .close": { opacity: 0.3, diff --git a/cli/app/src/components/GraphInspector/VirtualRow.tsx b/cli/app/src/components/GraphInspector/VirtualRow.tsx index d8fd860..55651a6 100644 --- a/cli/app/src/components/GraphInspector/VirtualRow.tsx +++ b/cli/app/src/components/GraphInspector/VirtualRow.tsx @@ -1,18 +1,34 @@ -import { StyledTreeItem } from './StyledTreeItem'; -import { Node } from './Node'; -import { VirtualItem } from '@tanstack/react-virtual'; +import { StyledTreeItem } from "./StyledTreeItem"; +import { Node } from "./Node"; +import { VirtualItem } from "@tanstack/react-virtual"; import type { VertexNode } from "../../../../graphql/types"; +import { useEffect, useRef } from "react"; + +interface VirtualRowProps { + virtualRow: VirtualItem; + vertexNode: VertexNode; + typename: string; + update: number; +} + +export function VirtualRow( + { virtualRow, vertexNode, typename, update }: VirtualRowProps, +): JSX.Element { + const elementRef = useRef(null); + + useEffect(() => { + virtualRow.measureElement(elementRef.current); + }, [update]); -export function VirtualRow({ virtualRow, vertexNode, typename }: { virtualRow: VirtualItem, vertexNode: VertexNode, typename: string }): JSX.Element { return (
@@ -27,5 +43,5 @@ export function VirtualRow({ virtualRow, vertexNode, typename }: { virtualRow: V } />
- ) -} \ No newline at end of file + ); +} diff --git a/cli/app/src/components/GraphInspector/graphReducer.ts b/cli/app/src/components/GraphInspector/graphReducer.ts index f88d74c..70e3872 100644 --- a/cli/app/src/components/GraphInspector/graphReducer.ts +++ b/cli/app/src/components/GraphInspector/graphReducer.ts @@ -2,7 +2,7 @@ import produce from "immer"; import { assert } from "../../assert/assert"; import { match } from "ts-pattern"; import type { VertexNode } from "../../../../graphql/types"; -import { State, Type } from './types'; +import { State, Type } from "./types"; type Actions = | { @@ -32,7 +32,7 @@ type Actions = }; function isNumber(s: unknown): s is number { - return !isNaN(Number(s)); + return s === '' ? false : !isNaN(Number(s)); } export const graphReducer = produce((state: State, action: Actions) => { @@ -61,8 +61,7 @@ export const graphReducer = produce((state: State, action: Actions) => { const [root, ...props] = path; - // deno-lint-ignore no-explicit-any - let draft: any = state.graph[root]; + let draft: Type = state.graph[root]; assert(!!draft, `no parent for ${path[0]}`); diff --git a/cli/app/src/components/GraphInspector/queries.ts b/cli/app/src/components/GraphInspector/queries.ts index ed77a53..6ce705e 100644 --- a/cli/app/src/components/GraphInspector/queries.ts +++ b/cli/app/src/components/GraphInspector/queries.ts @@ -1,5 +1,5 @@ import { fetchGraphQL } from "../../graphql/fetchGraphql"; -import { gql } from 'urql'; +import { gql } from "urql"; export async function node(id: string) { return await fetchGraphQL( @@ -64,4 +64,4 @@ query All($typename: String!, $first: Int!, $after: String!) { } } } -` +`; diff --git a/cli/app/src/components/Loader/Loader.tsx b/cli/app/src/components/Loader/Loader.tsx index c3be49a..3b824ab 100644 --- a/cli/app/src/components/Loader/Loader.tsx +++ b/cli/app/src/components/Loader/Loader.tsx @@ -1,10 +1,13 @@ -import CircularProgress from "@mui/material/CircularProgress"; +import LinearProgress from "@mui/material/LinearProgress"; import Box from "@mui/material/Box"; -export function Loader(): JSX.Element { +export function Loader({ debug }: { debug?: unknown }): JSX.Element { + if (debug) { + console.log(debug); + } return ( - - + + ); } diff --git a/cli/app/src/css/global.css b/cli/app/src/css/global.css index 05f6ac1..6c071c4 100644 --- a/cli/app/src/css/global.css +++ b/cli/app/src/css/global.css @@ -11,7 +11,10 @@ html { body { font-family: "Lucida Console", Monaco, monospace; margin: 0; - overflow: hidden; +} + +h2 { + margin-left: 1rem; } html, body, #root, main { diff --git a/cli/graphql/relay.ts b/cli/graphql/relay.ts index ae4076e..a721f1d 100644 --- a/cli/graphql/relay.ts +++ b/cli/graphql/relay.ts @@ -76,8 +76,8 @@ export function applyRelayPagination( } function applyCursorsToEdges(nodes: T[], before?: string, after?: string) { - const afterIdx = after != null ? Number(after) : -1; - const beforeIdx = before != null ? Number(before) : nodes.length; + const afterIdx = !!after ? Number(after) : -1; + const beforeIdx = !!before ? Number(before) : nodes.length; const edges = nodes.slice(afterIdx + 1, beforeIdx).map((node, i) => ({ node, diff --git a/cli/graphql/schema.ts b/cli/graphql/schema.ts index cf0c309..d6f8903 100644 --- a/cli/graphql/schema.ts +++ b/cli/graphql/schema.ts @@ -1,6 +1,6 @@ import { GraphQLJSON, GraphQLJSONObject } from "../deps.ts"; import type { GraphQLContext } from "./context.ts"; -import { applyRelayPagination, Page, PageArgs } from './relay.ts'; +import { applyRelayPagination, Page, PageArgs } from "./relay.ts"; import { toVertexNode } from "./toVertexNode.ts"; import { CreateInput, Type } from "./types.ts"; import { VertexNode } from "./types.ts"; @@ -27,7 +27,7 @@ export const resolvers = { }, all( _: unknown, - { typename, ...pageInfo }: PageArgs & { typename: string; }, + { typename, ...pageInfo }: PageArgs & { typename: string }, context: GraphQLContext, ): Page { const collection = context.factory.all(typename); diff --git a/cli/package-lock.json b/cli/package-lock.json index 39d6a1c..3c45e1e 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@emotion/react": "11.10.4", "@emotion/styled": "11.10.4", - "@headlessui/react": "1.7.3", "@mui/icons-material": "5.10.6", "@mui/lab": "5.0.0-alpha.100", "@mui/material": "5.10.6", @@ -23,7 +22,6 @@ "react": "18.2.0", "react-dom": "18.2.0", "ts-pattern": "4.0.5", - "twind": "0.16.17", "urql": "2.0.2" }, "devDependencies": { @@ -2172,18 +2170,6 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@headlessui/react": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.3.tgz", - "integrity": "sha512-LGp06SrGv7BMaIQlTs8s2G06moqkI0cb0b8stgq7KZ3xcHdH3qMP+cRyV7qe5x4XEW/IGY48BW4fLesD6NQLng==", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16 || ^17 || ^18", - "react-dom": "^16 || ^17 || ^18" - } - }, "node_modules/@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", @@ -3761,57 +3747,6 @@ "csstype": "^3.0.2" } }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -3866,14 +3801,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4767,24 +4694,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -6867,11 +6776,6 @@ "node": ">=4" } }, - "node_modules/style-vendorizer": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.2.3.tgz", - "integrity": "sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==" - }, "node_modules/stylis": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", @@ -7047,27 +6951,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/twind": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/twind/-/twind-0.16.17.tgz", - "integrity": "sha512-dBKm8+ncJcIALiqBRLxA/krFEwUSjnzR+N73eKgqPtVPJqfLpkajWwKWL5xEpEQ5ypS3ffa0jJjH3/eIeuA3pw==", - "dependencies": { - "csstype": "^3.0.5", - "htmlparser2": "^6.0.0", - "style-vendorizer": "^2.0.0" - }, - "engines": { - "node": ">=10.13" - }, - "peerDependencies": { - "typescript": "^4.1.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -7084,7 +6967,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "devOptional": true, + "dev": true, "peer": true, "bin": { "tsc": "bin/tsc", @@ -9224,12 +9107,6 @@ "integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==", "requires": {} }, - "@headlessui/react": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.3.tgz", - "integrity": "sha512-LGp06SrGv7BMaIQlTs8s2G06moqkI0cb0b8stgq7KZ3xcHdH3qMP+cRyV7qe5x4XEW/IGY48BW4fLesD6NQLng==", - "requires": {} - }, "@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", @@ -10359,39 +10236,6 @@ "csstype": "^3.0.2" } }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, "dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -10442,11 +10286,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -11038,17 +10877,6 @@ } } }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, "http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -12644,11 +12472,6 @@ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, - "style-vendorizer": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/style-vendorizer/-/style-vendorizer-2.2.3.tgz", - "integrity": "sha512-/VDRsWvQAgspVy9eATN3z6itKTuyg+jW1q6UoTCQCFRqPDw8bi3E1hXIKnGw5LvXS2AQPuJ7Af4auTLYeBOLEg==" - }, "stylis": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", @@ -12785,16 +12608,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "twind": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/twind/-/twind-0.16.17.tgz", - "integrity": "sha512-dBKm8+ncJcIALiqBRLxA/krFEwUSjnzR+N73eKgqPtVPJqfLpkajWwKWL5xEpEQ5ypS3ffa0jJjH3/eIeuA3pw==", - "requires": { - "csstype": "^3.0.5", - "htmlparser2": "^6.0.0", - "style-vendorizer": "^2.0.0" - } - }, "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -12805,7 +12618,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "devOptional": true, + "dev": true, "peer": true }, "ua-parser-js": { From ef84b7a0dde5ba202daeb166dd55e9b3b8e10b4d Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Tue, 4 Oct 2022 10:26:06 +0100 Subject: [PATCH 4/6] reinstate expanded nodes --- .../src/components/GraphInspector/GraphInspector.tsx | 10 +++++++++- cli/app/src/components/GraphInspector/Node.tsx | 2 +- cli/app/src/components/Loader/Loader.tsx | 5 +---- cli/package.json | 1 - cli/vite.config.ts | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cli/app/src/components/GraphInspector/GraphInspector.tsx b/cli/app/src/components/GraphInspector/GraphInspector.tsx index b721d7d..fa12feb 100644 --- a/cli/app/src/components/GraphInspector/GraphInspector.tsx +++ b/cli/app/src/components/GraphInspector/GraphInspector.tsx @@ -1,6 +1,6 @@ import "./GraphInspector.css"; import type { SyntheticEvent } from "react"; -import { useCallback, useEffect, useReducer, useState } from "react"; +import { useCallback, useEffect, useReducer, useState, useRef } from "react"; import TreeView from "@mui/lab/TreeView"; import { allQuery, node } from "./queries"; import { graphReducer } from "./graphReducer"; @@ -41,6 +41,7 @@ export function GraphInspector(): JSX.Element { }); const [{ graph }, dispatch] = useReducer(graphReducer, emptyGraph); + const expandedNodes = useRef(new Set()); const { data, error, fetching } = result; @@ -68,6 +69,13 @@ export function GraphInspector(): JSX.Element { const nodeId = nodeIds[0]; + if (expandedNodes.current.has(nodeId)) { + console.log(`${nodeId} has previously been opened`); + return; + } + + expandedNodes.current.add(nodeId); + if (nodeId.indexOf(".") > -1) { const path = nodeId.split("."); diff --git a/cli/app/src/components/GraphInspector/Node.tsx b/cli/app/src/components/GraphInspector/Node.tsx index 2cc5455..859bfa5 100644 --- a/cli/app/src/components/GraphInspector/Node.tsx +++ b/cli/app/src/components/GraphInspector/Node.tsx @@ -93,7 +93,7 @@ export function Node({ parentId, node }: NodeProps): JSX.Element { } /> )) - : } + : } ); })} diff --git a/cli/app/src/components/Loader/Loader.tsx b/cli/app/src/components/Loader/Loader.tsx index 3b824ab..7cf6c43 100644 --- a/cli/app/src/components/Loader/Loader.tsx +++ b/cli/app/src/components/Loader/Loader.tsx @@ -1,10 +1,7 @@ import LinearProgress from "@mui/material/LinearProgress"; import Box from "@mui/material/Box"; -export function Loader({ debug }: { debug?: unknown }): JSX.Element { - if (debug) { - console.log(debug); - } +export function Loader(): JSX.Element { return ( diff --git a/cli/package.json b/cli/package.json index ea81f59..1901646 100644 --- a/cli/package.json +++ b/cli/package.json @@ -6,7 +6,6 @@ "codegen": "graphql-codegen" }, "dependencies": { - "@tanstack/react-table": "8.5.13", "@emotion/styled": "11.10.4", "@emotion/react": "11.10.4", "@mui/material": "5.10.6", diff --git a/cli/vite.config.ts b/cli/vite.config.ts index 80701ac..10121db 100644 --- a/cli/vite.config.ts +++ b/cli/vite.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ root: "app", plugins: [react(), tsconfigPaths()], build: { - watch: {}, + watch: isDevelopment ? {} : undefined, emptyOutDir: true, outDir: "../dist", sourcemap: "inline", From 6ef78576f6cad818a2d49a034c9a2658d75262ce Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Tue, 4 Oct 2022 10:41:13 +0100 Subject: [PATCH 5/6] change selector for test --- cli/test/smoke.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/test/smoke.test.ts b/cli/test/smoke.test.ts index 9479dd3..9aafefe 100644 --- a/cli/test/smoke.test.ts +++ b/cli/test/smoke.test.ts @@ -18,7 +18,8 @@ describe("CLI smoke test", () => { let response = await fetch("http://localhost:8900"); expect(response.ok).toEqual(true); let body = await response.text(); - expect(body).toMatch(/div id="main"/); + console.log(body); + expect(body).toMatch(/main/); }, 10000); }); }); From b2d1610893b8cdb27d9f7b041c710e09de413ab2 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Tue, 4 Oct 2022 11:32:47 +0100 Subject: [PATCH 6/6] constrain height --- .../src/components/GraphInspector/DynamicRowVirtualizer.tsx | 3 +-- cli/graphql/relay.ts | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx b/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx index d8384b7..7ebda4f 100644 --- a/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx +++ b/cli/app/src/components/GraphInspector/DynamicRowVirtualizer.tsx @@ -25,7 +25,6 @@ export function DynamicRowVirtualizer( getScrollElement: () => expanderRef.current, // we need useCallback to force the update estimateSize: useCallback(() => nodes[0].fields.length * RowSize, [update]), - overscan: 3, enableSmoothScroll: false, getItemKey: (index) => nodes[index].id, // nuking this for now. Default does too much @@ -58,7 +57,7 @@ export function DynamicRowVirtualizer(
(nodes: T[], before?: string, after?: string) { const afterIdx = !!after ? Number(after) : -1; const beforeIdx = !!before ? Number(before) : nodes.length; + console.log({afterIdx, beforeIdx}); + const edges = nodes.slice(afterIdx + 1, beforeIdx).map((node, i) => ({ node, cursor: (afterIdx + 1 + i).toString(),