From c076bbb112b0dd7c6bdd7974f57255960e6adf15 Mon Sep 17 00:00:00 2001 From: lazyweirdo Date: Tue, 24 Dec 2019 06:10:12 +0100 Subject: [PATCH] Redesign UI to be more IPFS-like (#83) * Preventing CORB + some explanatory comments * Nicer look Just changed its look * Update screenshot * screenshot updated * bash script updated * Sorting refactor + max-width * Versioning app.js for caching pourposes + sorting default order value --- README.md | 2 +- app.js | 111 ++++++++++++++++++++++++++++---------------- index.html | 26 +++++------ publish-to-ipfs.sh | 2 +- styles.css | 113 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 196 insertions(+), 58 deletions(-) create mode 100644 styles.css diff --git a/README.md b/README.md index 0fcdb136..9de799b0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ You can view this website on GitHub Pages: https://ipfs.github.io/public-gateway-checker/ -[![screenshot_2019-12-14.png](https://ipfs.io/ipfs/QmX53EdPJxH377WHfwH8wV3tu8Zzjq9ojgQS6U82JRM6bd?filename=screenshot_2019-12-14.png)](https://ipfs.github.io/public-gateway-checker/) +[![screenshot_2019-12-19.jpg](https://ipfs.io/ipfs/QmQuMMz9RUbdknhabTW4WpJ2LSiAstV6drCTS9ZFsmy5K7?filename=screenshot_2019-12-19.jpg)](https://ipfs.github.io/public-gateway-checker/) **NOTE:** All of these (except `ipfs.io` and `dweb.link`) are hosted by third-parties and should be treated as such. diff --git a/app.js b/app.js index 63630949..24106e18 100644 --- a/app.js +++ b/app.js @@ -11,37 +11,64 @@ const HASH_STRING = 'Hello from IPFS Gateway Checker'; let checker = document.getElementById('checker'); checker.nodes = []; -checker.updateStats = function(node) { +checker.checkGateways = function(gateways) { + gateways.forEach((gateway) => { + let node = new Node(this.results, gateway, this.nodes.length); + this.nodes.push(node); + this.results.append(node.tag); + node.check(); + }); +}; + +checker.updateStats = function() { + this.stats.update(); +}; + +let Stats = function(parent) { + this.parent = parent; + this.tag = document.getElementById('checker.stats');//document.createElement("div"); // TODO:: ugly i know, WIP + this.tag.className = "Stats"; + + this.gateways = document.createElement("div"); + this.gateways.textContent = `0/0`; + this.gateways.className = "Gateways"; + this.tag.append(this.gateways); + + this.totals = document.createElement("div"); + this.totals.textContent = `0 ✅`; + this.totals.className = "Totals"; + this.tag.append(this.totals); +}; + +Stats.prototype.update = function() { let up = 0, down = 0; - for (let savedNode of this.nodes) { + for (let savedNode of this.parent.nodes) { if ("up" in savedNode.status) { savedNode.status.up ? ++up : ++down; } } - let gtwschckd = `${up+down}/${this.nodes.length} gateways checked`; - let totals = ` ==> ${up} ✅ - ${down} ❌`; - this.stats.textContent = gtwschckd + totals; + this.gateways.textContent = `${up+down}/${this.parent.nodes.length} gateways`; + this.totals.textContent = `${up} ✅`; }; -checker.stats = document.getElementById('checker.stats'); -checker.stats.parent = checker; + +checker.stats = new Stats(checker); checker.results = document.getElementById('checker.results'); checker.results.parent = checker; checker.results.checked = function(node) { - this.prepend(node.tag); this.parent.updateStats(node); }; checker.results.failed = function(node) { - this.append(node.tag); this.parent.updateStats(node); }; let Status = function(parent, index) { this.parent = parent; - this.tag = document.createElement("span"); - this.tag.textContent = ' WAIT: 🕑 - '; + this.tag = document.createElement("div"); + this.tag.className = "Status"; + this.tag.textContent = '🕑'; }; Status.prototype.check = function() { @@ -53,7 +80,7 @@ Status.prototype.check = function() { // 3 important things here // 1) we add #x-ipfs-companion-no-redirect to the final url (self explanatory) - // 2) we add ?filename=anyname.js as a parameter to let the gateway set correct Content-Type header + // 2) we add ?filename=anyname.js as a parameter to let the gateway guess Content-Type header // to be sent in headers in order to prevent CORB // 3) parameter 'i' is the one used to identify the gateway once the script executes let src = `${gatewayAndScriptHash}?i=${this.parent.index}&now=${now}&filename=anyname.js#x-ipfs-companion-no-redirect`; @@ -66,7 +93,7 @@ Status.prototype.check = function() { // and, even though it is failing here, we know it is UP if (!this.up) { this.up = false; - this.tag.textContent = 'DOWN: ❌ - '; + this.tag.textContent = '❌'; this.parent.failed(); } }; @@ -74,7 +101,7 @@ Status.prototype.check = function() { Status.prototype.checked = function() { this.up = true; - this.tag.innerHTML = '  UP: ✅ - '; + this.tag.innerHTML = '✅'; }; // this function is executed from that previously loaded script @@ -94,8 +121,9 @@ function OnScriptloaded(src) { let Cors = function(parent) { this.parent = parent; - this.tag = document.createElement("span"); - this.tag.textContent = ' CORS: 🕑 - '; + this.tag = document.createElement("div"); + this.tag.className = "Cors"; + this.tag.textContent = '🕑'; }; Cors.prototype.check = function() { @@ -108,7 +136,7 @@ Cors.prototype.check = function() { const matched = (HASH_STRING === text.trim()); if (matched) { this.parent.checked(); - this.tag.textContent = ' CORS: ✅ - '; + this.tag.textContent = '✅'; } else { this.onerror(); } @@ -118,32 +146,35 @@ Cors.prototype.check = function() { }; Cors.prototype.onerror = function() { - this.tag.textContent = ' CORS: ❌ - '; + this.tag.textContent = '❌'; }; let Origin = function(parent) { this.parent = parent; - - this.tag = document.createElement("span"); - this.tag.textContent = ' ORIGIN: 🕑 - '; + this.tag = document.createElement("div"); + this.tag.className = "Origin"; + this.tag.textContent = '🕑'; }; Origin.prototype.check = function() { const cidInSubdomain = this.parent.gateway.startsWith('https://:hash.ipfs.'); if (cidInSubdomain) { - this.tag.textContent = ' ORIGIN: ✅ - '; + this.tag.textContent = '✅'; } else { this.onerror(); } }; Origin.prototype.onerror = function() { - this.tag.textContent = ' ORIGIN: ❌ - '; + this.tag.textContent = '❌'; }; + let Node = function(parent, gateway, index) { this.parent = parent; this.tag = document.createElement("div"); + this.tag.className = "Node"; + this.tag.style["order"] = Date.now(); this.status = new Status(this); this.tag.append(this.status.tag); @@ -154,11 +185,15 @@ let Node = function(parent, gateway, index) { this.origin = new Origin(this); this.tag.append(this.origin.tag); - this.link = document.createElement("span"); - this.link.textContent = gateway.replace(':hash', HASH_TO_TEST); + this.link = document.createElement("div"); + let gatewayAndHash = gateway.replace(':hash', HASH_TO_TEST); + this.link.url = new URL(gatewayAndHash); + this.link.textContent = this.link.url.host.replace(`${HASH_TO_TEST}.`, ""); + this.link.className = "Link"; this.tag.append(this.link); - this.took = document.createElement("span"); + this.took = document.createElement("div"); + this.took.className = "Took"; this.tag.append(this.took); this.gateway = gateway; @@ -167,7 +202,7 @@ let Node = function(parent, gateway, index) { }; Node.prototype.check = function() { - this.checkingTime = performance.now(); + this.checkingTime = Date.now(); this.status.check(); this.cors.check(); this.origin.check(); @@ -178,11 +213,13 @@ Node.prototype.checked = function() { if (!this.status.up) { this.status.checked(); this.parent.checked(this); - let gatewayTitle = this.gateway.split(":hash")[0]; - let gatewayAndHash = this.gateway.replace(':hash', HASH_TO_TEST); - this.link.innerHTML = `${gatewayAndHash}`; - let ms = (performance.now() - this.checkingTime).toFixed(2); - this.took.textContent = ` (${ms}ms)`; + let url = this.link.url; + let host = url.host.replace(`${HASH_TO_TEST}.`, ""); + this.link.innerHTML = `${host}`; + let ms = Date.now() - this.checkingTime; + this.tag.style["order"] = ms; + let s = (ms / 1000).toFixed(2); + this.took.textContent = `${s}s`; } }; @@ -190,16 +227,8 @@ Node.prototype.failed = function() { this.parent.failed(this); }; -function checkGateways (gateways) { - gateways.forEach((gateway) => { - let node = new Node(checker.results, gateway, checker.nodes.length); - checker.nodes.push(node); - checker.results.append(node.tag); - node.check(); - }); -} fetch('./gateways.json') .then(res => res.json()) - .then(gateways => checkGateways(gateways)); + .then(gateways => checker.checkGateways(gateways)); diff --git a/index.html b/index.html index 84e92214..859cbcb4 100644 --- a/index.html +++ b/index.html @@ -3,22 +3,18 @@ Public IPFS Gateways - + + + + -

Public IPFS Gateways

-

-
+
Public Gateways
+
+
+
UP
cors
+ OI
resp
+
- + diff --git a/publish-to-ipfs.sh b/publish-to-ipfs.sh index 9b02be7f..8d569d26 100755 --- a/publish-to-ipfs.sh +++ b/publish-to-ipfs.sh @@ -1,3 +1,3 @@ #! /usr/bin/env bash -ipfs add -wQ app.js index.html gateways.json > lastpubver +ipfs add -wQ styles.css app.js index.html gateways.json > lastpubver diff --git a/styles.css b/styles.css new file mode 100644 index 00000000..3b90525e --- /dev/null +++ b/styles.css @@ -0,0 +1,113 @@ +body, html { + font-family: monospace; + color: #222; + background-color: #FAFAFA; + margin: 0; + padding: 0; + box-sizing: border-box; + text-align: center; +} + +div.Header { + display: flex; + justify-content: space-between; + align-items: center; + width: calc(100% - 2rem); + background-color: #0b3a53; + padding: 1rem; +} + +div.Header a { + box-sizing: border-box; +} + +div.Header a img { + height: 50px; +} + +div.Header div.Title { + position: relative; + display: inline-block; + color: #69c4cd; + font-family: Montserrat,Verdana,system-ui,sans-serif; + font-size: 1.5rem; + text-align: right; + font-weight: 200; +} + +div.Stats { + display: flex; + justify-content: flex-start; + align-items: center; + margin: 1em auto; + width: 95%; + max-width: 1024px; +} + +div.Stats div.Totals, +div.Stats div.Gateways { + border-radius: 9999px; + color: white; + font-weight: bold; + padding: 0.5em 1em; + margin: 0 1em 0 0; +} + +div.Stats div.Gateways { + background-color: #0b3a53; +} + +div.Stats div.Totals { + background-color: rgb(0, 181, 0); +} + +div.Results { + display: flex; + flex-direction: column; + justify-content: center; + margin: 0 auto; + width: 100%; + max-width: 1024px; +} + +div.Node { + display: flex; + justify-content: space-evenly; + align-items: center; + width: 95%; + padding: 0.5em 0; + margin: 0 2.5%; + border-bottom: 1px solid #EEE; +} + +div.Node div.Link { + width: 100%; + text-align: left; +} + +div.Node div.Link a { + text-decoration: none; + color: #357edd; + white-space: nowrap; +} + +div.Node div.Status, +div.Node div.Cors, +div.Node div.Origin { + width: 4em; + text-align: center; + font-weight: bold; +} + +div.Node div.Cors, +div.Node div.Origin { + font-size: 80%; +} + +div.Node div.Took { + width: 5em; + text-align: right; + font-size: 80%; + font-style: italic; +} +