forked from cory/tildefriends
		
	Add an SQL query tab.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4402 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		@@ -13,4 +13,5 @@ import * as tf_tab_news from './tf-tab-news.js';
 | 
				
			|||||||
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
 | 
					import * as tf_tab_news_feed from './tf-tab-news-feed.js';
 | 
				
			||||||
import * as tf_tab_search from './tf-tab-search.js';
 | 
					import * as tf_tab_search from './tf-tab-search.js';
 | 
				
			||||||
import * as tf_tab_connections from './tf-tab-connections.js';
 | 
					import * as tf_tab_connections from './tf-tab-connections.js';
 | 
				
			||||||
 | 
					import * as tf_tab_query from './tf-tab-query.js';
 | 
				
			||||||
import * as tf_tag from './tf-tag.js';
 | 
					import * as tf_tag from './tf-tag.js';
 | 
				
			||||||
@@ -68,6 +68,8 @@ class TfElement extends LitElement {
 | 
				
			|||||||
			this.tab = 'connections';
 | 
								this.tab = 'connections';
 | 
				
			||||||
		} else if (this.hash === '#mentions') {
 | 
							} else if (this.hash === '#mentions') {
 | 
				
			||||||
			this.tab = 'mentions';
 | 
								this.tab = 'mentions';
 | 
				
			||||||
 | 
							} else if (this.hash.startsWith('#sql=')) {
 | 
				
			||||||
 | 
								this.tab = 'query';
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			this.tab = 'news';
 | 
								this.tab = 'news';
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -310,6 +312,10 @@ class TfElement extends LitElement {
 | 
				
			|||||||
			return html`
 | 
								return html`
 | 
				
			||||||
				<tf-tab-search .following=${this.following} whoami=${this.whoami} .users=${this.users} query=${this.hash?.startsWith('#q=') ? decodeURIComponent(this.hash.substring(3)) : null}></tf-tab-search>
 | 
									<tf-tab-search .following=${this.following} whoami=${this.whoami} .users=${this.users} query=${this.hash?.startsWith('#q=') ? decodeURIComponent(this.hash.substring(3)) : null}></tf-tab-search>
 | 
				
			||||||
			`;
 | 
								`;
 | 
				
			||||||
 | 
							} else if (this.tab === 'query') {
 | 
				
			||||||
 | 
								return html`
 | 
				
			||||||
 | 
									<tf-tab-query .following=${this.following} whoami=${this.whoami} .users=${this.users} query=${this.hash?.startsWith('#sql=') ? decodeURIComponent(this.hash.substring(5)) : null}></tf-tab-query>
 | 
				
			||||||
 | 
								`;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -321,6 +327,8 @@ class TfElement extends LitElement {
 | 
				
			|||||||
			await tfrpc.rpc.setHash('#connections');
 | 
								await tfrpc.rpc.setHash('#connections');
 | 
				
			||||||
		} else if (tab === 'mentions') {
 | 
							} else if (tab === 'mentions') {
 | 
				
			||||||
			await tfrpc.rpc.setHash('#mentions');
 | 
								await tfrpc.rpc.setHash('#mentions');
 | 
				
			||||||
 | 
							} else if (tab === 'query') {
 | 
				
			||||||
 | 
								await tfrpc.rpc.setHash('#sql=');
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -340,6 +348,7 @@ class TfElement extends LitElement {
 | 
				
			|||||||
				<input type="button" class="tab" value="Connections" ?disabled=${self.tab == 'connections'} @click=${() => self.set_tab('connections')}></input>
 | 
									<input type="button" class="tab" value="Connections" ?disabled=${self.tab == 'connections'} @click=${() => self.set_tab('connections')}></input>
 | 
				
			||||||
				<input type="button" class="tab" value="Mentions" ?disabled=${self.tab == 'mentions'} @click=${() => self.set_tab('mentions')}></input>
 | 
									<input type="button" class="tab" value="Mentions" ?disabled=${self.tab == 'mentions'} @click=${() => self.set_tab('mentions')}></input>
 | 
				
			||||||
				<input type="button" class="tab" value="Search" ?disabled=${self.tab == 'search'} @click=${() => self.set_tab('search')}></input>
 | 
									<input type="button" class="tab" value="Search" ?disabled=${self.tab == 'search'} @click=${() => self.set_tab('search')}></input>
 | 
				
			||||||
 | 
									<input type="button" class="tab" value="Query" ?disabled=${self.tab == 'query'} @click=${() => self.set_tab('query')}></input>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
		`;
 | 
							`;
 | 
				
			||||||
		let contents =
 | 
							let contents =
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										111
									
								
								apps/ssb/tf-tab-query.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								apps/ssb/tf-tab-query.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					import {LitElement, html, unsafeHTML} from './lit-all.min.js';
 | 
				
			||||||
 | 
					import * as tfrpc from '/static/tfrpc.js';
 | 
				
			||||||
 | 
					import {styles} from './tf-styles.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TfTabQueryElement extends LitElement {
 | 
				
			||||||
 | 
						static get properties() {
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								whoami: {type: String},
 | 
				
			||||||
 | 
								users: {type: Object},
 | 
				
			||||||
 | 
								following: {type: Array},
 | 
				
			||||||
 | 
								query: {type: String},
 | 
				
			||||||
 | 
								expanded: {type: Object},
 | 
				
			||||||
 | 
								results: {type: Array},
 | 
				
			||||||
 | 
								error: {type: Object},
 | 
				
			||||||
 | 
								duration: {type: Number},
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static styles = styles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						constructor() {
 | 
				
			||||||
 | 
							super();
 | 
				
			||||||
 | 
							let self = this;
 | 
				
			||||||
 | 
							this.whoami = null;
 | 
				
			||||||
 | 
							this.users = {};
 | 
				
			||||||
 | 
							this.following = [];
 | 
				
			||||||
 | 
							this.expanded = {};
 | 
				
			||||||
 | 
							this.duration = undefined;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						async search(query) {
 | 
				
			||||||
 | 
							console.log('Searching...', this.whoami, query);
 | 
				
			||||||
 | 
							this.results = [];
 | 
				
			||||||
 | 
							this.error = undefined;
 | 
				
			||||||
 | 
							this.duration = undefined;
 | 
				
			||||||
 | 
							let search = this.renderRoot.getElementById('search');
 | 
				
			||||||
 | 
							if (search) {
 | 
				
			||||||
 | 
								search.value = query;
 | 
				
			||||||
 | 
								search.focus();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							await tfrpc.rpc.setHash('#sql=' + encodeURIComponent(query));
 | 
				
			||||||
 | 
							let start_time = new Date();
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								this.results = await tfrpc.rpc.query(query, [])
 | 
				
			||||||
 | 
							} catch (error) {
 | 
				
			||||||
 | 
								this.error = error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let end_time = new Date();
 | 
				
			||||||
 | 
							this.duration = (end_time - start_time).valueOf();
 | 
				
			||||||
 | 
							console.log('Done.');
 | 
				
			||||||
 | 
							search = this.renderRoot.getElementById('search');
 | 
				
			||||||
 | 
							if (search) {
 | 
				
			||||||
 | 
								search.value = query;
 | 
				
			||||||
 | 
								search.focus();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						search_keydown(event) {
 | 
				
			||||||
 | 
							if (event.keyCode == 13 && event.ctrlKey) {
 | 
				
			||||||
 | 
								this.query = this.renderRoot.getElementById('search').value;
 | 
				
			||||||
 | 
								event.preventDefault();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						on_expand(event) {
 | 
				
			||||||
 | 
							if (event.detail.expanded) {
 | 
				
			||||||
 | 
								let expand = {};
 | 
				
			||||||
 | 
								expand[event.detail.id] = true;
 | 
				
			||||||
 | 
								this.expanded = Object.assign({}, this.expanded, expand);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								delete this.expanded[event.detail.id];
 | 
				
			||||||
 | 
								this.expanded = Object.assign({}, this.expanded);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						render_results() {
 | 
				
			||||||
 | 
							if (!this.results?.length) {
 | 
				
			||||||
 | 
								return html`<div>No results.</div>`;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								let keys = Object.keys(this.results[0]).sort();
 | 
				
			||||||
 | 
								return html`<table style="width: 100%; max-width: 100%">
 | 
				
			||||||
 | 
									<tr>${keys.map(key => html`<th>${key}</th>`)}</tr>
 | 
				
			||||||
 | 
									${this.results.map(row => html`<tr>${keys.map(key => html`<td>${row[key]}</td>`)}</tr>`)}
 | 
				
			||||||
 | 
								</table>`;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						render_error() {
 | 
				
			||||||
 | 
							return html`<pre>${JSON.stringify(this.error, null, 2)}</pre>`;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						render() {
 | 
				
			||||||
 | 
							if (this.query !== this.last_query) {
 | 
				
			||||||
 | 
								this.last_query = this.query;
 | 
				
			||||||
 | 
								this.search(this.query);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let self = this;
 | 
				
			||||||
 | 
							return html`
 | 
				
			||||||
 | 
								<div style="display: flex; flex-direction: row">
 | 
				
			||||||
 | 
									<textarea id="search" rows=8 style="flex: 1" @keydown=${this.search_keydown}>${this.query}</textarea>
 | 
				
			||||||
 | 
									<input type="button" value="Execute" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}></input>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
								<div ?hidden=${this.duration === undefined}>Took ${this.duration / 1000.0} seconds.</div>
 | 
				
			||||||
 | 
								<div ?hidden=${this.duration !== undefined}>Executing...</div>
 | 
				
			||||||
 | 
								${this.render_error()}
 | 
				
			||||||
 | 
								${this.render_results()}
 | 
				
			||||||
 | 
							`;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					customElements.define('tf-tab-query', TfTabQueryElement);
 | 
				
			||||||
		Reference in New Issue
	
	Block a user