Lattice Grid Buy a licence

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.

Building…
Loading a live 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>