-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
294 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import * as zealot from "@brimdata/zealot" | ||
|
||
export class ZedAst { | ||
public tree: any | ||
constructor(public script: string) { | ||
this.tree = zealot.parseAst(script) | ||
} | ||
|
||
get from() { | ||
return this.ops.find((o) => o.kind === "From") | ||
} | ||
|
||
get pools() { | ||
const trunks = this.from?.trunks || [] | ||
return trunks.filter((t) => t.source.kind === "Pool").map((t) => t.source) | ||
} | ||
|
||
private _ops: any[] | ||
get ops() { | ||
if (this._ops) return this._ops | ||
if (!this.tree || this.tree.error) return [] | ||
const list = [] | ||
|
||
function collectOps(op, list) { | ||
list.push(op) | ||
if (COMPOUND_PROCS.includes(op.kind)) { | ||
for (const p of op.ops) collectOps(p, list) | ||
} else if (op.kind === OP_EXPR_PROC) { | ||
collectOps(op.expr, list) | ||
} | ||
} | ||
|
||
collectOps(this.tree, list) | ||
return (this._ops = list) | ||
} | ||
} | ||
|
||
export const OP_EXPR_PROC = "OpExpr" | ||
export const PARALLEL_PROC = "Parallel" | ||
export const SEQUENTIAL_PROC = "Sequential" | ||
export const COMPOUND_PROCS = [PARALLEL_PROC, SEQUENTIAL_PROC] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import {ZedScript} from "./zed-script" | ||
|
||
test("time range", () => { | ||
const script = new ZedScript( | ||
"from sample.pcap range 2022-01-01T00:00:00Z to 2022-02-01T00:00:00Z" | ||
) | ||
|
||
expect(script.range).toEqual([ | ||
new Date(Date.UTC(2022, 0, 1, 0, 0, 0)), | ||
new Date(Date.UTC(2022, 1, 1, 0, 0, 0)), | ||
]) | ||
}) | ||
|
||
test("number range range", () => { | ||
const script = new ZedScript("from sample.pcap range 0 to 100") | ||
|
||
expect(script.range).toEqual([0, 100]) | ||
}) | ||
|
||
test("no range", () => { | ||
const script = new ZedScript("from sample.pcap") | ||
|
||
expect(script.range).toEqual(null) | ||
}) | ||
|
||
test("no pool", () => { | ||
const script = new ZedScript("hello world") | ||
|
||
expect(script.range).toEqual(null) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import {ZedAst} from "./zed-ast" | ||
|
||
export class ZedScript { | ||
constructor(public script: string) {} | ||
|
||
private _ast: ZedAst | ||
get ast() { | ||
return this._ast || (this._ast = new ZedAst(this.script)) | ||
} | ||
|
||
get range() { | ||
const pool = this.ast.pools[0] | ||
if (!pool) return null | ||
const range = pool.range | ||
if (!range) return null | ||
|
||
return [parseRangeItem(range.lower), parseRangeItem(range.upper)] | ||
} | ||
} | ||
|
||
function parseRangeItem({type, text}) { | ||
switch (type) { | ||
case "int64": | ||
return parseInt(text) | ||
case "time": | ||
return new Date(text) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,39 @@ | ||
import React from "react" | ||
import {useSelector} from "react-redux" | ||
import {ZedScript} from "src/app/core/models/zed-script" | ||
import Dimens from "src/js/components/Dimens" | ||
import Results from "src/js/state/Results" | ||
import styled from "styled-components" | ||
|
||
import ChartSVG from "../ChartSVG" | ||
import {HISTOGRAM_RESULTS} from "../run-histogram-query" | ||
import useMainHistogram from "./useMainHistogram" | ||
|
||
const BG = styled.div` | ||
height: 80px; | ||
margin: 24px 16px 16px 16px; | ||
` | ||
|
||
export default function MainHistogramChart() { | ||
const query = useSelector(Results.getQuery(HISTOGRAM_RESULTS)) | ||
const range = new ZedScript(query).range | ||
if (!range) return null | ||
return ( | ||
<Dimens | ||
className="chart main-search-histogram" | ||
data-testid="histogram" | ||
render={(rect) => ( | ||
<MainHistogramSvg width={rect.width} height={rect.height} /> | ||
)} | ||
/> | ||
<BG> | ||
<Dimens | ||
className="chart main-search-histogram" | ||
data-testid="histogram" | ||
render={(rect) => ( | ||
<MainHistogramSvg width={rect.width} height={rect.height} /> | ||
)} | ||
/> | ||
</BG> | ||
) | ||
} | ||
|
||
type Props = {height: number; width: number} | ||
|
||
const MainHistogramSvg = React.memo(function MainHistogramSvg({ | ||
width, | ||
height, | ||
}: Props) { | ||
function MainHistogramSvg({width, height}: Props) { | ||
const chart = useMainHistogram(width, height) | ||
return <ChartSVG chart={chart} /> | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import {ZedScript} from "src/app/core/models/zed-script" | ||
import {Pool} from "src/app/core/pools/pool" | ||
import {syncPool} from "src/app/core/pools/sync-pool" | ||
import span from "src/js/brim/span" | ||
import histogramInterval, {timeUnits} from "src/js/lib/histogramInterval" | ||
import {DateTuple} from "src/js/lib/TimeWindow" | ||
import Current from "src/js/state/Current" | ||
import Editor from "src/js/state/Editor" | ||
import Pools from "src/js/state/Pools" | ||
import {Thunk} from "src/js/state/types" | ||
import zql from "src/js/zql" | ||
import {BrimQuery} from "../utils/brim-query" | ||
|
||
export const buildHistogramQuery = | ||
(): Thunk<Promise<string | null>> => | ||
async (dispatch, getState, {api}) => { | ||
const poolName = api.current.poolName | ||
const range = await dispatch(getRange(poolName)) | ||
console.log(range) | ||
return histogramZed(poolName, range) | ||
} | ||
|
||
export const getRange = | ||
(name: string): Thunk<Promise<DateTuple> | DateTuple> => | ||
(dispatch) => { | ||
const queryRange = dispatch(getRangeFromQuery()) | ||
if (queryRange) return queryRange | ||
else return dispatch(getRangeFromPool(name)) | ||
} | ||
|
||
function histogramZed(pool: string, range: DateTuple | null) { | ||
if (!range) return null | ||
const {number, unit} = histogramInterval(range) | ||
const interval = `${number}${timeUnits[unit]}` | ||
return `from "${pool}" range ${zql`${range[0]}`} to ${zql`${range[1]}`} | count() by every(${interval}), _path` | ||
} | ||
|
||
const getRangeFromPool = | ||
(poolName: string): Thunk<Promise<DateTuple>> => | ||
async (dispatch) => { | ||
if (!poolName) return null | ||
const pool = await dispatch(ensurePoolLoaded(poolName)) | ||
if (!pool) return | ||
return span(pool.everythingSpan()).toDateTuple() | ||
} | ||
|
||
const getRangeFromQuery = (): Thunk<DateTuple> => (_, getState) => { | ||
const snapshot = Editor.getSnapshot(getState()) | ||
const inputs = new ZedScript(BrimQuery.versionToZed(snapshot)) | ||
return inputs.range as DateTuple | ||
} | ||
|
||
const ensurePoolLoaded = | ||
(name: string): Thunk<Promise<Pool>> => | ||
(dispatch, getState) => { | ||
const lakeId = Current.getLakeId(getState()) | ||
const pool = Pools.getByName(lakeId, name)(getState()) | ||
if (!pool) return Promise.resolve(null) | ||
if (pool.hasStats()) { | ||
return Promise.resolve(pool) | ||
} else { | ||
return dispatch(syncPool(pool.id, lakeId)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import {Collector} from "@brimdata/zealot" | ||
import Results from "src/js/state/Results" | ||
import {Thunk} from "src/js/state/types" | ||
import {buildHistogramQuery} from "./build-histogram-query" | ||
|
||
export const HISTOGRAM_RESULTS = "zui/histogram" | ||
const id = HISTOGRAM_RESULTS | ||
|
||
// This is looking very similar to Results/flows.ts fetchResults() | ||
// Maybe this can be part of the api. It automatically saves it to | ||
// the results reducer, and it paginates the query for you? | ||
export const runHistogramQuery = | ||
(): Thunk => | ||
async (dispatch, getState, {api}) => { | ||
const tabId = api.current.tabId | ||
const key = api.current.location.key | ||
const query = await dispatch(buildHistogramQuery()) | ||
if (!query) return | ||
console.log(query) | ||
dispatch(Results.init({id, tabId, query, key})) | ||
const collect: Collector = ({rows, shapesMap}) => { | ||
dispatch(Results.setValues({id, tabId, values: rows})) | ||
dispatch(Results.setShapes({id, tabId, shapes: shapesMap})) | ||
} | ||
|
||
try { | ||
const res = await api.query(query, {tabId, id, collect}) | ||
await res.promise | ||
dispatch(Results.success({id, tabId, count: res.rows.length})) | ||
} catch (error) { | ||
if ( | ||
error instanceof DOMException && | ||
error.message.match(/user aborted/) | ||
) { | ||
return | ||
} | ||
dispatch(Results.error({id, error, tabId})) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.