aboutsummaryrefslogtreecommitdiff
path: root/html/repo_query.js
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-01-25 09:37:34 +0100
committerWojtek Kosior <koszko@koszko.org>2022-01-25 09:37:34 +0100
commitb75a5717a084c9e5a727c2e960f2b910abcb5ace (patch)
treea9dcd00c428aeba011e9a445b96aacad962a1f3d /html/repo_query.js
parent7218849ae2f43aee6b3462a30e07caf5bac3d22b (diff)
downloadbrowser-extension-b75a5717a084c9e5a727c2e960f2b910abcb5ace.tar.gz
browser-extension-b75a5717a084c9e5a727c2e960f2b910abcb5ace.zip
add a repo querying HTML interface
Diffstat (limited to 'html/repo_query.js')
-rw-r--r--html/repo_query.js210
1 files changed, 210 insertions, 0 deletions
diff --git a/html/repo_query.js b/html/repo_query.js
new file mode 100644
index 0000000..8f33356
--- /dev/null
+++ b/html/repo_query.js
@@ -0,0 +1,210 @@
+/**
+ * This file is part of Haketilo.
+ *
+ * Function: Show available repositories and allow querying them for resources.
+ *
+ * Copyright (C) 2022 Wojtek Kosior
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
+ * license. Although I request that you do not make use of this code in a
+ * proprietary program, I am not going to enforce this in court.
+ */
+
+#IMPORT common/indexeddb.js AS haketilodb
+
+#FROM common/browser.js IMPORT browser
+#FROM html/DOM_helpers.js IMPORT clone_template, Showable
+#FROM common/entities.js IMPORT item_id_string, version_string, \
+ is_valid_version
+#FROM html/install.js IMPORT InstallView
+
+const coll = new Intl.Collator();
+
+function ResultEntry(repo_entry, mapping_ref) {
+ Object.assign(this, clone_template("repo_query_single_result"));
+ Object.assign(this, {repo_entry, mapping_ref});
+
+ this.mapping_name.innerText = mapping_ref.long_name;
+ this.mapping_id.innerText = item_id_string(mapping_ref);
+
+ const iv = repo_entry.query_view.install_view;
+
+ function start_install() {
+ iv.show(repo_entry.repo_url, "mapping",
+ mapping_ref.identifier, mapping_ref.version);
+ }
+
+ const cb = repo_entry.query_view.install_view.when_hidden(start_install);
+ this.install_but.addEventListener("click", cb);
+}
+
+function RepoEntry(query_view, repo_url) {
+ Object.assign(this, clone_template("repo_query_single_repo"));
+ Object.assign(this, {query_view, repo_url});
+ this.results_shown_before = false;
+
+ this.repo_url_label.innerText = repo_url;
+
+ const query_results = async () => {
+ const msg = [
+ "repo_query",
+ `${repo_url}query?url=${encodeURIComponent(query_view.url)}`
+ ];
+ const response = await browser.tabs.sendMessage(query_view.tab_id, msg);
+
+ if ("error" in response)
+ throw "Failure to communicate with repository :(";
+
+ if (!response.ok)
+ throw `Repository sent HTTP code ${response.status} :(`;
+ if ("error_json" in response)
+ throw "Repository's response is not valid JSON :(";
+
+ if (!is_valid_version(response.json.api_schema_version)) {
+ var bad_api_ver = "";
+ } else if (response.json.api_schema_version > [1]) {
+ var bad_api_ver =
+ ` (${version_string(response.json.api_schema_version)})`;
+ } else {
+ var bad_api_ver = false;
+ }
+
+ if (bad_api_ver !== false)
+ throw `Results were served using unsupported Hydrilla API version${bad_api_ver}. You might need to update Haketilo.`;
+
+ /* TODO: here we should perform JSON schema validation! */
+
+ return response.json.mappings;
+ }
+
+ const populate_results = async () => {
+ this.results_shown_before = true;
+
+ try {
+ var results = await query_results();
+ } catch(e) {
+ this.info_span.innerText = e;
+ return;
+ }
+
+ this.info_span.remove();
+ this.results_list.classList.remove("hide");
+
+ this.result_entries = results.map(ref => new ResultEntry(this, ref));
+
+ const to_append = this.result_entries.length > 0 ?
+ this.result_entries.map(re => re.main_li) :
+ ["No results :("];
+
+ this.results_list.append(...to_append);
+ }
+
+ let show_results = () => {
+ if (!query_view.shown)
+ return;
+
+ if (!this.results_shown_before)
+ populate_results();
+
+ this.list_container.classList.remove("hide");
+ this.hide_results_but.classList.remove("hide");
+ this.show_results_but.classList.add("hide");
+ }
+ show_results = query_view.install_view.when_hidden(show_results);
+
+ let hide_results = () => {
+ if (!query_view.shown)
+ return;
+
+ this.list_container.classList.add("hide");
+ this.hide_results_but.classList.add("hide");
+ this.show_results_but.classList.remove("hide");
+ }
+ hide_results = query_view.install_view.when_hidden(hide_results);
+
+ this.show_results_but.addEventListener("click", show_results);
+ this.hide_results_but.addEventListener("click", hide_results);
+}
+
+const container_ids = ["repos_list_container", "install_view_container"];
+
+function RepoQueryView(tab_id, on_view_show, on_view_hide) {
+ Showable.call(this, on_view_show, on_view_hide);
+
+ Object.assign(this, clone_template("repo_query"));
+ this.tab_id = tab_id;
+
+ const show_container = name => {
+ for (const cid of container_ids) {
+ if (cid !== name)
+ this[cid].classList.add("hide");
+ }
+ this[name].classList.remove("hide");
+ }
+
+ this.install_view = new InstallView(
+ tab_id,
+ () => show_container("install_view_container"),
+ () => show_container("repos_list_container")
+ );
+ this.install_view_container.prepend(this.install_view.main_div);
+
+ const show_super = this.show;
+ this.show = async url => {
+ if (!show_super())
+ return;
+
+ this.url = url;
+ this.url_span.innerText = url;
+
+ [...this.repos_list.children].forEach(c => c.remove());
+
+ const repo_urls = await haketilodb.get_repos();
+ repo_urls.sort((a, b) => coll.compare(a, b));
+ this.repo_entries = repo_urls.map(ru => new RepoEntry(this, ru));
+
+ if (repo_urls.length === 0) {
+ const info_li = document.createElement("li");
+ info_li.innerText = "You have no repositories configured :(";
+ this.repos_list.append(info_li);
+ return;
+ }
+
+ this.repos_list.append(...this.repo_entries.map(re => re.main_li));
+ }
+
+ this.cancel_but.addEventListener("click",
+ this.install_view.when_hidden(this.hide));
+}
+#EXPORT RepoQueryView