/
Query.svelte
127 lines (112 loc) · 3.3 KB
/
Query.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<script lang="ts">
import { onMount, tick } from "svelte";
import { get } from "../api";
import type { ChartTypes } from "../charts";
import Chart from "../charts/Chart.svelte";
import { chartContext } from "../charts/context";
import { parseQueryChart } from "../charts/query-charts";
import { getFilterParams } from "../stores/filters";
import {
addToHistory,
clearHistory,
query_shell_history,
} from "../stores/query";
import QueryEditor from "./QueryEditor.svelte";
import QueryLinks from "./QueryLinks.svelte";
import ReadonlyQueryEditor from "./ReadonlyQueryEditor.svelte";
let query_string = "";
const resultElems: Record<string, HTMLElement> = {};
type ResultType = {
result?: { table: string; chart: ChartTypes | null };
error?: unknown;
};
const query_results: Record<string, ResultType> = {};
$: query_result_array = $query_shell_history.map(
(item): [string, ResultType] => [item, query_results[item] || {}]
);
async function setResult(query: string, res: ResultType) {
addToHistory(query);
query_results[query] = res;
await tick();
const url = new URL(window.location.href);
url.searchParams.set("query_string", query);
window.history.replaceState(null, "", url.toString());
resultElems[query].setAttribute("open", "true");
}
async function clearResults() {
clearHistory();
await tick();
const url = new URL(window.location.href);
query_string = "";
url.searchParams.set("query_string", query_string);
window.history.replaceState(null, "", url.toString());
}
function submit() {
const query = query_string;
if (!query) {
return;
}
if (query.trim().toUpperCase() === "CLEAR") {
clearResults();
return;
}
get("query_result", { query_string: query, ...getFilterParams() }).then(
(res) => {
const r = parseQueryChart(res.chart, $chartContext);
const chart = r.success ? r.value : null;
setResult(query, { result: { chart, table: res.table } });
},
(error) => {
setResult(query, { error });
}
);
}
function click(query: string) {
if (!query_results[query]) {
query_string = query;
submit();
}
}
onMount(() => {
const url = new URL(window.location.href);
query_string = url.searchParams.get("query_string") || "";
if (query_string) {
submit();
}
});
</script>
<QueryEditor bind:value={query_string} {submit} />
<div>
{#each query_result_array as [history_item, { result, error }] (history_item)}
<details class:error bind:this={resultElems[history_item]}>
<summary on:click={() => click(history_item)}>
<ReadonlyQueryEditor value={history_item} />
{#if result}
<span class="spacer" />
<QueryLinks query={history_item} />
{/if}
</summary>
<div>
{#if result}
{#if result.chart}
<Chart chart={result.chart} />
{/if}
{@html result.table}
{:else if error}
{error}
{/if}
</div>
</details>
{/each}
</div>
<style>
details > div {
max-height: 80vh;
overflow: auto;
}
div :global(.query-error) {
font-family: var(--font-family-monospaced);
color: var(--background);
background: var(--error);
}
</style>