Skip to content

Commit

Permalink
Dependency Graph UI/UX changes (#10612)
Browse files Browse the repository at this point in the history
  • Loading branch information
bvaughn authored Jul 16, 2024
1 parent def150b commit c0b288e
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 303 deletions.
9 changes: 6 additions & 3 deletions packages/accordion/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {
FC,
MouseEventHandler,
ReactElement,
ReactNode,
useEffect,
useReducer,
useRef,
Expand Down Expand Up @@ -75,9 +76,9 @@ export function AccordionPane({
dispatch = () => ({}),
expanded,
header,
headerNode,
height = 0,
index,
initialHeight,
isBeingResized = false,
isResizable = false,
onResizeStart = () => ({}),
Expand All @@ -90,9 +91,9 @@ export function AccordionPane({
dispatch?: Dispatch<AccordionAction>;
expanded?: boolean;
header: string;
headerNode?: ReactNode;
height?: SectionHeight;
index?: number;
initialHeight?: number;
isBeingResized?: boolean;
isResizable?: boolean;
onResizeStart?: (e: React.MouseEvent) => void;
Expand Down Expand Up @@ -128,7 +129,9 @@ export function AccordionPane({
>
<div className="flex select-none items-center space-x-2">
<div className={classNames("img arrow", { expanded: _expanded })} />
<span className="overflow-hidden overflow-ellipsis whitespace-pre">{header}</span>
<span className="overflow-hidden overflow-ellipsis whitespace-pre">
{headerNode ?? header}
</span>
</div>
{button ? button : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export default function PrimaryPanes() {
className={classnames("sources-pane", enableLargeText ? "text-base" : "text-xs")}
expanded={!sourcesCollapsed}
onToggle={() => setSourcesCollapsed(!sourcesCollapsed)}
initialHeight={400}
button={<QuickOpenButton />}
>
<SourcesTree />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.Panel {
display: flex;
flex-direction: column;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ExecutionPoint } from "@replayio/protocol";
import { Suspense, useContext } from "react";

import { PanelLoader } from "replay-next/components/PanelLoader";
import { ReplayClientContext } from "shared/client/ReplayClientContext";
import { DependencyGraphMode } from "shared/client/types";
import { depGraphCache } from "ui/suspense/depGraphCache";

import { Item } from "./Item";
import styles from "./DependencyGraph.module.css";

type Props = {
mode?: DependencyGraphMode;
point: ExecutionPoint | undefined;
};

export function DependencyGraph(props: Props) {
return (
<Suspense fallback={<PanelLoader />}>
<DependencyGraphSuspends {...props} />
</Suspense>
);
}

function DependencyGraphSuspends({ mode, point }: Props) {
const replayClient = useContext(ReplayClientContext);

const depGraphValue = depGraphCache.read(replayClient, point ?? null, mode ?? null);
const valueDescending = depGraphValue?.slice().reverse();

return (
<div className={styles.Panel}>
{valueDescending?.map((entry, index) => (
<Item
key={index}
isCurrent={index === 0}
location={null}
name={entry.code}
timeStampedPoint={
entry.point != null && entry.time != null
? {
point: entry.point,
time: entry.time,
}
: null
}
/>
))}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.Item {
padding: 0.25rem 0.5rem;
display: flex;
flex-direction: row;
gap: 0.25rem;
white-space: nowrap;
}
.Item:hover {
background-color: var(--theme-selection-background-hover);
cursor: pointer;
}
.Item[data-selected] {
background-color: var(--theme-selection-background);
color: white;
}
.Item[data-disabled] {
color: var(--color-dim);
}
.Item[data-disabled]:hover {
background-color: transparent;
cursor: default;
}

.NameColumn {
overflow: hidden;
text-overflow: ellipsis;
}

.TimestampColumn {
flex: 1;
font-size: var(--font-size-small);
overflow: hidden;
text-overflow: ellipsis;
}

.LocationColumn {
color: var(--color-dim);
flex-grow: 0;
flex-shrink: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.Item[data-selected] .LocationColumn {
display: none;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { TimeStampedPoint } from "@replayio/protocol";

import { getRawSourceURL } from "devtools/client/debugger/src/utils/source";
import { getURL } from "devtools/client/debugger/src/utils/sources-tree";
import { formatTimestamp } from "replay-next/src/utils/time";
import { seek } from "ui/actions/timeline";
import { useAppDispatch } from "ui/setup/hooks";
import { LocationWithUrl } from "ui/suspense/depGraphCache";

import styles from "./Item.module.css";

export function Item({
isCurrent,
name,
location,
timeStampedPoint,
}: {
name: string;
isCurrent?: boolean;
location: LocationWithUrl | null;
timeStampedPoint: TimeStampedPoint | null;
}) {
const dispatch = useAppDispatch();

const onClick = () => {
timeStampedPoint &&
dispatch(
seek({
executionPoint: timeStampedPoint.point,
openSource: true,
time: timeStampedPoint.time,
})
);
};

let source = null;
if (location) {
source = `${getRawSourceURL(getURL(location).filename)}:${location.line}`;
}

return (
<div
className={styles.Item}
data-selected={isCurrent || undefined}
data-disabled={!timeStampedPoint || undefined}
onClick={isCurrent ? undefined : onClick}
title={location?.url}
>
<div className={styles.NameColumn}>{name}</div>
{timeStampedPoint && (
<div className={styles.TimestampColumn}>({formatTimestamp(timeStampedPoint.time)})</div>
)}
{source && <div className={styles.LocationColumn}>{source}</div>}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PropsWithChildren } from "react";

export function Message({ children }: PropsWithChildren) {
return <div className="w-full py-2 text-center italic">{children}</div>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.Panel {
display: flex;
flex-direction: column;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { TimeStampedPoint } from "@replayio/protocol";
import { Suspense, useContext } from "react";

import { Message } from "devtools/client/debugger/src/components/SecondaryPanes/DependencyGraph/Message";
import { PanelLoader } from "replay-next/components/PanelLoader";
import { ReplayClientContext } from "shared/client/ReplayClientContext";
import { reactComponentStackCache } from "ui/suspense/depGraphCache";

import { Item } from "./Item";

type Props = {
timeStampedPoint: TimeStampedPoint | null;
};

export function ReactComponentStack(props: Props) {
return (
<Suspense fallback={<PanelLoader />}>
<ReactComponentStackSuspends {...props} />
</Suspense>
);
}

function ReactComponentStackSuspends({ timeStampedPoint }: Props) {
const replayClient = useContext(ReplayClientContext);
const reactStackValue = reactComponentStackCache.read(replayClient, timeStampedPoint ?? null);

if (!timeStampedPoint) {
return <Message>Not paused at a point</Message>;
}

if (!reactStackValue || reactStackValue.length === 0) {
return <Message>No frames to display</Message>;
}

const firstItem = reactStackValue[0];

return (
<>
{firstItem && (
<Item
isCurrent
location={firstItem.componentLocation}
name={firstItem.componentName}
timeStampedPoint={firstItem}
/>
)}
{reactStackValue?.map((entry, index) => (
<Item
key={index}
location={entry.parentLocation}
name={entry.parentComponentName}
timeStampedPoint={entry}
/>
))}
</>
);
}
Loading

0 comments on commit c0b288e

Please sign in to comment.