]> BookStack Code Mirror - bookstack/blob - resources/js/components/query-manager.ts
Vectors: Finished core fetch & display functionality
[bookstack] / resources / js / components / query-manager.ts
1 import {Component} from "./component";
2
3 export class QueryManager extends Component {
4     protected input!: HTMLTextAreaElement;
5     protected generatedLoading!: HTMLElement;
6     protected generatedDisplay!: HTMLElement;
7     protected contentLoading!: HTMLElement;
8     protected contentDisplay!: HTMLElement;
9     protected form!: HTMLFormElement;
10     protected fieldset!: HTMLFieldSetElement;
11
12     setup() {
13         this.input = this.$refs.input as HTMLTextAreaElement;
14         this.form = this.$refs.form as HTMLFormElement;
15         this.fieldset = this.$refs.fieldset as HTMLFieldSetElement;
16         this.generatedLoading = this.$refs.generatedLoading;
17         this.generatedDisplay = this.$refs.generatedDisplay;
18         this.contentLoading = this.$refs.contentLoading;
19         this.contentDisplay = this.$refs.contentDisplay;
20
21         this.setupListeners();
22
23         // Start lookup if a query is set
24         if (this.input.value.trim() !== '') {
25             this.runQuery();
26         }
27     }
28
29     protected setupListeners(): void {
30         // Handle form submission
31         this.form.addEventListener('submit', event => {
32             event.preventDefault();
33             this.runQuery();
34         });
35
36         // Allow Ctrl+Enter to run a query
37         this.input.addEventListener('keydown', event => {
38             if (event.key === 'Enter' && event.ctrlKey && this.input.value.trim() !== '') {
39                 this.runQuery();
40             }
41         });
42     }
43
44     protected async runQuery(): Promise<void> {
45         this.contentLoading.hidden = false;
46         this.generatedLoading.hidden = false;
47         this.contentDisplay.innerHTML = '';
48         this.generatedDisplay.innerHTML = '';
49         this.fieldset.disabled = true;
50
51         const query = this.input.value.trim();
52         const url = new URL(window.location.href);
53         url.searchParams.set('ask', query);
54         window.history.pushState({}, '', url.toString());
55
56         const es = window.$http.eventSource('/query', 'POST', {query});
57
58         let messageCount = 0;
59         for await (const {data, event, id} of es) {
60             messageCount++;
61             if (messageCount === 1) {
62                 // Entity results
63                 this.contentDisplay.innerHTML = JSON.parse(data).view;
64                 this.contentLoading.hidden = true;
65             } else if (messageCount === 2) {
66                 // LLM Output
67                 this.generatedDisplay.innerText = JSON.parse(data).result;
68                 this.generatedLoading.hidden = true;
69             } else {
70                 es.close();
71                 break;
72             }
73         }
74
75         this.fieldset.disabled = false;
76     }
77 }