@tgdcbr/t-analytics-web
v0.1.3
Published
Wise Analytics web component for natural-language driven analytics
Maintainers
Readme
@wise/analytics-web
A reusable web component that lets users request analytics in natural language and renders the resulting chart + table using signed report URLs. The component follows a data-first approach where tables are shown immediately and charts are only generated when explicitly requested by users.
<wise-analytics
mcp-gateway="/api/mcp"
auth-token="tenant:demo"
theme="auto"
></wise-analytics>Installation
npm install @wise/analytics-web vega vega-lite vega-embedPeer dependencies (vega, vega-lite, vega-embed) are resolved from the host
application. lit ships as a regular dependency so you do not have to install it
separately.
Attributes & properties
| Name | Type | Default | Description |
|------|------|---------|-------------|
| mcp-gateway (mcpGateway) | string | '' | Base URL for the MCP gateway (/api/mcp in the reference backend). |
| auth-token (authToken) | string | '' | Bearer token passed to the gateway and report API. |
| token-provider (tokenProvider) | () => Promise<string> | – | Async callback invoked before authenticated requests. Useful for refreshing expiring tokens. |
| request-middleware (requestMiddleware) | (req: Request) => Promise<Request> | – | Hook that can mutate the outgoing Request (headers, tracing, custom fetch) before dispatch. |
| fetcher | (req: Request) => Promise<Response> | – | Override used to perform network requests (preferred over the legacy WISE_FETCH_SYMBOL). |
| report-urls (reportUrls) | { report_id, structure_url, data_url } | – | Skip the MCP gateway and render a pre-resolved report directly. |
| theme | 'auto' \| 'light' \| 'dark' | 'auto' | Controls the built-in light/dark presets. auto follows the OS preference. |
| mode | 'visual' \| 'headless' | 'visual' | Render the default charts/tables or emit render-done with { structure, data } so the host can render with any library. |
| credentials-mode (credentialsMode) | 'include' \| 'omit' \| 'same-origin' | – | Sets RequestInit.credentials for cookie-based auth. |
| library | string | 'vega-lite@5' | Default chart renderer if the structure does not declare one. |
| max-rows (maxRows) | number | 100 | Maximum number of rows rendered in the preview table. |
| page-size (pageSize) | number | 50 | Number of rows requested per page when fetching /data. |
| debug | boolean | false | Enables verbose console logging of request/response metadata. |
Methods
All methods return Promise instances unless otherwise noted.
createReport(prompt: string, hints?: Record<string, unknown>)- Calls
POST {mcp-gateway}/create_reportand renders the resulting report.
- Calls
openReport(reportId: string)- Calls
POST {mcp-gateway}/get_report_urlsand renders the resolved report.
- Calls
refresh()- Re-fetches the last rendered
structure_url/data_urlpair.
- Re-fetches the last rendered
setToken(jwt: string)- Updates the bearer token at runtime.
Events
| Name | Detail | Description |
|------|--------|-------------|
| report-created | { report_id, structure_url, data_url } | Fired after createReport resolves. |
| render-error | { code, message } | Fired when the gateway, report fetch, or renderer fails. |
| render-start | { report_id?: string } | Fired before rendering begins. |
| render-done | { report_id, structure?, data? } | Fired after rendering completes. In mode="headless" the event includes the resolved structure + data payload. |
| before-fetch | { url, method } | Fired immediately before a network request is dispatched. |
| after-fetch | { url, status, ok } | Fired after each network request completes. |
Chart specifications & alternatives
- If the backend includes a Vega-Lite spec in
chart.spec, the component sanitizes it (removing any embeddeddataor external URLs) and injects the fetched rows before rendering. chart.alternatives[]appear as a dropdown so users can switch between LLM-suggested variants (scores are surfaced alongside the label) and the auto-generated fallback.- A fallback “Auto chart” is always available; it uses the dataset schema to pick a sensible mark/encoding when no spec is provided or when a spec becomes invalid.
Transport & auth hooks
- Token providers – return a fresh token every time the component needs to call the MCP gateway or signed report URLs.
- Request middleware – mutate or replace the
Requestobject before it is sent (e.g. append tracing headers, inject CSRF tokens, or proxy through a custom transport). - Fetcher overrides – provide a
(req) => fetch(req)replacement if you need to integrate with custom networking stacks. The legacyWISE_FETCH_SYMBOLoverride still works but should only be used when you must mutate a request from middleware. - Cookie auth – set
credentials-mode="include"when the backend relies on HttpOnly session cookies.
Headless rendering
When mode="headless" the component skips built-in chart/table rendering and
instead emits render-done with { structure, data }. Hosts can render the
payload with any charting library (Recharts, ECharts, custom SVG, etc.).
Table pagination
- The component calls the signed
/dataURL withlimit/offsetquery parameters and exposes Previous/Next controls. - Update the
pageSizeproperty to control how many rows are fetched at a time; the default is 50.
Data-first behavior
The component implements a data-first approach to analytics:
- Tables first: When users submit prompts, the system immediately returns tabular data without generating charts
- Explicit chart requests: Charts are only created when users explicitly ask for visualizations (e.g., "show me a bar chart of sales by region")
- Chart alternatives: When charts are generated, users can switch between LLM-suggested variants using the dropdown
- Always accessible data: Raw data remains accessible in table format regardless of chart generation
This approach prioritizes data accessibility and performance while still providing rich visualizations on demand.
Excel export integration
Add a custom "Export to Excel" button using the footer slot:
<wise-analytics mcp-gateway="/api/mcp" auth-token="your-token">
<div slot="footer">
<button id="export-btn" onclick="exportToExcel()">📊 Export to Excel</button>
</div>
</wise-analytics>
<script>
async function exportToExcel() {
const analytics = document.querySelector('wise-analytics');
// Get the current report ID from the component
const reportId = analytics.currentReportId;
if (!reportId) {
alert('No report available for export');
return;
}
try {
// Request signed Excel export URL
const response = await fetch(`${analytics.mcpGateway}/export_excel`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${analytics.authToken}`
},
body: JSON.stringify({ report_id: reportId })
});
const { download_url } = await response.json();
// Trigger download
const link = document.createElement('a');
link.href = download_url;
link.download = `report_${reportId}.xlsx`;
link.click();
} catch (error) {
console.error('Export failed:', error);
alert('Export failed. Please try again.');
}
}
</script>For React/Vue applications, use the component events:
// React example
function Dashboard() {
const [reportId, setReportId] = useState<string | null>(null);
const handleExport = async () => {
if (!reportId) return;
const response = await fetch('/api/mcp/export_excel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ report_id: reportId })
});
const { download_url } = await response.json();
window.open(download_url, '_blank');
};
return (
<div>
<WiseAnalyticsReact
mcpGateway="/api/mcp"
onReportCreated={(e) => setReportId(e.detail.report_id)}
/>
<button onClick={handleExport} disabled={!reportId}>
📊 Export to Excel
</button>
</div>
);
}Slots & styling
The component uses a shadow DOM and exposes two slots:
<slot name="header">– Inject custom headers, filters, or titles.<slot name="footer">– Perfect for action buttons such as "Export to Excel".
Styling hooks:
- CSS custom properties:
--wa-bg,--wa-color,--wa-border,--wa-radius,--wa-accent,--wa-accent-contrast,--wa-shadow,--wa-input-bg. - Host attribute
data-theme="light|dark"is toggled automatically when you set thethemeproperty.
Usage from Angular
See docs/angular.md for a complete Angular integration guide,
including a runnable example and Docker workflow. The sample app honours
window.GATEWAY_URL if you need to override the gateway at runtime.
Framework wrappers
Official React and Vue wrappers live in src/react.tsx and src/vue.ts. Import
them directly to use JSX/TSX bindings:
import { WiseAnalyticsReact } from '@wise/analytics-web/react';
export function Dashboard() {
return (
<WiseAnalyticsReact
mcpGateway="/api/mcp"
tokenProvider={() => fetch('/token').then((res) => res.text())}
credentialsMode="include"
onRenderDone={(event) => console.log(event.detail)}
/>
);
}Both wrappers import the base module for its side-effect so the custom element is always registered, even when bundlers tree-shake unused exports.
Backend contract
Any backend language/framework can power the component as long as it exposes the
contract documented in docs/backend-contract.md.
