diff --git a/apps/ssb/script.js b/apps/ssb/script.js
index 8f1ab8a8..6f4301a1 100644
--- a/apps/ssb/script.js
+++ b/apps/ssb/script.js
@@ -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';
\ No newline at end of file
diff --git a/apps/ssb/tf-app.js b/apps/ssb/tf-app.js
index bc1bf2fe..01d4fb9a 100644
--- a/apps/ssb/tf-app.js
+++ b/apps/ssb/tf-app.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`
`;
+ } else if (this.tab === 'query') {
+ return html`
+
+ `;
}
}
@@ -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 {
self.set_tab('connections')}>
self.set_tab('mentions')}>
self.set_tab('search')}>
+ self.set_tab('query')}>
`;
let contents =
diff --git a/apps/ssb/tf-tab-query.js b/apps/ssb/tf-tab-query.js
new file mode 100644
index 00000000..bec5a7d8
--- /dev/null
+++ b/apps/ssb/tf-tab-query.js
@@ -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`
No results.
`;
+ } else {
+ let keys = Object.keys(this.results[0]).sort();
+ return html`
+ ${keys.map(key => html`${key} `)}
+ ${this.results.map(row => html`${keys.map(key => html`${row[key]} `)} `)}
+
`;
+ }
+ }
+
+ render_error() {
+ return html`${JSON.stringify(this.error, null, 2)} `;
+ }
+
+ render() {
+ if (this.query !== this.last_query) {
+ this.last_query = this.query;
+ this.search(this.query);
+ }
+ let self = this;
+ return html`
+
+
+ self.search(self.renderRoot.getElementById('search').value)}>
+
+ Took ${this.duration / 1000.0} seconds.
+ Executing...
+ ${this.render_error()}
+ ${this.render_results()}
+ `;
+ }
+}
+
+customElements.define('tf-tab-query', TfTabQueryElement);
\ No newline at end of file