Skip to content

Refactor editor and optimize performance with UI enhancements#72

Open
ndom91 wants to merge 34 commits intostrongdm:mainfrom
ndom91:cleanup-controlui-frontend
Open

Refactor editor and optimize performance with UI enhancements#72
ndom91 wants to merge 34 commits intostrongdm:mainfrom
ndom91:cleanup-controlui-frontend

Conversation

@ndom91
Copy link
Copy Markdown

@ndom91 ndom91 commented Apr 12, 2026

Great project! As a frontend web dev I really wanted to help improve the control UI though 😊

In short, these are the UI/UX changes:

  • Split the policy editing and event viewing into two separate tabs / pages (selector in the top-right)
  • Use flexbox for layout instead of ResizeObserver and dynamically calculated JS heights
  • Event viewer table now leverages the @tanstack/react-virtual package that was installed but never used to actually virtualize all the rows of incoming events so you can show more than 50 at a time. I've had 10k+ in simulated mode with great performance still
  • Event viewer now pauses the view, so to speak, when you scroll down so that you can clearly read the rows of data as new stuff comes in without them getting pushed away. This "paused" view then shows a button "Back to the top" that also has a count on it for how many new items have come in. Clicking it takes you back to the top to the live scrolling view of new events
  • Minor redesign of the event viewer rows as well as the global header
  • Align scrollbar styles with the rest of the app
  • A bunch of minor web best practices like making the cursor pointer on hover of buttons and html attributes like autocomplete=off on forms, etc.
  • Rm a few unused dependencies
  • Dynamically import / load the big fakerjs dependency when loading simulator mode
  • Replaced the heavy monaco editor with a much more lightweight one (we dont need an entire vscode-like experience here, right)

Screenshots

CleanShot 2026-04-12 at 18 40 37 CleanShot 2026-04-12 at 18 46 06

AI Summary

This pull request makes several UI and dependency changes to the policy console and events stream in the web app. The main improvements include a visual and interaction redesign of the events stream table, dependency cleanup and replacement for code editing, and enhancements to test reliability. The changes also add custom syntax highlighting for the Cedar policy editor and update how the main page switches between tabs.

UI/UX Improvements:

  • The events stream table (ActionsStream) is visually redesigned: rows have a colored left accent for allow/deny, badges are color-coded by event type, and action buttons are more compact and only visible on hover. The repeat count is always shown, and tooltips are simplified. [1] [2]
  • The events and policy editor now live in separate tabs, with tab state managed in page.tsx. The policy editor uses the new CedarEditor with Prism-based syntax highlighting. [1] [2]

Dependency and Editor Changes:

  • Removes unused or replaced dependencies (@monaco-editor/react, monaco-editor, reactflow, @xyflow/react, framer-motion) and adds prismjs, react-simple-code-editor, and types for PrismJS to support the new code editor. [1] [2]

Testing Improvements:

  • Mocks the virtualizer in ActionsStream tests to ensure all rows render in the test environment, making tests deterministic regardless of jsdom layout.
  • Updates test queries to correctly count data rows, ignoring spacer and header rows, and updates text assertions for new wording ("2 events" instead of "2 shown"). [1] [2]

Styling and Theming:

  • Adds custom scrollbar styling and removes many unused theme variables and animation keyframes from globals.css. [1] [2]
  • Adds Prism token color rules for the Cedar policy editor for improved syntax highlighting.

Code Cleanup:

  • Removes unused callback dependencies and cleans up event handler logic in the main console page.

These changes collectively modernize the UI, improve maintainability, and enhance the developer and user experience.

ndom91 and others added 30 commits April 12, 2026 17:29
Monaco (~300KB) was loaded eagerly for a policy editor panel that starts
collapsed. Replace with react-simple-code-editor (~3KB) + a custom Prism
grammar for Cedar syntax highlighting (~6KB total).

- Remove @monaco-editor/react and monaco-editor dependencies
- Add react-simple-code-editor and prismjs
- Rewrite cedar-language.ts with a Prism grammar (keywords, entities,
  strings, comments, operators)
- Rewrite cedar-editor.tsx: textarea-based editor with Prism highlighting,
  debounced validation, lint error display below editor
- Add Cedar token color styles to globals.css
- Update cedar-editor tests for the new component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
faker (~6MB) was imported at the top level of sim.tsx, bundled
unconditionally even in live mode. Now it is dynamically imported
when simulation mode activates, with synchronous fallback strings
used until the import resolves (typically <100ms).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Apply content-visibility: auto with contain-intrinsic-size to offscreen
action rows. The browser skips layout and paint for rows below the fold,
reducing initial render cost when the table has many rows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
handlePolicyRemoved was doing an optimistic filter via functional
setState then immediately calling loadLines() which overwrites the
state with a full refetch — wasting the filter. The delete handler
in PolicyBlockCard already calls refresh(), so the optimistic filter
is sufficient here.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 8-bar equalizer animation at the bottom of ActionsStream was
recreating 8 div elements on every render. Move to a module-level
constant so React reuses the same element tree.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add an Events/Policy tab switcher to the header bar alongside the
existing Sim/Live toggle. The events stream and policy editor now
render on separate tabs instead of a single combined layout.

- Add PageTab type and activeTab/onTabChange props to DataSourceControls
- Lift tab state to SingleConsolePage, pass down to header and content
- Events tab: ActionsStream (filterable event table)
- Policy tab: CedarEditorCollapsible + SingleHeader + PolicyBlockCards
- Policy lines stay loaded across tab switches for instant switching
- PromptBanner remains visible on both tabs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the collapsible Cedar editor with the full editor always
rendered on the left (2/3 width), and the enforcement toggle +
individual policy line cards on the right (1/3 width). On mobile
the layout stacks vertically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the hard-capped 50-row table with a virtualized list that
can scroll through all filtered events (up to 25,000). Only ~30 rows
are in the DOM at any time via the virtualizer with padding spacers.

- Wire up useVirtualizer with 44px estimated row height and 15-row overscan
- Remove the .slice(0, 50) cap on filtered results
- Replace content-visibility CSS (superseded by virtualization)
- Update summary label to show total filtered count
- Mock useVirtualizer in tests to render all rows in jsdom

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove redundant pr-2 padding on the scroll container. The
scrollbarGutter: stable property already reserves space for the
scrollbar natively — the extra padding was doubling the gap and
making the header row visibly shorter than the container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add thin cyan-tinted scrollbars globally using both the standard
scrollbar-width/scrollbar-color properties and webkit pseudoelements.
6px wide, transparent track, cyan-glow thumb at 30% opacity (50% on
hover), rounded corners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sticky thead had bg-slate-900/80 (semi-transparent) causing
scrolled rows to bleed through, and text was at cyan-400/70. Change
to solid bg-slate-900 and full cyan-400 text for a clean header that
doesn't show content underneath when scrolling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add h-9 to the Simulated/Connected badge in the header and the
events count badge in the events view so they align vertically
with the adjacent TabsList components (also h-9).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All tab triggers (data source, allowed/denied, event type, page tabs)
now show a pointer cursor on hover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Shrink logo from 64px to 36px, title from text-6xl to text-2xl
- Remove the separate "Data Source" label + text display section
- Move the Sim/Live tab selector inline next to the logo, with the
  status badge and WS URL beside it
- Reduce padding, margins, and gaps throughout the header bar
- Page tabs (Events/Policy) remain on the right side

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reduce main padding from p-6 to px-4 py-3 and gaps from space-y-4
  to space-y-3
- Remove redundant mb-4 from header
- Reduce viewport gutter from 24px to 12px so the events pane
  extends closer to the bottom edge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add cursor-pointer to the Button component base styles so all
  buttons (download, policy add/deny, etc.) show a pointer on hover
- Remove the Tooltip wrapper on the event detail cell — it showed
  identical content on hover and added no value

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the 8-bar pulsing equalizer animation in the bottom-right of
the events table status bar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the user scrolls down, the visible actions list is frozen so
rows stay stable for reading and interaction. New events accumulate
silently. The "Resume (N new)" button in the action bar above the
table shows how many events arrived since pausing. Clicking it or
scrolling back to the top unfreezes the list and resumes live mode.

- Snapshot actions into frozenActions on scroll-away
- Virtualizer renders from frozenActions while paused
- Resume button in toolbar (after events badge) with new-event count
- "Paused" indicator in the footer status bar
- Scrolling to top auto-resumes live mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Row improvements:
- 3px left-edge color accent (green=allowed, red=denied)
- Color-coded event type badges by category
- Compact decision column with small dot + text
- Repeat count shown as ×N only when > 1
- Policy buttons appear on hover only
- Tighter padding and smaller fonts throughout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Filter input: placeholder ... → …, add aria-label, autocomplete="off"
- Logo img: add explicit width/height attributes (prevents CLS)
- StrongDM link: add visible hover state (underline + color shift)
- Cedar editor textarea: add focus-visible ring to replace outline:none
- html element: add color-scheme: dark (fixes native input/scrollbar)
- Metadata: add page title

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The collapsible wrapper became dead code when the policy tab switched
to rendering CedarEditor directly. Remove both the component and its
test file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace redundant window resize listener + ResizeObserver on
  pane/parent/body with a single ResizeObserver on the pane and
  document.documentElement (covers both element and viewport changes)
- Delete 8 unused shadcn/ui components: dropdown-menu, scroll-area,
  navigation-menu, avatar, separator, label, card, table
- Remove 6 corresponding @radix-ui dependencies from package.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reorder columns: accent | time | event | detail | actions | decision | #
- Policy allow/deny buttons now sit between Detail and Decision
- Count column: bump from 10px to text-xs, drop × prefix, lighter
  color for single-count rows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove animated gradient overlay (body::after) and its keyframe —
  the biggest "AI template" tell
- Remove cyan glow blur behind the logo
- Remove gradient glow line at top of events pane
- Remove backdrop-blur from header and events pane (no visual
  benefit on solid dark backgrounds, saves GPU compositing)
- Replace "?" tooltip empty state with inline text
- Migrate hardcoded border-cyan-500/30 to border-border throughout
  (header, tabs, input, pane, thead, status bar)
- Migrate hardcoded text colors in status bar and badge to
  text-muted-foreground for consistency
- Bump status bar text from text-[10px] to text-xs for readability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the .slice(0, 5) cap and "...and N more" truncation from both
the inline lint error list and the confirmation modal. All errors are
now rendered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Simulated/Live toggle and connection status badge are only
relevant to the events stream. Hide them when the Policy tab is
active for a cleaner header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename "Resume" to "Back to top" and switch from amber to emerald
to match the Simulated/Connected badge color scheme.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change editor container from bg-slate-950/60 to bg-slate-900/60 and
border-cyan-500/30 to border-border, matching the events table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add rounded-lg border border-border bg-slate-900/60 to the Policy
Editor sub-header so it matches the card style used throughout the
rest of the UI. Also use border-border on the Start Permissive
button and text-muted-foreground on the description.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ndom91 and others added 4 commits April 12, 2026 18:46
Match padding (py-2.5), background (bg-slate-900/60), border
(border-border), and font weight to the policy editor header card
so both sit at the same height. Remove backdrop-blur.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace conditional rendering (unmount/remount) with CSS display
toggling so both Events and Policy tabs stay mounted across switches.
This eliminates the lag from re-initializing the virtualizer, filters,
ResizeObserver, and editor on every tab change. Scroll position and
component state are preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The events pane was using a ResizeObserver + JS to measure and set
its height, which caused body overflow and layout jank. Replace with
a proper flex column from html/body through main/section/pane:

- body: h-screen flex flex-col overflow-hidden
- main: flex-1 flex flex-col min-h-0
- section/tab wrappers: flex-1 flex flex-col min-h-0
- events pane: flex-1 min-h-0 (fills remaining space naturally)

Remove the ResizeObserver effect, paneRef, paneHeight state,
MIN_EVENTS_PANE_HEIGHT, and VIEWPORT_GUTTER_PX constants. Remove
min-height: 100vh from body CSS. Gaps are now consistent gap-3
throughout the layout chain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SingleProvider:
- Remove unused "shadow" mode from SingleMode type
- Remove unused paused/setPaused/profile/setProfile state
- Remove unused useSingleOptional export

PolicyBlocksContext + reducer:
- Remove unused editorOpen state and toggleEditor/openEditor/closeEditor
- Remove unused clearNotice action (auto-cleared by setTimeout)
- Simplify reducer to 4 actions: SET_DRAFT, SHOW_NOTICE, CLEAR_NOTICE,
  INIT_DRAFT

CedarEditor:
- Remove duplicate inline notice span (keep fixed bottom-right panel)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant