diff --git a/apps/ssb.json b/apps/ssb.json index 40285f78..a95e2387 100644 --- a/apps/ssb.json +++ b/apps/ssb.json @@ -1,5 +1,5 @@ { "type": "tildefriends-app", "emoji": "🦀", - "previous": "&wggp4XYiydgBSvQfWqGXXPtkgZ3XWkGLzkiBmghCyd8=.sha256" + "previous": "&J8epgiTHHI/2GtNoS+FW3UpyTrIEL4ltovW1JpmwSW4=.sha256" } diff --git a/apps/ssb/script.js b/apps/ssb/script.js index f266961d..e9beb10f 100644 --- a/apps/ssb/script.js +++ b/apps/ssb/script.js @@ -12,7 +12,6 @@ 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'; import * as tf_styles from './tf-styles.js'; diff --git a/apps/ssb/tf-app.js b/apps/ssb/tf-app.js index 59e8910d..d4c133e9 100644 --- a/apps/ssb/tf-app.js +++ b/apps/ssb/tf-app.js @@ -206,8 +206,6 @@ class TfElement extends LitElement { this.tab = 'search'; } else if (this.hash === '#connections') { this.tab = 'connections'; - } else if (this.hash.startsWith('#sql=')) { - this.tab = 'query'; } else { this.tab = 'news'; } @@ -736,17 +734,6 @@ class TfElement extends LitElement { : null} > `; - } else if (this.tab === 'query') { - return html` - - `; } } @@ -757,8 +744,6 @@ class TfElement extends LitElement { await tfrpc.rpc.setHash('#'); } else if (tab === 'connections') { await tfrpc.rpc.setHash('#connections'); - } else if (tab === 'query') { - await tfrpc.rpc.setHash('#sql='); } } @@ -792,7 +777,6 @@ class TfElement extends LitElement { '📰': 'news', '📡': 'connections', '🔍': 'search', - '👩‍💻': 'query', }; let tabs = html` diff --git a/apps/ssb/tf-tab-query.js b/apps/ssb/tf-tab-query.js deleted file mode 100644 index 179750bd..00000000 --- a/apps/ssb/tf-tab-query.js +++ /dev/null @@ -1,136 +0,0 @@ -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``)} - - ${this.results.map( - (row) => - html` - ${keys.map((key) => html``)} - ` - )} -
${key}
${row[key]}
`; - } - } - - render_error() { - if (this.error) { - return html`

${this.error.message}

-
${this.error.stack}
`; - } - } - - render() { - if (this.query !== this.last_query) { - this.last_query = this.query; - this.search(this.query); - } - let self = this; - return html` -
- - -
-
- Took ${this.duration / 1000.0} seconds. -
-
Executing...
- ${this.render_error()} ${this.render_results()} - `; - } -} - -customElements.define('tf-tab-query', TfTabQueryElement); diff --git a/apps/ssb/tf-tab-search.js b/apps/ssb/tf-tab-search.js index 282e4134..17958751 100644 --- a/apps/ssb/tf-tab-search.js +++ b/apps/ssb/tf-tab-search.js @@ -11,6 +11,9 @@ class TfTabSearchElement extends LitElement { following: {type: Array}, query: {type: String}, expanded: {type: Object}, + messages: {type: Array}, + results: {type: Array}, + error: {type: Object}, }; } @@ -38,24 +41,40 @@ class TfTabSearchElement extends LitElement { search.select(); } await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query)); - let results = await tfrpc.rpc.query( - ` - SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature - FROM messages_fts(?) - JOIN messages ON messages.rowid = messages_fts.rowid - JOIN json_each(?) AS following ON messages.author = following.value - ORDER BY timestamp DESC limit 100 - `, - ['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)] - ); - console.log('Done.'); - search = this.renderRoot.getElementById('search'); - if (search) { - search.value = query; - search.focus(); - search.select(); + this.error = undefined; + this.results = []; + this.messages = []; + if (query.startsWith('sql:')) { + this.messages = []; + try { + this.results = await tfrpc.rpc.query( + query.substring('sql:'.length), + [] + ); + } catch (e) { + this.results = []; + this.error = e; + } + } else { + let results = await tfrpc.rpc.query( + ` + SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature + FROM messages_fts(?) + JOIN messages ON messages.rowid = messages_fts.rowid + JOIN json_each(?) AS following ON messages.author = following.value + ORDER BY timestamp DESC limit 100 + `, + ['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)] + ); + console.log('Done.'); + search = this.renderRoot.getElementById('search'); + if (search) { + search.value = query; + search.focus(); + search.select(); + } + this.messages = results; } - this.renderRoot.getElementById('news').messages = results; } search_keydown(event) { @@ -87,6 +106,39 @@ class TfTabSearchElement extends LitElement { tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts)); } + render_results() { + if (this.error) { + return html`

${this.error.message}

+
${this.error.stack}
`; + } else if (this.messages?.length) { + return html``; + } else if (this.results?.length) { + let keys = Object.keys(this.results[0]).sort(); + return html` + + ${keys.map((key) => html``)} + + ${this.results.map( + (row) => + html` + ${keys.map((key) => html``)} + ` + )} +
${key}
${row[key]}
`; + } else { + return html`
No results.
`; + } + } + render() { if (this.query !== this.last_query) { this.last_query = this.query; @@ -94,11 +146,13 @@ class TfTabSearchElement extends LitElement { } let self = this; return html` -
- - +
+
+ + +
+ ${this.render_results()}
- `; } } diff --git a/docs/usage.md b/docs/usage.md index 647f344d..3df02c73 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -41,7 +41,6 @@ options: ssb_port (default: 8008): Port on which to listen for SSB secure handshake connections. http_local_only (default: false): Whether to bind http(s) to the loopback address. Otherwise any. http_port (default: 12345): Port on which to listen for HTTP connections. - https_port (default: 0): Port on which to listen for secure HTTP connections. out_http_port_file (default: ""): File to which to write bound HTTP port. blob_fetch_age_seconds (default: -1): Only blobs mentioned more recently than this age will be automatically fetched. blob_expire_age_seconds (default: -1): Blobs older than this will be automatically deleted.