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