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_search from './tf-tab-search.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'; | ||||
| @@ -68,6 +68,8 @@ class TfElement extends LitElement { | ||||
| 			this.tab = 'connections'; | ||||
| 		} else if (this.hash === '#mentions') { | ||||
| 			this.tab = 'mentions'; | ||||
| 		} else if (this.hash.startsWith('#sql=')) { | ||||
| 			this.tab = 'query'; | ||||
| 		} else { | ||||
| 			this.tab = 'news'; | ||||
| 		} | ||||
| @@ -310,6 +312,10 @@ class TfElement extends LitElement { | ||||
| 			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> | ||||
| 			`; | ||||
| 		} 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'); | ||||
| 		} else if (tab === '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="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="Query" ?disabled=${self.tab == 'query'} @click=${() => self.set_tab('query')}></input> | ||||
| 			</div> | ||||
| 		`; | ||||
| 		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