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`${key} `)}
-
- ${this.results.map(
- (row) =>
- html`
- ${keys.map((key) => html`${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`
-
-
-
- self.search(self.renderRoot.getElementById('search').value)}
- >
- Execute
-
-
-
- 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`${key} `)}
+
+ ${this.results.map(
+ (row) =>
+ html`
+ ${keys.map((key) => html`${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`
-
-
-
self.search(self.renderRoot.getElementById('search').value)}>Search
+
+
+
+ self.search(self.renderRoot.getElementById('search').value)}>Search
+
+ ${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.