How the Dashboard Implements Persona-Adaptive UI for Different User Roles
The dashboard implements persona-adaptive UI by storing a global persona state in a Zustand store and using that value to conditionally render features, filter graph nodes, and toggle educational overlays across the application.
The Egonex-AI/Understand-Anything repository contains a sophisticated dashboard that dynamically adjusts its interface based on three distinct user roles: non-technical, junior, and experienced. This role-based adaptation ensures that non-technical stakeholders see simplified abstractions while experienced developers access full implementation details, all driven by a centralized state management system.
Core Architecture: The Persona State Store
The foundation of the adaptive UI resides in store.ts, which defines a Zustand store managing the global persona state. The store declares a strict Persona type union of the three roles and provides a setPersona function that handles both state updates and cache invalidation.
According to the source code in store.ts (lines 12–43), the setPersona implementation performs two critical operations:
- Updates the
personavalue in the store state - Clears layout caches including
containerLayoutCacheandexpandedContainersto force recomputation of container sizes and positions
This cache clearing ensures that UI elements dependent on the previous persona's layout constraints are recalculated immediately, preventing visual artifacts during role transitions.
Role Selection Interface
User role switching occurs through the PersonaSelector.tsx component (lines 5–38), which renders three distinct buttons corresponding to the available personas. When a user clicks a role button, the component invokes setPersona from the dashboard store, triggering a full UI re-render with the new role applied.
The selector component consumes the store using the standard Zustand pattern:
import { useDashboardStore } from "../store";
function PersonaSelector() {
const { persona, setPersona } = useDashboardStore((s) => ({
persona: s.persona,
setPersona: s.setPersona
}));
return (
<div className="persona-controls">
<button
onClick={() => setPersona("non-technical")}
className={persona === "non-technical" ? "active" : ""}
>
Non-Technical
</button>
<button onClick={() => setPersona("junior")}>Junior</button>
<button onClick={() => setPersona("experienced")}>Experienced</button>
</div>
);
}
Conditional Rendering Based on User Roles
Throughout the dashboard, components access the current persona via useDashboardStore((s) => s.persona) and apply conditional logic to determine feature visibility. This pattern creates a layered interface where complexity scales with user expertise.
Filtering Graph Complexity for Non-Technical Users
In GraphView.tsx (lines 372–444), the rendering engine consults the persona value to filter implementation details. When persona === "non-technical", the component returns early for function and class sub-nodes, hiding internal implementation details from stakeholders who only need high-level architectural views.
The filtering logic implements an explicit guard clause:
import { useDashboardStore } from "../store";
function GraphNode({ node }: { node: GraphNode }) {
const persona = useDashboardStore((s) => s.persona);
// Non-technical users never see function/class internals
if (persona === "non-technical" && subFileTypes.has(node.type)) {
return null;
}
return <NodeRenderer node={node} />;
}
Enabling Learn Mode for Junior Developers
Both MobileLayout.tsx (lines 42–66) and App.tsx (lines 234–393) treat the junior persona as a specialized "learn mode." When the persona matches "junior", the interface activates educational features including the Learn panel, onboarding overlays, and contextual help tooltips.
This implementation allows junior developers to access guided tours and explanatory content while experienced users work with a streamlined interface free from instructional overhead.
Persona-Aware Export Functionality
The ExportMenu.tsx component (lines 29–189) applies persona-specific filtering when serializing graph data for download. The export logic checks the current persona and applies node filters accordingly:
import { useDashboardStore } from "../store";
function exportGraph() {
const { graph, persona } = useDashboardStore.getState();
let filtered = graph.nodes;
if (persona === "non-technical") {
filtered = filtered.filter((n) => !subFileTypes.has(n.type));
}
// Serialize filtered nodes and trigger download
const exportData = JSON.stringify({ ...graph, nodes: filtered });
downloadFile(exportData, `graph-${persona}.json`);
}
This ensures that exported diagrams match the visual complexity level shown in the dashboard interface, maintaining consistency between the interactive view and static exports.
Cache Invalidation on Role Switch
The setPersona function in store.ts (lines 34–42) implements aggressive cache invalidation to support clean UI transitions. When the persona changes, the function clears containerLayoutCache, expandedContainers, and other layout-dependent state objects.
This invalidation guarantees that container sizes, node positions, and expand/collapse states do not persist incorrectly between personas. For example, a graph section expanded by an experienced user will not remain artificially expanded when a non-technical user switches roles, as the layout constraints must be recalculated for the simplified view.
Summary
- The dashboard uses a Zustand store (
store.ts) to manage global persona state across three roles: non-technical, junior, and experienced - PersonaSelector.tsx provides the UI controls for role switching, invoking
setPersonato trigger global state updates - GraphView.tsx filters implementation details for non-technical users by returning early on sub-file type nodes
- MobileLayout.tsx and App.tsx activate "learn mode" educational features specifically for the junior persona
- ExportMenu.tsx applies persona-specific filters to ensure exported data matches the UI complexity level
- Cache invalidation in
setPersonaclears layout caches to prevent visual artifacts during role transitions
Frequently Asked Questions
What are the three user personas defined in the dashboard?
The dashboard defines three personas in store.ts: non-technical (for stakeholders needing high-level abstractions), junior (for developers requiring educational guidance and learn mode), and experienced (for developers needing full implementation details). Each persona is stored as a string literal in the Persona type union and drives conditional rendering logic throughout the application.
How does the dashboard handle state transitions when switching personas?
When switching personas via setPersona in store.ts, the dashboard clears cached layout data including containerLayoutCache and expandedContainers (lines 34–42). This cache invalidation forces the UI to recompute container sizes and positions based on the new role's requirements, ensuring that layout artifacts from the previous persona do not persist.
Which components are affected by the persona setting?
The persona setting affects GraphView.tsx (node filtering), MobileLayout.tsx and App.tsx (learn mode toggles), and ExportMenu.tsx (export filtering). Additionally, PersonaSelector.tsx provides the interface for changing roles, while all components access the shared Zustand store via useDashboardStore((s) => s.persona).
How does the export functionality adapt to different user roles?
The ExportMenu.tsx component reads the current persona from the store and applies filters before serializing graph data. For non-technical users, it strips out function and class sub-nodes using the same subFileTypes filter applied in the visual graph, ensuring that exported diagrams match the simplified UI view rather than exposing implementation details.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →