demo D313
Reading Splunk live: JavaScript Data Grid Demo
A grid over Splunk’s own search REST API, filter and sort turned into SPL; run here against a mock of that API, since there is no public instance or credential this site can publish
createPushdownSource · splunkAdapter · lastPlan()
This grid reads Splunk's own search REST API, turning a filter or a sort into SPL and paging the job's results. There is no public Splunk instance and no credential this site could publish safely, so it runs against a mock of that API in the same shape a real instance answers with, and shows the split between what reached the search and what stayed with the grid.
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.72.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.72.0/lattice-grid.min.js"></script>
<div id="grid" style="height:520px"></div>
<script>
// There is no public Splunk instance to run this sample against and no
// credential this page could publish, so `fetch` here answers the search
// REST API's own dispatch/poll/results/cancel sequence from a small mock
// instead of a real instance. Point `fetch` at your own wrapper (or drop
// it and pass a token in `headers`) to run this against a real one.
const mockEvents = Array.from({ length: 40 }, (_, i) => ({
event_id: 'evt-' + (i + 1),
_time: new Date(Date.UTC(2026, 8, 27, 0, i * 30)).toISOString(),
src_ip: '10.20.' + (i % 255) + '.' + ((i * 3) % 255),
action: i % 3 === 0 ? 'allowed' : 'blocked',
}));
const mockFetch = async (input, init = {}) => {
const url = new URL(String(input));
const method = String(init.method || 'GET').toUpperCase();
if (method === 'POST' && url.pathname.endsWith('/services/search/v2/jobs')) {
return new Response(JSON.stringify({ sid: 'mock-1' }));
}
if (method === 'GET' && url.pathname.endsWith('/results')) {
const offset = Number(url.searchParams.get('offset') || 0);
const count = Number(url.searchParams.get('count') || 0) || mockEvents.length;
return new Response(JSON.stringify({ results: mockEvents.slice(offset, offset + count) }));
}
if (method === 'GET') {
return new Response(JSON.stringify({ isDone: true, dispatchState: 'DONE', resultCount: mockEvents.length }));
}
return new Response(null, { status: 200 }); // DELETE, cancelling the job
};
// Against a real instance: drop `fetch` and put a bearer token in `headers`,
// or supply your own `fetch` wrapper for one that expires and needs refreshing.
const adapter = LatticeGrid.splunkAdapter({
url: 'https://splunk.example.com:8089',
search: 'index=security sourcetype=firewall',
earliest: '-24h',
fetch: mockFetch,
});
const source = LatticeGrid.createPushdownSource({
adapter,
compute: LatticeGrid,
pageSize: 25,
});
const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
rowKey: 'event_id',
toolPanel: { side: 'left', panels: ['filters', 'columns'] },
columns: [
{ field: '_time', title: 'Time', type: 'dateString' },
{ field: 'src_ip', title: 'Source IP' },
{ field: 'action', title: 'Action', filter: { type: 'set' } },
],
source,
});
// After each query, lastPlan() reports what the search ran and what stayed here.
grid.on('rows:changed', () => {
const plan = source.lastPlan();
if (plan) console.log(plan.unpushed.length ? 'pushed part' : 'pushed all', plan);
});
</script>