Extending the Data Dashboard
The Data Dashboard is designed to be extended. This guide covers the four main extension points: chart types, exporters, query engine capabilities, and panel tabs.
Adding New Chart Types
Chart rendering uses Chart.js. To add a new chart type:
1. Register the Chart Type
In bundles/data-dashboard/panel/chart-renderer.js, add your type to the CHART_TYPES registry:
const CHART_TYPES = {
bar: { label: 'Bar', icon: '...', minColumns: 2 },
line: { label: 'Line', icon: '...', minColumns: 2 },
pie: { label: 'Pie', icon: '...', minColumns: 2 },
scatter: { label: 'Scatter', icon: '...', minColumns: 2 },
// Add your type:
heatmap: { label: 'Heatmap', icon: '...', minColumns: 3 },
};2. Add the Rendering Logic
Add a case to the buildChartConfig() function that returns a Chart.js configuration object:
case 'heatmap':
return {
type: 'matrix', // Requires chartjs-chart-matrix plugin
data: {
datasets: [{
data: transformToMatrix(queryResults, options),
// ...
}]
},
options: { /* ... */ }
};3. Handle Server-Side Rendering
If the chart type requires a Chart.js plugin, add it to the server-side canvas renderer in chart-renderer.js:
import ChartjsMatrix from 'chartjs-chart-matrix';
Chart.register(ChartjsMatrix);Also add the plugin to package.json dependencies in the bundle directory.
4. Update the Panel UI
The chart type selector in the panel auto-populates from CHART_TYPES, so no UI changes are needed unless your type requires custom configuration fields.
Custom Exporters
Exporters convert query results into downloadable formats. Built-in: CSV, JSON.
Adding an Exporter
Create a module in bundles/data-dashboard/exporters/:
// bundles/data-dashboard/exporters/xlsx.js
export default {
id: 'xlsx',
label: 'Excel (.xlsx)',
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
extension: '.xlsx',
async export(queryResults, options) {
// queryResults.columns: string[]
// queryResults.rows: object[]
// Return a Buffer
const workbook = buildWorkbook(queryResults);
return workbook.toBuffer();
}
};Register it in the exporter registry:
// bundles/data-dashboard/exporters/index.js
import xlsx from './xlsx.js';
export const exporters = [csv, json, xlsx];The panel and MCP tools automatically pick up registered exporters.
Extending the Query Engine
Adding Query Transforms
Query transforms modify SQL before execution — useful for adding automatic LIMIT clauses, query logging, or custom functions.
Add a transform to the pipeline in server.js:
const transforms = [
addDefaultLimit, // Add LIMIT 1000 if no LIMIT present
logQueryExecution, // Log to query history
// Add yours:
addCustomFunctions, // Register custom SQL functions
];Each transform receives the SQL string and connection context, and returns the (possibly modified) SQL:
function addCustomFunctions(sql, context) {
// Register a custom SQLite function on the connection
context.db.function('geo_distance', (lat1, lon1, lat2, lon2) => {
// Haversine formula
return calculateDistance(lat1, lon1, lat2, lon2);
});
return sql;
}Supporting New Database Types
The query engine currently supports SQLite backends. To add support for PostgreSQL, MySQL, or other databases:
- Create a driver adapter in
bundles/data-dashboard/drivers/ - Implement the
DatabaseDriverinterface:connect(),execute(sql),getSchema(),close() - Register the driver type in
server.js
The data backend's type field (set during crow_register_backend) determines which driver is used.
Adding Panel Tabs via Plugins
Third-party bundles can add tabs to the Data Dashboard panel by registering a tab plugin.
Tab Plugin Structure
Place a module in ~/.crow/bundles/<your-bundle>/dashboard-tabs/:
// ~/.crow/bundles/geo-tools/dashboard-tabs/map-tab.js
export default {
id: 'map',
label: 'Map',
icon: '<svg>...</svg>',
order: 50, // Position after built-in tabs
async render({ req, db, queryResults }) {
// Return HTML string for the tab content
return `
<div id="map-container" style="height: 500px;"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
const map = L.map('map-container').setView([30, -95], 6);
// ... render query results as markers
</script>
`;
}
};Tab plugins are auto-discovered when the parent bundle is installed. They appear in the tab bar alongside the built-in tabs.
Next Steps
- Data Dashboard Architecture — Internal design and query engine details
- Creating Add-ons — General add-on development guide
- Creating Panels — Nest panel development patterns
- Nominatim Developer Guide — GIS integration example