Skip to content

Commit

Permalink
Merge pull request #38 from pietrzakacper/feature/searchEvents
Browse files Browse the repository at this point in the history
[inProgress]Feature/search events
  • Loading branch information
pietrzakacper authored Dec 27, 2024
2 parents b4b937b + 3b6395b commit be28c2a
Show file tree
Hide file tree
Showing 15 changed files with 451 additions and 139 deletions.
Binary file modified e2e-tests/bun.lockb
Binary file not shown.
5 changes: 3 additions & 2 deletions e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "",
"main": "index.js",
"devDependencies": {
"@playwright/test": "^1.42.1",
"@playwright/test": "^1.49.1",
"@types/bun": "^1.0.11",
"@types/node": "^20.11.30"
},
Expand All @@ -23,6 +23,7 @@
"license": "ISC",
"private": true,
"dependencies": {
"find-free-ports": "^3.1.1"
"find-free-ports": "^3.1.1",
"playwright": "^1.49.1"
}
}
Binary file modified frontend/bun.lockb
Binary file not shown.
4 changes: 4 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-table": "^8.12.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"fast-equals": "^5.0.1",
"history": "^5.3.0",
"lucide-react": "^0.338.0",
"mark.js": "^8.11.1",
"prism-react-renderer": "^2.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.3.0",
"react-json-tree": "^0.18.0",
"react-json-view": "^1.21.3",
"react-mark.js": "^9.0.7",
"tailwind-merge": "^2.2.1",
"tailwindcss-animate": "^1.0.7",
"tracethat.dev": "../reporters/javascript/tracethat.dev",
Expand Down
59 changes: 59 additions & 0 deletions frontend/src/components/ui/toggle-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from "react"
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
import { type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"
import { toggleVariants } from "@/components/ui/toggle"

const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants>
>({
size: "default",
variant: "default",
})

const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center justify-center gap-1", className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
))

ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName

const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext)

return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
}),
className
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
)
})

ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName

export { ToggleGroup, ToggleGroupItem }
43 changes: 43 additions & 0 deletions frontend/src/components/ui/toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from "react"
import * as TogglePrimitive from "@radix-ui/react-toggle"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const toggleVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-10 px-3",
sm: "h-9 px-2.5",
lg: "h-11 px-5",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)

const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
))

Toggle.displayName = TogglePrimitive.Root.displayName

export { Toggle, toggleVariants }
19 changes: 19 additions & 0 deletions frontend/src/hooks/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useState, useEffect } from 'react';

export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);

useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);

return () => {
clearTimeout(handler);
};
}, [value, delay]);

return debouncedValue;
}

export default useDebounce;
11 changes: 11 additions & 0 deletions frontend/src/hooks/usePrevious.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useEffect, useRef } from "react";

export function usePrevious<T>(value: T) {
const ref = useRef<T>();

useEffect(() => {
ref.current = value;
});

return ref.current;
}
15 changes: 15 additions & 0 deletions frontend/src/hooks/useRemount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useState } from "react";

export function useRemount() {
const [mounted, setMounted] = useState(true);

return {
mounted,
remount: () => {
setMounted(false);
setTimeout(() => {
setMounted(true);
}, 0);
},
};
}
81 changes: 67 additions & 14 deletions frontend/src/layouts/EventViewer/EventViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,55 @@ import { TraceEvent } from "@/validators/TraceEvent";
import { Loader2, X } from "lucide-react";
import { ReactNode, useMemo } from "react";
import ReactJson, { ThemeObject } from "react-json-view";
import { Marker } from "react-mark.js";
import { useRef, useEffect, useState } from "react";
import { SearchBy } from "../EventsSearch/EventsSearch";

interface EventViewerProps {
events: TraceEvent[];
selectedEventCallId: string | null;
onEventClose: () => void;
viewerPlaceholder: ReactNode;
searchValue: string;
searchBy: SearchBy;
}
export const EventViewer = ({ events, selectedEventCallId, onEventClose, viewerPlaceholder }: EventViewerProps) => {

export const EventViewer = ({
events,
selectedEventCallId,
onEventClose,
viewerPlaceholder,
searchValue,
searchBy,
}: EventViewerProps) => {
const [searchValueMarker, setSearchValueMarker] = useState({ searchValue });

useEffect(() => {
setSearchValueMarker({ searchValue: searchValue });
}, [searchValue, searchBy]);

const jsonViewerRef = useRef(null);
useEffect(() => {
// New properties might appear in the JSON
// and we need to remount the higlighter so it picks up the changes
const observer = new MutationObserver((mutationsList) => {
if ((mutationsList[0].target as HTMLElement).className === "icon-container") {
setSearchValueMarker({ searchValue: searchValue });
}
});

if (jsonViewerRef.current) {
observer.observe(jsonViewerRef.current, {
childList: true,
subtree: true,
});
}

return () => {
observer.disconnect();
};
}, [events, selectedEventCallId, onEventClose, viewerPlaceholder, searchValue, searchBy]);

const selectedEvent = useMemo(() => {
if (selectedEventCallId == null) {
return undefined;
Expand Down Expand Up @@ -84,19 +125,31 @@ export const EventViewer = ({ events, selectedEventCallId, onEventClose, viewerP

<div className="p-4 overflow-auto flex-1">
<div className="font-mono select-text p-4 rounded-sm bg-muted overflow-x-auto w-full">
<ReactJson
// Needed to properly handle theme changes
key={theme.theme}
src={selectedEvent.details}
theme={viewerTheme}
iconStyle="square"
displayDataTypes={false}
displayObjectSize={false}
indentWidth={4}
enableClipboard={true}
style={{ fontFamily: "inherit", background: "none" }}
shouldCollapse={({ name }) => name !== "root"}
/>
<div ref={jsonViewerRef}>
<Marker mark={searchValueMarker.searchValue}>
<ReactJson
// Needed to properly handle theme changes
key={theme.theme}
src={selectedEvent.details}
theme={viewerTheme}
iconStyle="square"
displayDataTypes={false}
displayObjectSize={false}
indentWidth={4}
enableClipboard={true}
style={{ fontFamily: "inherit", background: "none" }}
shouldCollapse={({ name, src }) => {
if (searchBy === "eventName" || searchValue === "") {
return name !== "root";
}

const isSearchedDataHere = JSON.stringify(src).toLowerCase().includes(searchValue.toLowerCase());

return !isSearchedDataHere;
}}
/>
</Marker>
</div>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit be28c2a

Please sign in to comment.