From 1b2b20803ab82fafbfe75fecaa05f6f6c1222242 Mon Sep 17 00:00:00 2001 From: francisanthony17 Date: Wed, 29 Nov 2023 15:57:20 +1100 Subject: [PATCH 1/4] initialise debugger dev --- client/src/hooks/useBreakpoints.tsx | 141 ++++++++++++++++------------ client/src/layers/trace/index.tsx | 3 +- client/src/pages/DebugPage.tsx | 21 +++++ 3 files changed, 106 insertions(+), 59 deletions(-) diff --git a/client/src/hooks/useBreakpoints.tsx b/client/src/hooks/useBreakpoints.tsx index 70c9f476..e5cfde5c 100644 --- a/client/src/hooks/useBreakpoints.tsx +++ b/client/src/hooks/useBreakpoints.tsx @@ -1,60 +1,85 @@ -import { useCallback } from "react"; +import { call } from "components/script-editor/call"; +import { get, keyBy, toLower as lower, startCase } from "lodash"; +import memoizee from "memoizee"; +import { TraceEventType } from "protocol"; +import { useMemo } from "react"; +import { UploadedTrace } from "slices/UIState"; +import { useLayer } from "slices/layers"; + + +export type Comparator = { + key: string; + apply: (value: number, reference: number) => boolean; +}; + +export type Breakpoint = { + key: string; + property?: string; + reference?: number; + condition?: Comparator; + active?: boolean; + type?: TraceEventType; +}; + +export type DebugLayerData = { + code?: string; + monotonicF?: boolean; + monotonicG?: boolean; + breakpoints?: Breakpoint[]; + trace?: UploadedTrace; +}; +export function useBreakpoints(key?: string) { + const { layer } = useLayer(key); + const {monotonicF, monotonicG,breakpoints ,code,trace} = layer?.source??{} + // TODO: + return useMemo(() => { + const memo = keyBy(trace?.content?.events, "id"); + return memoizee((step: number) => { + const event = trace?.content?.events?.[step]; + if (event) { + try { + // Check monotonic f or g values + if (step) { + for (const p of [monotonicF && "f", monotonicG && "g"]) { + if (p && get(memo[`${event.pId}`], p) > get(event, p)) { + return { result: `Monotonicity violation on ${p}` }; + } + } + } + // Check breakpoints in the breakpoints section + for (const { + active, + condition, + type, + property = "", + reference = 0, + } of breakpoints??[]) { + const isType = !type || type === event.type; + const match = condition?.apply?.(get(event, property), reference); + if (active && isType && match) { + return { + result: `${property} ${lower( + startCase(condition?.key) + )} ${reference}`, + }; + } + } + // Check breakpoints in the script editor section + if ( + call(code ?? "", "shouldBreak", [ + step, + event, + trace?.content?.events?? [], + ]) + ) { + return { result: "Script editor" }; + } + } catch (e) { + return { error: `${e}` }; + } + } + return { result: "" }; + }); + }, [code, trace?.content, breakpoints, monotonicF, monotonicG]); -export function useBreakpoints() { - //TODO: - // const [{ specimen }] = useSpecimen(); - // const [{ code, breakpoints = [], monotonicF, monotonicG }] = useUIState(); - // return useMemo(() => { - // const memo = keyBy(specimen?.eventList, "id"); - // return memoize((step: number) => { - // const event = specimen?.eventList?.[step]; - // if (event) { - // try { - // // Check monotonic f or g values - // if (step) { - // for (const p of [monotonicF && "f", monotonicG && "g"]) { - // if (p && get(memo[`${event.pId}`], p) > get(event, p)) { - // return { result: `Monotonicity violation on ${p}` }; - // } - // } - // } - // // Check breakpoints in the breakpoints section - // for (const { - // active, - // condition, - // type, - // property = "", - // reference = 0, - // } of breakpoints) { - // const isType = !type || type === event.type; - // const match = condition?.apply?.(get(event, property), reference); - // if (active && isType && match) { - // return { - // result: `${property} ${lower( - // startCase(condition?.key) - // )} ${reference}`, - // }; - // } - // } - // // Check breakpoints in the script editor section - // if ( - // call(code ?? "", "shouldBreak", [ - // step, - // event, - // specimen?.eventList ?? [], - // ]) - // ) { - // return { result: "Script editor" }; - // } - // } catch (e) { - // return { error: `${e}` }; - // } - // } - // return { result: "" }; - // }); - // }, [code, specimen, breakpoints, monotonicF, monotonicG]); - return useCallback( - (_i: number) => ({ result: "", error: undefined, offset: 0 }), - [] - ); } diff --git a/client/src/layers/trace/index.tsx b/client/src/layers/trace/index.tsx index 142d9c59..c43ac307 100644 --- a/client/src/layers/trace/index.tsx +++ b/client/src/layers/trace/index.tsx @@ -14,6 +14,7 @@ import { colorsHex, getColorHex } from "components/renderer/colors"; import { parseString } from "components/renderer/parser/parseString"; import { useTraceParser } from "components/renderer/parser/parseTrace"; import { ParseTraceWorkerReturnType } from "components/renderer/parser/parseTraceSlave.worker"; +import { DebugLayerData } from "hooks/useBreakpoints"; import { useEffectWhen } from "hooks/useEffectWhen"; import { LayerController, inferLayerName } from "layers"; import { @@ -99,7 +100,7 @@ export type TraceLayerData = { trace?: UploadedTrace; parsedTrace?: ParseTraceWorkerReturnType; onion?: "off" | "transparent" | "solid"; -} & PlaybackLayerData; +} & PlaybackLayerData & DebugLayerData; export type TraceLayer = Layer; diff --git a/client/src/pages/DebugPage.tsx b/client/src/pages/DebugPage.tsx index 57eb1d18..864b480b 100644 --- a/client/src/pages/DebugPage.tsx +++ b/client/src/pages/DebugPage.tsx @@ -1,5 +1,10 @@ import { TabContext, TabList, TabPanel } from "@mui/lab"; import { Box, Tab, Typography as Type } from "@mui/material"; +import { + LayersOutlined as LayersIcon, + SortOutlined as StepsIcon, +} from "@mui/icons-material"; +import { delay, map } from "lodash"; import { Flex } from "components/generic/Flex"; import { Space } from "components/generic/Space"; import { Switch } from "components/generic/Switch"; @@ -9,11 +14,16 @@ import { Page } from "pages/Page"; import { ReactNode, useState } from "react"; import { useUIState } from "slices/UIState"; import { BreakpointListEditor } from "../components/breakpoint-editor/BreakpointListEditor"; +import { useLayer } from "slices/layers"; +import { FeaturePicker } from "components/app-bar/FeaturePicker"; +import { inferLayerName, layerHandlers } from "layers/Layer"; + export function DebugPage() { const { controls, onChange, state } = useViewTreeContext(); const [{ monotonicF, monotonicG }, setUIState] = useUIState(); const [tab, setTab] = useState("standard"); + const { key, setKey, layers, layer } = useLayer(); function renderHeading(label: ReactNode) { return ( @@ -25,6 +35,17 @@ export function DebugPage() { + } + label="Layer" + value={key} + items={map(layers, (l) => ({ + id: l.key, + name: inferLayerName(l), + }))} + onChange={setKey} + showArrow + /> setTab(v)}> From 526d38c078e2eac670a21ef2939255b9674a5d5e Mon Sep 17 00:00:00 2001 From: francisanthony17 Date: Wed, 29 Nov 2023 15:59:23 +1100 Subject: [PATCH 2/4] delete .github for feature-debugger branch --- .github/workflows/main.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 70dcaf46..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Deploy to GitHub Pages -on: [push] -jobs: - build-and-deploy: - runs-on: ubuntu-latest - env: - CI: false - steps: - - name: Checkout - uses: actions/checkout@v2.3.1 - - - name: Install and Build - run: | - npm install - cd client && npm run build - - - name: Deploy - uses: JamesIves/github-pages-deploy-action@4.1.5 - with: - branch: gh-pages # The branch the action should deploy to. - folder: client/dist # The folder the action should deploy. From e5647be7a31630279d5348047e63e23e22f3b815 Mon Sep 17 00:00:00 2001 From: francisanthony17 Date: Thu, 30 Nov 2023 18:38:59 +1100 Subject: [PATCH 3/4] fix breakpoints so it corresponds with its layer --- .../BreakpointListEditor.tsx | 41 ++++++++++++++----- client/src/hooks/usePlaybackState.tsx | 4 +- client/src/pages/DebugPage.tsx | 31 +++++++------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/client/src/components/breakpoint-editor/BreakpointListEditor.tsx b/client/src/components/breakpoint-editor/BreakpointListEditor.tsx index b571c36d..c69df91c 100644 --- a/client/src/components/breakpoint-editor/BreakpointListEditor.tsx +++ b/client/src/components/breakpoint-editor/BreakpointListEditor.tsx @@ -1,14 +1,37 @@ import { Box } from "@mui/material"; import { ListEditor } from "components/generic/ListEditor"; -import { debounce, flatMap as flat, get, keys, map, uniq } from "lodash"; -import { Breakpoint, useUIState } from "slices/UIState"; +import { Breakpoint, DebugLayerData } from "hooks/useBreakpoints"; +import { flatMap as flat, get, keys, map, set, uniq } from "lodash"; +import { produce } from "produce"; +import { Layer, useLayer } from "slices/layers"; import { BreakpointEditor } from "./BreakpointEditor"; import { comparators } from "./comparators"; import { intrinsicProperties } from "./intrinsicProperties"; import { propertyPaths as paths } from "./propertyPaths"; -export function BreakpointListEditor() { - const [{ breakpoints = [] }, setUIState] = useUIState(); +type BreakpointListEditorProps = { + breakpoints: Breakpoint[] |undefined; + onValueChange?: (v: Breakpoint[]) => void; + layer: Layer |undefined + }; + +export function BreakpointListEditor({ + breakpoints, + onValueChange, + layer + }: BreakpointListEditorProps) { + + const {setLayer} = useLayer(); + + function handleBreakpointsChange(updatedBreakpoints: Breakpoint[]) { + onValueChange?.(updatedBreakpoints); + layer && + setLayer( + produce(layer, (layer) => + set(layer, "source.breakpoints" , updatedBreakpoints) + ) + ); + } const properties = uniq([ ...intrinsicProperties, @@ -26,7 +49,7 @@ export function BreakpointListEditor() { value={breakpoints} useDelete useEdit={false} - editor={(v) => } + editor={(v) => } //v = a breakpoint create={() => ({ active: true, property: properties?.[0], @@ -34,11 +57,9 @@ export function BreakpointListEditor() { type: undefined, reference: 0, })} - onChange={debounce( - (v) => setUIState(() => ({ breakpoints: v })), - 1000 - )} - addItemLabel="Breakpoint" + onChange={(updatedBreakpoints) => + handleBreakpointsChange(updatedBreakpoints) + } addItemLabel="Breakpoint" placeholderText="Click the button below to add a breakpoint." /> diff --git a/client/src/hooks/usePlaybackState.tsx b/client/src/hooks/usePlaybackState.tsx index f1cee4e9..78ba88eb 100644 --- a/client/src/hooks/usePlaybackState.tsx +++ b/client/src/hooks/usePlaybackState.tsx @@ -38,11 +38,11 @@ export function usePlaybackState(key?: string) { const callbacks = { play: () => { - notify("Playback started"); + // notify("Playback started"); setPlaybackState({ playback: "playing", step: stepBy(1) }); }, pause: (n = 0) => { - notify("Playback paused"); + // notify("Playback paused"); setPlaybackState({ playback: "paused", step: stepBy(n) }); }, stepTo: (n = 0) => setPlaybackState({ step: n }), diff --git a/client/src/pages/DebugPage.tsx b/client/src/pages/DebugPage.tsx index 864b480b..d1ab5a52 100644 --- a/client/src/pages/DebugPage.tsx +++ b/client/src/pages/DebugPage.tsx @@ -1,29 +1,28 @@ -import { TabContext, TabList, TabPanel } from "@mui/lab"; -import { Box, Tab, Typography as Type } from "@mui/material"; import { - LayersOutlined as LayersIcon, - SortOutlined as StepsIcon, + LayersOutlined as LayersIcon } from "@mui/icons-material"; -import { delay, map } from "lodash"; +import { TabContext, TabList, TabPanel } from "@mui/lab"; +import { Box, Tab, Typography as Type } from "@mui/material"; +import { FeaturePicker } from "components/app-bar/FeaturePicker"; import { Flex } from "components/generic/Flex"; import { Space } from "components/generic/Space"; import { Switch } from "components/generic/Switch"; import { useViewTreeContext } from "components/inspector/ViewTree"; import { ScriptEditor } from "components/script-editor/ScriptEditor"; +import { DebugLayerData } from "hooks/useBreakpoints"; +import { inferLayerName } from "layers/Layer"; +import { map, set } from "lodash"; import { Page } from "pages/Page"; +import { produce } from "produce"; import { ReactNode, useState } from "react"; -import { useUIState } from "slices/UIState"; -import { BreakpointListEditor } from "../components/breakpoint-editor/BreakpointListEditor"; import { useLayer } from "slices/layers"; -import { FeaturePicker } from "components/app-bar/FeaturePicker"; -import { inferLayerName, layerHandlers } from "layers/Layer"; - +import { BreakpointListEditor } from "../components/breakpoint-editor/BreakpointListEditor"; export function DebugPage() { const { controls, onChange, state } = useViewTreeContext(); - const [{ monotonicF, monotonicG }, setUIState] = useUIState(); const [tab, setTab] = useState("standard"); - const { key, setKey, layers, layer } = useLayer(); + const { key, setKey, layers, layer ,setLayer} = useLayer(); + const {monotonicF,monotonicG,breakpoints} = layer?.source??{} function renderHeading(label: ReactNode) { return ( @@ -61,20 +60,22 @@ export function DebugPage() { setUIState(() => ({ monotonicF: v }))} + disabled = {!layer} + onChange={(_, v) => layer && setLayer(produce(layer, (layer) => set(layer, 'source.monotonicF',v)))} /> setUIState(() => ({ monotonicG: v }))} + disabled = {!layer} + onChange={(_, v) => layer && setLayer(produce(layer, (layer) => set(layer, 'source.monotonicG',v)))} /> {renderHeading("Breakpoints")} - + {renderHeading("Export")} From 292e9806ee98efeab0e69a44966301380866c4a2 Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Thu, 30 Nov 2023 19:41:14 +1100 Subject: [PATCH 4/4] Improve steps page and debugger --- client/src/components/app-bar/Playback.tsx | 2 +- .../breakpoint-editor/BreakpointEditor.tsx | 24 ++-- .../BreakpointListEditor.tsx | 40 +++---- .../components/inspector/EventInspector.tsx | 4 +- client/src/pages/DebugPage.tsx | 67 ++++++----- client/src/pages/StepsPage.tsx | 112 +++++++----------- 6 files changed, 113 insertions(+), 136 deletions(-) diff --git a/client/src/components/app-bar/Playback.tsx b/client/src/components/app-bar/Playback.tsx index d46b2ec3..6a0edd7b 100644 --- a/client/src/components/app-bar/Playback.tsx +++ b/client/src/components/app-bar/Playback.tsx @@ -41,7 +41,7 @@ export function PlaybackService({ const notify = useSnackbar(); const [{ playbackRate = 1 }] = useSettings(); - const shouldBreak = useBreakpoints(); + const shouldBreak = useBreakpoints(value?.key); const renderLabel = useCallback( (label: ReactNode, offset: number) => ( diff --git a/client/src/components/breakpoint-editor/BreakpointEditor.tsx b/client/src/components/breakpoint-editor/BreakpointEditor.tsx index 6e429112..0e9016ad 100644 --- a/client/src/components/breakpoint-editor/BreakpointEditor.tsx +++ b/client/src/components/breakpoint-editor/BreakpointEditor.tsx @@ -1,13 +1,13 @@ -import { Divider, TextField, Typography as Type } from "@mui/material"; -import { find, last, map, startCase } from "lodash"; -import { comparators } from "./comparators"; -import { eventTypes } from "./eventTypes"; -import { Flex } from "components/generic/Flex"; -import { SelectField as Select } from "components/generic/Select"; -import { Space } from "components/generic/Space"; -import { Switch } from "components/generic/Switch"; -import { Breakpoint } from "slices/UIState"; - +import { Divider, TextField, Typography as Type } from "@mui/material"; +import { find, last, map, startCase } from "lodash"; +import { comparators } from "./comparators"; +import { eventTypes } from "./eventTypes"; +import { Flex } from "components/generic/Flex"; +import { SelectField as Select } from "components/generic/Select"; +import { Space } from "components/generic/Space"; +import { Switch } from "components/generic/Switch"; +import { Breakpoint } from "slices/UIState"; + type BreakpointEditorProps = { value: Breakpoint; onValueChange?: (v: Breakpoint) => void; @@ -23,7 +23,7 @@ export function BreakpointEditor({ onChange?.({ ...value, ...next }); } return ( - +