diff --git a/qortal-ui-plugins/plugins/core/qdn/websites.src.js b/qortal-ui-plugins/plugins/core/qdn/websites.src.js index 644bdf67..0c0c6257 100644 --- a/qortal-ui-plugins/plugins/core/qdn/websites.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/websites.src.js @@ -4,6 +4,7 @@ import { Epml } from '../../../epml.js' import '@material/mwc-icon' import '@material/mwc-button' +import '@material/mwc-tab-bar' import '@material/mwc-textfield' import '@vaadin/button' import '@vaadin/grid' @@ -28,7 +29,13 @@ class Websites extends LitElement { searchName: { type: String }, searchResources: { type: Array }, searchFollowedNames: { type: Array }, - searchBlockedNames: { type: Array } + searchBlockedNames: { type: Array }, + webResources: { type: Array }, + webFollowedNames: { type: Array }, + webBlockedNames: { type: Array }, + blockResources: { type: Array }, + blockFollowedNames: { type: Array }, + blockBlockedNames: { type: Array } } } @@ -43,6 +50,15 @@ class Websites extends LitElement { --lumo-primary-color: hsl(199, 100%, 48%); } + #tabs-1 { + --mdc-tab-height: 50px; + } + + #tabs-1-content { + height: 100%; + padding-bottom: 10px; + } + #pages { display: flex; flex-wrap: wrap; @@ -177,88 +193,181 @@ class Websites extends LitElement { this.searchResources = [] this.searchFollowedNames = [] this.searchBlockedNames = [] + this.webResources = [] + this.webFollowedNames = [] + this.webBlockedNames = [] + this.blockResources = [] + this.blockFollowedNames = [] + this.blockBlockedNames = [] } render() { return html`
-
-

Browse Websites

- ${this.renderPublishButton()} -
-
-

Search Websites

-
- - { - render(html`${this.renderSearchAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderSearchName(data.item)}`, root) - }}> - - { - render(html`${this.renderSearchStatus(data.item)}`, root) - }}> - - { - render(html`${this.renderSearchSize(data.item)}`, root) - }}> - - { - render(html`${this.renderSearchFollowUnfollowButton(data.item)}`, root); - }}> - - { - render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root); - }}> - -
-
-
-

Websites

- - { - render(html`${this.renderAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderName(data.item)}`, root) - }}> - - { - render(html`${this.renderStatus(data.item)}`, root) - }}> - - { - render(html`${this.renderSize(data.item)}`, root) - }}> - - { - render(html`${this.renderFollowUnfollowButton(data.item)}`, root); - }}> - - { - render(html`${this.renderBlockUnblockButton(data.item)}`, root); - }}> - - -
- ${this.isEmptyArray(this.resources) ? html` - No websites available - `: ''} -
- ${this.renderRelayModeText()} -
+ + + + + + +
+
+

Browse Websites

+

${this.renderPublishButton()}

+
+
+

Search Websites

+
+ + { + render(html`${this.renderSearchAvatar(data.item)}`, root) + }}> + + { + render(html`${this.renderSearchName(data.item)}`, root) + }}> + + { + render(html`${this.renderSearchStatus(data.item)}`, root) + }}> + + { + render(html`${this.renderSearchSize(data.item)}`, root) + }}> + + { + render(html`${this.renderSearchFollowUnfollowButton(data.item)}`, root); + }}> + + { + render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root); + }}> + +
+
+
+

Websites

+ + { + render(html`${this.renderAvatar(data.item)}`, root) + }}> + + { + render(html`${this.renderName(data.item)}`, root) + }}> + + { + render(html`${this.renderStatus(data.item)}`, root) + }}> + + { + render(html`${this.renderSize(data.item)}`, root) + }}> + + { + render(html`${this.renderFollowUnfollowButton(data.item)}`, root); + }}> + + { + render(html`${this.renderBlockUnblockButton(data.item)}`, root); + }}> + + +
+ ${this.isEmptyArray(this.resources) ? html` + No websites available + `: ''} +
+ ${this.renderRelayModeText()} +
+
+
+

Your followed Webistes

+

${this.renderPublishButton()}

+
+
+

Followed Websites

+ + { + render(html`${this.renderWebAvatar(data.item)}`, root) + }}> + + { + render(html`${this.renderWebName(data.item)}`, root) + }}> + + { + render(html`${this.renderWebStatus(data.item)}`, root) + }}> + + { + render(html`${this.renderWebSize(data.item)}`, root) + }}> + + { + render(html`${this.renderWebFollowUnfollowButton(data.item)}`, root); + }}> + + { + render(html`${this.renderWebBlockUnblockButton(data.item)}`, root); + }}> + + + ${this.isEmptyArray(this.webResources) ? html` + You not follow any website + `: ''} +
+ ${this.renderRelayModeText()} +
+
+
+

Your blocked Webistes

+

${this.renderPublishButton()}

+
+
+

Blocked Websites

+ + { + render(html`${this.renderBlockAvatar(data.item)}`, root) + }}> + + { + render(html`${this.renderBlockName(data.item)}`, root) + }}> + + { + render(html`${this.renderBlockStatus(data.item)}`, root) + }}> + + { + render(html`${this.renderBlockSize(data.item)}`, root) + }}> + + { + render(html`${this.renderBlockFollowUnfollowButton(data.item)}`, root); + }}> + + { + render(html`${this.renderBlockBlockUnblockButton(data.item)}`, root); + }}> + + + ${this.isEmptyArray(this.blockResources) ? html` + You have not blocked any website + `: ''} +
+ ${this.renderRelayModeText()} +
+ + ` } @@ -266,6 +375,10 @@ class Websites extends LitElement { this.showWebsites() + setTimeout(() => { + this.displayTabContent('browse') + }, 0) + const getFollowedNames = async () => { let followedNames = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}` @@ -284,6 +397,42 @@ class Websites extends LitElement { setTimeout(getBlockedNames, 60000) } + const getWebFollowedNames = async () => { + let webFollowedNames = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}` + }) + + this.webFollowedNames = webFollowedNames + setTimeout(getWebFollowedNames, 60000) + } + + const getWebBlockedNames = async () => { + let webBlockedNames = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}` + }) + + this.webBlockedNames = webBlockedNames + setTimeout(getWebBlockedNames, 60000) + } + + const getBlockFollowedNames = async () => { + let blockFollowedNames = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}` + }) + + this.blockFollowedNames = blockFollowedNames + setTimeout(getBlockFollowedNames, 60000) + } + + const getBlockBlockedNames = async () => { + let blockBlockedNames = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}` + }) + + this.blockBlockedNames = blockBlockedNames + setTimeout(getBlockBlockedNames, 60000) + } + const getSearchFollowedNames = async () => { let searchFollowedNames = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}` @@ -338,12 +487,20 @@ class Websites extends LitElement { parentEpml.subscribe('config', c => { if (!configLoaded) { setTimeout(this.getArbitraryResources, 1) + setTimeout(this.getFollowedWebsites, 1) + setTimeout(this.getBlockedWebsites, 1) setTimeout(getFollowedNames, 1) setTimeout(getBlockedNames, 1) + setTimeout(getWebFollowedNames, 1) + setTimeout(getWebBlockedNames, 1) + setTimeout(getBlockFollowedNames, 1) + setTimeout(getBlockBlockedNames, 1) setTimeout(getSearchFollowedNames, 1) setTimeout(getSearchBlockedNames, 1) setTimeout(getRelayMode, 1) setInterval(this.getArbitraryResources, 120000) + setInterval(this.getFollowedWebsites, 60000) + setInterval(this.getBlockedWebsites, 60000) configLoaded = true } this.config = JSON.parse(c) @@ -357,6 +514,15 @@ class Websites extends LitElement { parentEpml.imReady() } + displayTabContent(tab) { + const tabBrowseContent = this.shadowRoot.getElementById('tab-browse-content') + const tabFollowedContent = this.shadowRoot.getElementById('tab-followed-content') + const tabBlockedContent = this.shadowRoot.getElementById('tab-blocked-content') + tabBrowseContent.style.display = (tab === 'browse') ? 'block' : 'none' + tabFollowedContent.style.display = (tab === 'followed') ? 'block' : 'none' + tabBlockedContent.style.display = (tab === 'blocked') ? 'block' : 'none' + } + searchListener(e) { if (e.key === 'Enter') { this.doSearch(e); @@ -453,6 +619,330 @@ class Websites extends LitElement { this.searchResult() } + getFollowedWebsites = async () => { + let data = []; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const namesUrl = `${nodeUrl}/lists/followedNames?apiKey=${this.getApiKey()}`; + const jsonUrl = `${nodeUrl}/arbitrary/resources?service=WEBSITE&default=true&limit=0&reverse=false&includestatus=true`; + + const jsonRes = await fetch(jsonUrl); + const jsonData = await jsonRes.json(); + const response = await fetch(namesUrl); + const names = await response.json(); + + let webres = jsonData.filter((elm) => names.includes(elm.name)); + + this.webResources = webres; + } + + renderWebAvatar(webObj) { + let name = webObj.name + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`; + return html`` + } + + renderWebName(webObj) { + let name = webObj.name + return html`${name}` + } + + renderWebStatus(webObj) { + return html`${webObj.status.title}` + } + + renderWebSize(webObj) { + if (webObj.size === null) { + return html`` + } + let sizeWebReadable = this.bytesToSize(webObj.size); + return html`${sizeWebReadable}` + } + + renderWebFollowUnfollowButton(webObj) { + let name = webObj.name + if (this.webFollowedNames == null || !Array.isArray(this.webFollowedNames)) { + return html`` + } + if (this.webFollowedNames.indexOf(name) === -1) { + return html` this.webFollowName(webObj)}>add_to_queue Follow` + } + else { + return html` this.webUnfollowName(webObj)}>remove_from_queue Unfollow` + } + } + + async webFollowName(webObj) { + let name = webObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.webFollowedNames = this.webFollowedNames.filter(item => item != name); + this.webFollowedNames.push(name) + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to follow this registered name. Please try again') + } + return ret + } + + async webUnfollowName(webObj) { + let name = webObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}`, + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.webFollowedNames = this.webFollowedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') + } + return ret + } + + renderWebBlockUnblockButton(webObj) { + let name = webObj.name + if (this.webBlockedNames == null || !Array.isArray(this.webBlockedNames)) { + return html`` + } + if (this.webBlockedNames.indexOf(name) === -1) { + return html` this.webBlockName(webObj)}>block Block` + } + else { + return html` this.webUnblockName(webObj)}>radio_button_unchecked Unblock` + } + } + + async webBlockName(webObj) { + let name = webObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.webBlockedNames = this.webBlockedNames.filter(item => item != name); + this.webBlockedNames.push(name) + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to block this registered name. Please try again') + } + return ret + } + + async webUnblockName(webObj) { + let name = webObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.webBlockedNames = this.webBlockedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') + } + return ret + } + + getBlockedWebsites = async () => { + let data = []; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const blockedNamesUrl = `${nodeUrl}/lists/blockedNames?apiKey=${this.getApiKey()}`; + const blockedJsonUrl = `${nodeUrl}/arbitrary/resources?service=WEBSITE&default=true&limit=0&reverse=false&includestatus=true`; + + const blockedJsonRes = await fetch(blockedJsonUrl); + const blockedJsonData = await blockedJsonRes.json(); + const blockedResponse = await fetch(blockedNamesUrl); + const blockednames = await blockedResponse.json(); + + let blockedres = blockedJsonData.filter((elm) => blockednames.includes(elm.name)); + + this.blockResources = blockedres; + } + + renderBlockAvatar(blockObj) { + let name = blockObj.name + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`; + return html`` + } + + renderBlockName(blockObj) { + let name = blockObj.name + return html`${name}` + } + + renderBlockStatus(blockObj) { + return html`${blockObj.status.title}` + } + + renderBlockSize(blockObj) { + if (blockObj.size === null) { + return html`` + } + let sizeBlockReadable = this.bytesToSize(blockObj.size); + return html`${sizeBlockReadable}` + } + + renderBlockFollowUnfollowButton(blockObj) { + let name = blockObj.name + if (this.blockFollowedNames == null || !Array.isArray(this.blockFollowedNames)) { + return html`` + } + if (this.blockFollowedNames.indexOf(name) === -1) { + return html` this.blockFollowName(blockObj)}>add_to_queue Follow` + } + else { + return html` this.blockUnfollowName(blockObj)}>remove_from_queue Unfollow` + } + } + + async blockFollowName(blockObj) { + let name = blockObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.blockFollowedNames = this.blockFollowedNames.filter(item => item != name); + this.blockFollowedNames.push(name) + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to follow this registered name. Please try again') + } + return ret + } + + async blockUnfollowName(blockObj) { + let name = blockObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}`, + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.blockFollowedNames = this.blockFollowedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') + } + return ret + } + + renderBlockBlockUnblockButton(blockObj) { + let name = blockObj.name + if (this.blockBlockedNames == null || !Array.isArray(this.blockBlockedNames)) { + return html`` + } + if (this.blockBlockedNames.indexOf(name) === -1) { + return html` this.blockBlockName(blockObj)}>block Block` + } + else { + return html` this.blockUnblockName(blockObj)}>radio_button_unchecked Unblock` + } + } + + async blockBlockName(blockObj) { + let name = blockObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.blockBlockedNames = this.blockBlockedNames.filter(item => item != name); + this.blockBlockedNames.push(name) + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to block this registered name. Please try again') + } + return ret + } + + async blockUnblockName(blockObj) { + let name = blockObj.name + let items = [ + name + ] + let namesJsonString = JSON.stringify({ "items": items }) + let ret = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: `${namesJsonString}` + }) + if (ret === true) { + this.blockBlockedNames = this.blockBlockedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') + } + return ret + } + async searchResult() { let searchName = this.shadowRoot.getElementById('searchName').value if (searchName.length === 0) { diff --git a/scripts/add-debian-apt-repo.sh b/scripts/add-debian-apt-repo.sh index 21eddfac..5589351d 100644 --- a/scripts/add-debian-apt-repo.sh +++ b/scripts/add-debian-apt-repo.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Make necessary config and add LOTW Softwares apt repo +# Make necessary config and add Qortal Softwares apt repo # SCript to run UI without sandbox echo \'/opt/${productFilename}/qortal-ui\' --no-sandbox > '/opt/${productFilename}/run-ui' @@ -21,7 +21,6 @@ if ! which curl; then sudo apt-get --yes install curl; fi # Install apt repository source list if it does not exist if ! grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep qortal.list; then - curl -sS https://lotw.qortal.org/lotw_pub.gpg | sudo apt-key add - - echo "deb [arch=amd64] https://lotw.qortal.org/debian stable main" \ - | sudo tee /etc/apt/sources.list.d/qortal.list + curl -sS https://update.qortal.online/repo/qortal.gpg | sudo apt-key add - + echo 'deb https://update.qortal.online/repo/ ./ ' > /etc/apt/sources.list.d/qortal.list fi diff --git a/scripts/uninstall-debian-conf.sh b/scripts/uninstall-debian-conf.sh index cc02cedf..aeba788d 100644 --- a/scripts/uninstall-debian-conf.sh +++ b/scripts/uninstall-debian-conf.sh @@ -4,7 +4,6 @@ # Remove apt repository source list when user uninstalls app if grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep qortal.list; then - sudo apt-key del 5025E50F; sudo rm /etc/apt/sources.list.d/qortal.list; fi