CSR Cockpit Integration
CSR Cockpit Integration
The CSR Cockpit has two separate interfaces with different audiences and different role mappings. Both embed the same widget — configured differently.
Prerequisites
@teei/chat-widgetinstalled (see Integration Guide)@astrojs/reactalready configured incsr-cockpit/astro.config.mjs(it is)- RAG Worker running at
https://knowledge-api.theeducationalequalityinstitute.org - Widget CSS imported once globally
Interface 1 — Manager Dashboard
URL pattern: /{company-slug}/ and all sub-routes
Layout file: csr-cockpit/src/layouts/CockpitLayout.astro
Audience: CSR managers at partner companies
Role values: viewer, csr_manager, company_admin, platform_admin
Role mapping
The CSR Cockpit uses a 5-role permission system (CockpitRole). Map these to the knowledge widget’s simpler role hierarchy:
// In CockpitLayout.astro frontmatterconst KNOWLEDGE_ROLE_MAP: Record<string, string> = { viewer: 'employee', // read-only manager — same content as employees csr_manager: 'manager', // full CSR manager access company_admin: 'manager', // company administrator platform_admin: 'admin', // TEEI platform administrator};
// managerRole comes from resolvePageContext() / page-auth.tsconst knowledgeRole = KNOWLEDGE_ROLE_MAP[managerRole] ?? 'employee';Step-by-step installation
Step 1: Open csr-cockpit/src/layouts/CockpitLayout.astro.
Step 2: Add the import at the top of the frontmatter block, with the other React component imports:
---// Existing importsimport { AnnotationOverlay } from "../components/annotations/AnnotationOverlay";
// Add these two lines:import { ChatProvider, ChatWidget } from '@teei/chat-widget';import '@teei/chat-widget/styles';---Step 3: Add the role mapping in the frontmatter, after managerRole is resolved:
---// ... existing resolvePageContext() call
const KNOWLEDGE_ROLE_MAP: Record<string, string> = { viewer: 'employee', csr_manager: 'manager', company_admin: 'manager', platform_admin: 'admin',};
const knowledgeRole = KNOWLEDGE_ROLE_MAP[managerRole] ?? 'employee';---Step 4: Add the widget to the layout body, immediately before </body>. Place it after <AnnotationOverlay> to avoid z-index conflicts (the annotation overlay uses z-index 9994; the chat widget uses z-index 9999):
<!-- Existing components --> {isAnnotationsEnabled() && ( <AnnotationOverlay client:load transition:persist /> )}
<!-- TEEI Knowledge Assistant --> <ChatProvider client:idle apiUrl="https://knowledge-api.theeducationalequalityinstitute.org" platform="csr-cockpit" userRole={knowledgeRole} language="en" > <ChatWidget /> </ChatProvider>
</body>Step 5: Verify the build:
cd teei-astro/csr-cockpitnpx astro checknpm run buildStep 6: Verify the widget renders:
curl -I http://localhost:6410/demo/# → HTTP/2 200Open http://localhost:6410/demo/ in a browser. You should see the TEEI chat FAB (floating blue circle) in the bottom-right corner. Click it to open the panel.
Interface 2 — Employee Portal
URL pattern: /{company-slug}/portal/ and all sub-routes
Layout file: csr-cockpit/src/layouts/PortalLayout.astro (if it exists) or the portal pages directly
Audience: Employees participating in volunteering programmes
Role: Always employee
Employees access a simplified view of company volunteering data. They should receive volunteer-level knowledge content — how to log hours, programme overviews, mentor guides.
Step-by-step installation
Step 1: Locate the portal layout. If a shared portal layout exists:
find csr-cockpit/src -name "*Portal*Layout*" -o -name "*portal*layout*" 2>/dev/nullIf no portal-specific layout exists, add the widget to each portal page directly (see pattern below).
Step 2: In the portal layout or portal page frontmatter:
---import { ChatProvider, ChatWidget } from '@teei/chat-widget';// Styles only need to be imported once — skip if already imported in a parent layout---Step 3: Add the widget to the portal body:
<!-- TEEI Knowledge Assistant — Employee Portal --> <ChatProvider client:idle apiUrl="https://knowledge-api.theeducationalequalityinstitute.org" platform="csr-portal" userRole="employee" language="en" > <ChatWidget greeting="Hi! I can help you find volunteer opportunities, log hours, and navigate the portal. What do you need?" /> </ChatProvider>Note platform="csr-portal" (not csr-cockpit) — this ensures the widget only retrieves content tagged for the portal context, not manager-only content.
Demo company considerations
The CSR Cockpit has a public demo at /demo/. The widget should work in demo mode. When isDemoCompany is true, the widget can still render — it simply queries with whatever role the demo session provides.
If you want to show a demo-specific greeting:
---const widgetGreeting = isDemo ? "Hi! This is the TEEI Knowledge Assistant demo. I can answer questions about the CSR Cockpit's features. What would you like to know?" : undefined; // undefined falls back to the default greeting---
<ChatProvider client:idle apiUrl={...} platform="csr-cockpit" userRole={knowledgeRole}> <ChatWidget greeting={widgetGreeting} /></ChatProvider>Z-index reference (CSR Cockpit)
Existing overlay z-indexes in CSR Cockpit:
| Component | z-index |
|---|---|
| AnnotationOverlay FAB | 9994 |
| AnnotationOverlay panel | 9995 |
| CommandPalette | 9996 |
| DemoExitIntent modal | 9997 |
| DemoContactDrawer | 9998 |
| Chat Widget FAB | 9999 |
| Chat Widget panel | 9999 |
The chat widget’s z-index is set via --teei-chat-z: 9999 in the widget CSS. If you experience stacking conflicts, override this CSS variable:
/* In csr-cockpit/src/styles/cockpit-layout.css */.teei-chat-widget { --teei-chat-z: 9990; /* Lower than DemoExitIntent if needed */}Verification checklist
-
npx astro checkexits 0 (no TypeScript errors) -
npm run buildexits 0 -
curl -I http://localhost:6410/demo/returns 200 - Chat FAB visible at bottom-right of
/demo/at 1440px - Chat panel opens on FAB click
- Sending a message produces a streamed response
- Widget does not appear on
/portal/login(excluded path) - No console errors in browser DevTools
Gotchas
React hydration conflict with client:visible: The widget uses client:idle. Do not change this to client:visible — it is banned in CSR Cockpit’s CLAUDE.md.
jsxDEV is not a function during dev: This is a known Vite esbuild gotcha in CSR Cockpit (documented in astro.config.mjs). The fix is already in place via optimizeDeps.esbuildOptions.define. If the widget component triggers this, clear the Vite cache: rm -rf node_modules/.vite.
Dark mode: The widget reads [data-theme="dark"] from the document root. CSR Cockpit sets this attribute via its theme toggle. No extra configuration is needed — dark mode works automatically.
Annotations overlay click-intercept: The AnnotationOverlay .ann-click-overlay intercepts pointer events when active. The chat widget uses z-index: 9999 (above the annotation overlay at 9994–9995). If click interception prevents the chat FAB from receiving clicks, check that the annotation overlay is not in active intercept mode.