diff --git a/plugins/plugins/core/q-app/q-apps.src.js b/plugins/plugins/core/q-app/q-apps.src.js index c3136d2c..7bf724e1 100644 --- a/plugins/plugins/core/q-app/q-apps.src.js +++ b/plugins/plugins/core/q-app/q-apps.src.js @@ -4,16 +4,12 @@ import {Epml} from '../../../epml.js' import {get, registerTranslateConfig, translate, use} from 'lit-translate' import isElectron from 'is-electron' import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@material/mwc-dialog' +import '@polymer/paper-dialog/paper-dialog.js' +import '@polymer/paper-icon-button/paper-icon-button.js' +import '@polymer/iron-icons/iron-icons.js' import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-tab-bar' -import '@material/mwc-textfield' -import '@polymer/paper-dialog/paper-dialog.js' -import '@vaadin/button' -import '@vaadin/grid' -import '@vaadin/icon' -import '@vaadin/icons' import '@vaadin/text-field' registerTranslateConfig({ @@ -25,25 +21,29 @@ const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class QApps extends LitElement { static get properties() { return { - service: { type: String }, - identifier: { type: String }, - loading: { type: Boolean }, - resources: { type: Array }, - pageRes: { type: Array }, + selectedAddress: { type: Object }, + appsArray: { type: Array }, followedNames: { type: Array }, blockedNames: { type: Array }, - relayMode: { type: Boolean }, - btnDisabled: { type: Boolean }, - selectedAddress: { type: Object }, - searchName: { type: String }, searchResources: { type: Array }, followedResources: { type: Array }, blockedResources: { type: Array }, + isLoading: {type: Boolean}, + relayMode: { type: Boolean }, + service: { type: String }, + identifier: { type: String }, + searchName: { type: String }, textStatus: { type: String }, textProgress: { type: String }, - theme: { type: String, reflect: true }, - hasInitiallyFetched: {type:Boolean}, - isLoading: {type: Boolean} + appIconUrl: { type: String }, + appTitle: { type: String }, + appPublisher: { type: String }, + appDescription: { type: String }, + appTags: { type: String }, + appStatus: { type: String }, + appFollow: { type: String }, + appBlock: { type: String }, + theme: { type: String, reflect: true } } } @@ -53,15 +53,6 @@ class QApps extends LitElement { --mdc-theme-primary: rgb(3, 169, 244); --mdc-button-disabled-fill-color: rgba(3, 169, 244, 0.5); --mdc-theme-surface: var(--white); - --mdc-text-field-outlined-idle-border-color: var(--txtfieldborder); - --mdc-text-field-outlined-hover-border-color: var(--txtfieldhoverborder); - --mdc-text-field-label-ink-color: var(--black); - --mdc-text-field-ink-color: var(--black); - --mdc-dialog-content-ink-color: var(--black); - --mdc-dialog-shape-radius: 25px; - --mdc-dialog-min-width: 300px; - --mdc-dialog-max-width: auto; - --mdc-dialog-max-height: 700px; --paper-input-container-focus-color: var(--mdc-theme-primary); --lumo-primary-text-color: rgb(0, 167, 245); --lumo-primary-color-50pct: rgba(0, 167, 245, 0.5); @@ -75,74 +66,92 @@ class QApps extends LitElement { --_lumo-grid-secondary-border-color: var(--border2); } - #tabs-1 { - --mdc-tab-height: 50px; + [hidden] { + display: hidden !important; + visibility: none !important; } - #tabs-1-content { - height: 100%; - padding-bottom: 10px; + h2 { + margin: 0; } - mwc-tab-bar { - --mdc-text-transform: none; - --mdc-tab-color-default: var(--black); - --mdc-tab-text-label-color-default: var(--black); - } + h3 { + margin: 10px 0; + } - #pages { - display: flex; - flex-wrap: wrap; - padding: 10px 5px 5px 5px; - margin: 0px 20px 20px 20px; + h4 { + margin: 0; } - #pages > button { - user-select: none; - padding: 5px; - margin: 0 5px; - border-radius: 10%; - border: 0; - background: transparent; - font: inherit; - outline: none; - cursor: pointer; + h5 { + margin: 5px 0; + font-size: 14px; + } + + h6 { + margin: 5px 0; + text-transform: uppercase; color: var(--black); + font-weight: 600; } - #pages > button:not([disabled]):hover, - #pages > button:focus { - color: #ccc; - background-color: #eee; + h2, h3, h4, h5 { + color: var(--black); + font-weight: 400; } - #pages > button[selected] { - font-weight: bold; - color: var(--white); - background-color: #ccc; + p { + font-size: 14px; + line-height: 21px; + color: var(--black); } - #pages > button[disabled] { - opacity: 0.5; - cursor: default; + span { + font-size: 14px; + word-break: break-all; + } + + #tabs-1 { + --mdc-tab-height: 50px; } + #tabs-1-content { + height: 100%; + padding-bottom: 10px; + } + + mwc-tab-bar { + --mdc-text-transform: none; + --mdc-tab-color-default: var(--black); + --mdc-tab-text-label-color-default: var(--black); + } + #apps-list-page { background: var(--white); padding: 12px 24px; } - #search { - display: flex; + .search { + display: inline; width: 50%; align-items: center; } - .divCard { - border: 1px solid var(--border); - padding: 1em; - box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20); - margin-bottom: 2em; + paper-spinner-lite { + height: 30px; + width: 30px; + --paper-spinner-color: var(--mdc-theme-primary); + --paper-spinner-stroke-width: 3px; + } + + .spinner { + width: 100%; + display: flex; + justify-content: center; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); } paper-dialog.progress { @@ -160,98 +169,42 @@ class QApps extends LitElement { overflow-y: auto; } - h2 { - margin:0; - } - - h2, h3, h4, h5 { - color: var(--black); - font-weight: 400; - } - - a.visitSite { + paper-dialog.search { + min-width: 550px; + max-width: 550px; + min-height: auto; + max-height: 700px; + background-color: var(--white); color: var(--black); - text-decoration: none; - } - - [hidden] { - display: hidden !important; - visibility: none !important; - } - - .details { - display: flex; - font-size: 18px; - } - - span { - font-size: 14px; - word-break: break-all; - } - - select { - padding: 13px 20px; - width: 100%; - font-size: 14px; - color: #555; - font-weight: 400; - } - - .title { - font-weight:600; - font-size:12px; - line-height: 32px; - opacity: 0.66; - } - - .resourceTitle { - font-size:15px; - line-height: 32px; - } - - .resourceDescription { - font-size:11px; - padding-bottom: 5px; - } - - .resourceCategoryTags { - font-size:11px; - padding-bottom: 10px; - } - - .resourceRegisteredName { - font-size:15px; - line-height: 32px; - } - - .resourceStatus, .resourceStatus span { - font-size:11px; + line-height: 1.6; + overflow: auto; + border: 1px solid var(--black); + border-radius: 10px; + padding: 15px; + box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.1); } - .itemList { - padding:0; + paper-dialog.appinfo { + width: auto; + max-width: 450px; + height: auto; + background-color: var(--white); + border: 1px solid var(--black); + border-radius: 15px; + padding: 5px; + overflow-y: auto; } .relay-mode-notice { - margin:auto; - text-align:center; - word-break:normal; - font-size:14px; - line-height:20px; + margin: auto; + margin-top: 20px; + text-align: center; + word-break: normal; + font-size: 14px; + line-height: 20px; color: var(--relaynodetxt); } - img { - border-radius: 25%; - max-width: 65px; - height: 100%; - max-height: 65px; - } - - .green { - --mdc-theme-primary: #198754; - } - .lds-roller { display: inline-block; position: relative; @@ -356,28 +309,261 @@ class QApps extends LitElement { } } + .grid-container { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + + .grid-container-search { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 10px; + } + + .container { + height: 84px; + width: 84px; + overflow: hidden; + margin: 10px auto; + border-radius: 25%; + border: 1px solid var(--black); + transition: all 0.3s ease-in-out; + box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.3); + background: linear-gradient(315deg, #045de9 0%, #09c6f9 74%); + } + + img { + cursor: pointer; + position: relative; + border-radius: 25%; + display: block; + height: 64px; + width: 64px; + object-fit: cover; + margin: 10px auto; + transition: all 0.3s ease; + } + + .round-icon { + margin-top: -87px; + margin-left: 69px; + width: 16px; + height: 16px; + border-radius: 50%; + border: 1px solid #64dd17; + background-color: #76ff03; + } + + .myapptitle { + display: flex; + justify-content: center; + max-height: 32px; + overflow: hidden; + text-overflow: ellipsis; + color: var(--black); + font-size: 17px; + font-weight: 500; + padding: 10px; + line-height: 20px; + margin-top: -10px; + text-align: center; + } + + @media (min-width: 400px) { + .grid-container { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 10px; + } + } + + @media (min-width: 640px) { + .grid-container { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 10px; + } + } + + @media (min-width: 767px) { + .grid-container { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; + } + } + + @media (min-width: 1024px) { + .grid-container { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 10px; + } + } + + @media (min-width: 1280px) { + .grid-container { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 10px; + } + } + + @media (min-width: 1600px) { + .grid-container { + display: grid; + grid-template-columns: repeat(7, 1fr); + gap: 10px; + } + } + + @media (min-width: 1920px) { + .grid-container { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 10px; + } + } + + .card-container { + background-color: var(--white); + color: var(--black); + position: relative; + width: 350px; + max-width: 100%; + text-align: center; + } + + .card-container .block { + color: rgb(3, 169, 244); + background-color: transparent; + border-radius: 3px; + border: 1px solid rgb(3, 169, 244); + font-size: 14px; + font-weight: bold; + padding: 3px 7px; + position: absolute; + top: 30px; + left: 30px; + } + + .card-container .block:hover { + color: #FFF; + background-color: rgb(3, 169, 244); + cursor: pointer; + } + + .card-container .close { + color: #df3636; + background-color: transparent; + border-radius: 3px; + border: 1px solid #df3636; + font-size: 14px; + font-weight: bold; + padding: 3px 7px; + position: absolute; + top: 30px; + right: 30px; + } + + .card-container .close:hover { + color: #FFF; + background-color: #df3636; + cursor: pointer; + } + + .card-container img { + height: 96px; + width: 96px; + } + + .buttons { + display: flex; + justify-content: space-between; + margin: 10px; + } + + button.primary { + background-color: transparent; + border: 1px solid rgb(3, 169, 244); + border-radius: 3px; + color: rgb(3, 169, 244); + font-family: Montserrat, sans-serif; + font-weight: 500; + padding: 10px 25px; + } + + button.primary:hover { + background-color: rgb(3, 169, 244); + color: #FFF; + cursor: pointer; + } + + button.secondary { + background-color: transparent; + border: 1px solid #198754; + border-radius: 3px; + color: #198754; + font-family: Montserrat, sans-serif; + font-weight: 500; + padding: 10px 25px; + } + + button.secondary:hover { + background-color: #198754; + color: #FFF; + cursor: pointer; + } + + .tags { + background-color: var(--white); + text-align: left; + padding: 10px; + margin-top: 10px; + } + + .tags ul { + list-style-type: none; + margin: 0; + padding: 0; + } + + .tags ul li { + border: 1px solid rgb(3, 169, 244); + border-radius: 3px; + display: inline-block; + font-size: 12px; + margin: 0 7px 7px 0; + padding: 7px; + } ` } constructor() { super() - this.service = "APP" - this.identifier = null this.selectedAddress = {} - this.resources = [] - this.pageRes = [] + this.appsArray = [] this.followedNames = [] this.blockedNames = [] - this.relayMode = null - this.isLoading = false - this.hasInitiallyFetched = false - this.btnDisabled = false - this.searchName = '' this.searchResources = [] this.followedResources = [] this.blockedResources = [] + this.isLoading = false + this.relayMode = false + this.service = "APP" + this.identifier = '' + this.searchName = '' this.textStatus = '' this.textProgress = '' + this.appIconUrl = '' + this.appTitle = '' + this.appPublisher = '' + this.appDescription = '' + this.appTags = '' + this.appStatus = '' + this.appFollow = '' + this.appBlock = '' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' } @@ -391,172 +577,123 @@ class QApps extends LitElement {
-
-

${translate("appspage.schange1")}

-

${this.renderSearchButton()}

-

${this.renderPublishButton()}

-
- - { - render(html`${this.renderAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderInfo(data.item)}`, root) - }}> - - { - render(html`${this.renderPublishedBy(data.item)}`, root) - }}> - - { - render(html`${this.renderDownload(data.item)}`, root) - }}> - - { - render(html`${this.renderFollowUnfollowButton(data.item)}`, root); - }}> - - { - render(html`${this.renderBlockUnblockButton(data.item)}`, root); - }}> - - -
- ${this.isLoading ? html` -
- ` : ''} - ${this.isEmptyArray(this.pageRes) && this.hasInitiallyFetched ? html` - ${translate("appspage.schange10")} - ` : ''} - ${this.renderRelayModeText()}
- -
+
+

${translate("appspage.schange1")}

+

${this.renderSearchButton()}

+

${this.renderPublishButton()}

+
+
+ ${this.isLoading ? html` +
+ +
+ ` : ''} + ${this.renderRelayModeText()} +
-
-

${translate("appspage.schange11")}

-

${this.renderSearchButton()}

-

${this.renderPublishButton()}

-
-

${translate("appspage.schange12")}

- - { - render(html`${this.renderAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderInfo(data.item)}`, root) - }}> - - { - render(html`${this.renderPublishedBy(data.item)}`, root) - }}> - - { - render(html`${this.renderDownload(data.item)}`, root) - }}> - - { - render(html`${this.renderFollowUnfollowButtonTab(data.item)}`, root); - }}> - - - ${this.followedResources == null ? html` - Loading... - ` : ''} - ${this.isEmptyArray(this.followedResources) ? html` - ${translate("appspage.schange13")} - ` : ''} - ${this.renderRelayModeText()} -
+
+

${translate("appspage.schange11")}

+

${this.renderSearchButton()}

+

${this.renderPublishButton()}

+
+
+ ${this.isLoading ? html` +
+ +
+ ` : ''} + ${this.isEmptyArray(this.followedResources) ? html`
${translate("appspage.schange13")}
` : ''} + ${this.renderRelayModeText()} +
-
-

${translate("appspage.schange14")}

-

${this.renderSearchButton()}

-

${this.renderPublishButton()}

-
-

${translate("appspage.schange15")}

- - { - render(html`${this.renderAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderInfo(data.item)}`, root) - }}> - - { - render(html`${this.renderPublishedBy(data.item)}`, root) - }}> - - { - render(html`${this.renderBlockUnblockButtonTab(data.item)}`, root); - }}> - - - ${this.blockedResources == null ? html` - Loading... - ` : ''} - ${this.isEmptyArray(this.blockedResources) ? html` - ${translate("appspage.schange16")} - ` : ''} - ${this.renderRelayModeText()} -
- - - -

${translate("appspage.schange4")}

-
- - { - render(html`${this.renderAvatar(data.item)}`, root) - }}> - - { - render(html`${this.renderPublishedBy(data.item)}`, root) - }}> - - { - render(html`${this.renderDownload(data.item)}`, root) - }}> - - { - render(html`${this.renderFollowUnfollowButton(data.item)}`, root); - }}> - - { - render(html`${this.renderBlockUnblockButton(data.item)}`, root); - }}> - - -
- -
-

${translate("appspage.schange41")}

-

${this.textProgress}

-
+
+

${translate("appspage.schange14")}

+

${this.renderSearchButton()}

+

${this.renderPublishButton()}

+
+
+ ${this.isLoading ? html` +
+ +
+ ` : ''} + ${this.isEmptyArray(this.blockedResources) ? html`
${translate("appspage.schange16")}
` : ''} + ${this.renderRelayModeText()} + + + + +
+ +
+ +
+ +
+

${translate("appspage.schange41")}

+

${this.textProgress}

+
+ +
+ ${this.appBlock} + this.closeAppInfoDialog()}>${translate("general.close")} + +

${this.appTitle}

+
${translate("appspage.schange7")}: ${this.appPublisher}
+

${this.appDescription}

+
+
TAGS
+
    +
  • ${this.appTags}
  • +
+
+
+ ${this.appStatus} + ${this.appFollow} +
+
+
+ +
+ ${this.appBlock} + this.closeBlockedInfoDialog()}>${translate("general.close")} + +

${this.appTitle}

+
${translate("appspage.schange7")}: ${this.appPublisher}
+

${this.appDescription}

+
+
TAGS
+
    +
  • ${this.appTags}
  • +
+
+
+
` } firstUpdated() { this.changeTheme() this.changeLanguage() - this.showapps() setTimeout(() => { this.displayTabContent('browse') }, 0) const getFollowedNames = async () => { - let followedNames = await parentEpml.request('apiCall', { + const followedNames = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}` }) @@ -565,7 +702,7 @@ class QApps extends LitElement { } const getBlockedNames = async () => { - let blockedNames = await parentEpml.request('apiCall', { + const blockedNames = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}` }) this.blockedNames = blockedNames @@ -573,7 +710,7 @@ class QApps extends LitElement { } const getRelayMode = async () => { - let relayMode = await parentEpml.request('apiCall', { + const relayMode = await parentEpml.request('apiCall', { url: `/arbitrary/relaymode?apiKey=${this.getApiKey()}` }) @@ -617,9 +754,6 @@ class QApps extends LitElement { setTimeout(getFollowedNames, 1) setTimeout(getBlockedNames, 1) setTimeout(getRelayMode, 1) - setTimeout(this.getFollowedNamesResource, 1) - setTimeout(this.getBlockedNamesResource, 1) - setInterval(this.getArbitraryResources, 600000) configLoaded = true } this.config = JSON.parse(c) @@ -630,6 +764,9 @@ class QApps extends LitElement { setInterval(() => { this.clearConsole() }, 60000) + setInterval(() => { + this.getAppsArrayData() + }, 600000) } clearConsole() { @@ -661,197 +798,367 @@ class QApps extends LitElement { } } - renderCatText() { - return html`${translate("appspage.schange26")}` - } - - displayTabContent(tab) { + async 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') if (tab === 'browse') { - this.refreshapps() tabBrowseContent.style.display = 'block' tabFollowedContent.style.display = 'none' tabBlockedContent.style.display = 'none' + await this.getAppsArrayData() } else if (tab === 'followed') { - this.getFollowedNamesRefresh() - this.getFollowedNamesResource() tabBrowseContent.style.display = 'none' tabFollowedContent.style.display = 'block' tabBlockedContent.style.display = 'none' + await this.getFollowedNamesRefresh() + await this.getFollowedNamesResource() } else if (tab === 'blocked') { - this.getBlockedNamesRefresh() - this.getBlockedNamesResource() tabBrowseContent.style.display = 'none' tabFollowedContent.style.display = 'none' tabBlockedContent.style.display = 'block' - } else { + await this.getBlockedNamesRefresh() + await this.getBlockedNamesResource() } } - searchListener(e) { - if (e.key === 'Enter') { - this.doSearch(e) - } + getAppsArrayData = async () => { + this.isLoading = true + this.appsArray = [] + const appsArrayRes = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=APP&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&excludeblocked=true` + }) + this.appsArray = appsArrayRes + this.isLoading = false + this.renderAppGrid() } - async getResourcesGrid() { - this.resourcesGrid = this.shadowRoot.querySelector(`#resourcesGrid`) - this.pagesControl = this.shadowRoot.querySelector('#pages') - this.pages = undefined + renderAppGrid() { + 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 gridContainer = this.shadowRoot.getElementById('apps-container') + this.shadowRoot.getElementById('apps-container').innerHTML = '' + + this.appsArray.forEach(item => { + const name = item.name + const title = item.metadata.title + const description = item.metadata.description + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}` + let tags = 'No Tags' + if (item.metadata.tags != null && item.metadata.tags.length > 0) { + tags = item.metadata.tags.join(", ") + } + const status1 = item.status.description + const status2 = item.status.status + + const openDialog = () => {this.openAppInfoDialog(url, title, name, description, tags, status1, status2)} + + let clickTimeout + let isDoubleClick = false + + const widgetElement = document.createElement('div') + + const myImage = document.createElement('img') + myImage.src = `${url}` + myImage.onerror = function() { + myImage.src = '/img/incognito.png' + } + myImage.addEventListener('click', function() { + clickTimeout = setTimeout(function() { + if (!isDoubleClick) { + openDialog() + } + isDoubleClick = false + }, 250) + }) + myImage.addEventListener('dblclick', function() { + clearTimeout(clickTimeout) + isDoubleClick = true + window.location.href = `../qdn/browser/index.html?name=${item.name}&service=APP` + }) + + const myStatus = document.createElement('div') + myStatus.classList.add('round-icon') + + const myContainer = document.createElement('div') + myContainer.classList.add('container') + myContainer.appendChild(myImage) + if (item.status.description === "Published but not yet downloaded" || item.status.status === "MISSING_DATA") { + } else if (item.status.description === "Ready" || item.status.status === "DOWNLOADED") { + myContainer.appendChild(myStatus) + } + + const myAppTitle = document.createElement('div') + myAppTitle.classList.add('myapptitle') + myAppTitle.textContent = item.metadata.title + + widgetElement.appendChild(myContainer) + widgetElement.appendChild(myAppTitle) + + gridContainer.appendChild(widgetElement) + }) } - getArbitraryResources = async () => { - const resources = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=false&includemetadata=false&excludeblocked=true` + getFollowedNamesRefresh = async () => { + this.isLoading = true + const followedNamesRes = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}` }) - this.resources = resources + this.followedNames = followedNamesRes + this.isLoading = false } getFollowedNamesResource = async () => { - const followedRes = await parentEpml.request('apiCall', { + this.isLoading = true + const followedResourcesRes = await parentEpml.request('apiCall', { url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&namefilter=followedNames` }) - this.followedResources = followedRes + this.followedResources = followedResourcesRes + this.isLoading = false + this.renderFollowedAppsGrid() } - getFollowedNamesRefresh = async () => { - let followedNames = await parentEpml.request('apiCall', { - url: `/lists/followedNames?apiKey=${this.getApiKey()}` - }) - this.followedNames = followedNames - } + renderFollowedAppsGrid() { + 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 gridContainer = this.shadowRoot.getElementById('followed-container') + this.shadowRoot.getElementById('followed-container').innerHTML = '' + + this.followedResources.forEach(item => { + const name = item.name + const title = item.metadata.title + const description = item.metadata.description + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}` + let tags = 'No Tags' + if (item.metadata.tags != null && item.metadata.tags.length > 0) { + tags = item.metadata.tags.join(", ") + } + const status1 = item.status.description + const status2 = item.status.status - getBlockedNamesResource = async () => { - const blockedRes = await parentEpml.request('apiCall', { - url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&namefilter=blockedNames` + const openDialog = () => {this.openAppInfoDialog(url, title, name, description, tags, status1, status2)} + + let clickTimeout + let isDoubleClick = false + + const widgetElement = document.createElement('div') + + const myImage = document.createElement('img') + myImage.src = `${url}` + myImage.onerror = function() { + myImage.src = '/img/incognito.png' + } + myImage.addEventListener('click', function() { + clickTimeout = setTimeout(function() { + if (!isDoubleClick) { + openDialog() + } + isDoubleClick = false + }, 250) + }) + myImage.addEventListener('dblclick', function() { + clearTimeout(clickTimeout) + isDoubleClick = true + window.location.href = `../qdn/browser/index.html?name=${item.name}&service=APP` + }) + + const myStatus = document.createElement('div') + myStatus.classList.add('round-icon') + + const myContainer = document.createElement('div') + myContainer.classList.add('container') + myContainer.appendChild(myImage) + if (item.status.description === "Published but not yet downloaded" || item.status.status === "MISSING_DATA") { + } else if (item.status.description === "Ready" || item.status.status === "DOWNLOADED") { + myContainer.appendChild(myStatus) + } + + const myAppTitle = document.createElement('div') + myAppTitle.classList.add('myapptitle') + myAppTitle.textContent = item.metadata.title + + widgetElement.appendChild(myContainer) + widgetElement.appendChild(myAppTitle) + + gridContainer.appendChild(widgetElement) }) - this.blockedResources = blockedRes } getBlockedNamesRefresh = async () => { - let blockedNames = await parentEpml.request('apiCall', { + this.isLoading = true + const blockedNamesRes = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}` }) - this.blockedNames = blockedNames + this.blockedNames = blockedNamesRes + this.isLoading = false } - async getData(offset) { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port - let jsonOffsetUrl = `${nodeUrl}/arbitrary/resources?service=APP&default=true&limit=20&offset=${offset}&reverse=false&includestatus=true&includemetadata=true&excludeblocked=true` + getBlockedNamesResource = async () => { this.isLoading = true - - const jsonOffsetRes = await fetch(jsonOffsetUrl) - const jsonOffsetData = await jsonOffsetRes.json() - - this.pageRes = jsonOffsetData - if(!this.hasInitiallyFetched){ - this.hasInitiallyFetched = true - } - this.isLoading = false + this.blockedResources = [] + const blockedResourcesRes = await parentEpml.request('apiCall', { + url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&namefilter=blockedNames` + }) + this.blockedResources = blockedResourcesRes + this.isLoading = false + this.renderBlockedAppsGrid() } - async updateItemsFromPage(page) { - if (page === undefined) { - return - } + renderBlockedAppsGrid() { + 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 gridContainer = this.shadowRoot.getElementById('blocked-container') + this.shadowRoot.getElementById('blocked-container').innerHTML = '' + + this.blockedResources.forEach(item => { + const name = item.name + const title = item.metadata.title + const description = item.metadata.description + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}` + let tags = 'No Tags' + if (item.metadata.tags != null && item.metadata.tags.length > 0) { + tags = item.metadata.tags.join(", ") + } + const status1 = item.status.description + const status2 = item.status.status - if (!this.pages) { - this.pages = Array.apply(null, { length: Math.ceil(this.resources.length / 20) }).map((item, index) => { - return index + 1 - }) + const openDialog = () => {this.openBlockedInfoDialog(url, title, name, description, tags, status1, status2)} - let offset = 0 + let clickTimeout + let isDoubleClick = false - const prevBtn = document.createElement('button') - prevBtn.textContent = '<' - prevBtn.addEventListener('click', () => { - if (parseInt(this.pagesControl.querySelector('[selected]').textContent) > 1) { - offset = (parseInt(this.pagesControl.querySelector('[selected]').textContent) - 2) * 20 - } else { - offset = 0 - } - this.getData(offset) - const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent) - this.updateItemsFromPage(selectedPage - 1) - }) - this.pagesControl.appendChild(prevBtn) - - this.pages.forEach((pageNumber) => { - const pageBtn = document.createElement('button') - pageBtn.textContent = pageNumber - let offset = 0 - pageBtn.addEventListener('click', (e) => { - if (parseInt(e.target.textContent) > 1) { - offset = (parseInt(e.target.textContent) - 1) * 20 - } else { - offset = 0 + const widgetElement = document.createElement('div') + + const myImage = document.createElement('img') + myImage.src = `${url}` + myImage.onerror = function() { + myImage.src = '/img/incognito.png' + } + myImage.addEventListener('click', function() { + clickTimeout = setTimeout(function() { + if (!isDoubleClick) { + openDialog() } - this.getData(offset) - this.updateItemsFromPage(parseInt(e.target.textContent)) - }) - if (pageNumber === page) { - pageBtn.setAttribute('selected', true) - } - this.pagesControl.appendChild(pageBtn) + isDoubleClick = false + }, 250) }) - - const nextBtn = window.document.createElement('button') - nextBtn.textContent = '>' - nextBtn.addEventListener('click', () => { - if (parseInt(this.pagesControl.querySelector('[selected]').textContent) >= 1) { - offset = ((parseInt(this.pagesControl.querySelector('[selected]').textContent) + 1) * 20) - 20 - } else { - offset = 0 - } - this.getData(offset) - const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent) - this.updateItemsFromPage(selectedPage + 1) + myImage.addEventListener('dblclick', function() { + clearTimeout(clickTimeout) + isDoubleClick = true }) - this.pagesControl.appendChild(nextBtn) - } - const buttons = Array.from(this.pagesControl.children) - buttons.forEach((btn, index) => { - if (parseInt(btn.textContent) === page) { - btn.setAttribute('selected', true) - } else { - btn.removeAttribute('selected') - } - if (index === 0) { - if (page === 1) { - btn.setAttribute('disabled', '') - } else { - btn.removeAttribute('disabled') - } - } - if (index === buttons.length - 1) { - if (page === this.pages.length) { - btn.setAttribute('disabled', '') - } else { - btn.removeAttribute('disabled') - } + const myStatus = document.createElement('div') + myStatus.classList.add('round-icon') + + const myContainer = document.createElement('div') + myContainer.classList.add('container') + myContainer.appendChild(myImage) + if (item.status.description === "Published but not yet downloaded" || item.status.status === "MISSING_DATA") { + } else if (item.status.description === "Ready" || item.status.status === "DOWNLOADED") { + myContainer.appendChild(myStatus) } + + const myAppTitle = document.createElement('div') + myAppTitle.classList.add('myapptitle') + myAppTitle.textContent = item.metadata.title + + widgetElement.appendChild(myContainer) + widgetElement.appendChild(myAppTitle) + + gridContainer.appendChild(widgetElement) }) } - async showapps() { - await this.getData(0) - await this.getArbitraryResources() - await this.getResourcesGrid() - await this.updateItemsFromPage(1, true) + openAppInfoDialog(url, title, name, description, tags, status1, status2) { + this.appIconUrl = '' + this.appTitle = '' + this.appPublisher = '' + this.appDescription = '' + this.appTags = '' + this.appStatus = '' + this.appFollow = '' + this.appBlock = '' + this.appIconUrl = url + this.appTitle = title + this.appPublisher = name + this.appDescription = description + this.appTags = tags + if (status1 === "Published but not yet downloaded" || status2 === "MISSING_DATA") { + this.appStatus = html`` + } else if (status1 === "Ready" || status2 === "DOWNLOADED") { + this.appStatus = html`` + } + if (this.followedNames.indexOf(name) === -1) { + this.appFollow = html`` + } else { + this.appFollow = html`` + } + if (this.blockedNames.indexOf(name) === -1) { + this.appBlock = html` this.blockName(name)}>${translate("appspage.schange31")}` + } else { + this.appBlock = html` this.unblockName(name)}>${translate("appspage.schange32")}` + } + this.shadowRoot.getElementById('appInfoDialog').open() + } + + closeAppInfoDialog() { + this.shadowRoot.getElementById('appInfoDialog').close() + this.appIconUrl = '' + this.appTitle = '' + this.appPublisher = '' + this.appDescription = '' + this.appTags = '' + this.appStatus = '' + this.appFollow = '' + this.appBlock = '' + } + + openBlockedInfoDialog(url, title, name, description, tags, status1, status2) { + this.appIconUrl = '' + this.appTitle = '' + this.appPublisher = '' + this.appDescription = '' + this.appTags = '' + this.appStatus = '' + this.appFollow = '' + this.appBlock = '' + this.appIconUrl = url + this.appTitle = title + this.appPublisher = name + this.appDescription = description + this.appTags = tags + if (this.blockedNames.indexOf(name) === -1) { + this.appBlock = html` this.blockName(name)}>${translate("appspage.schange31")}` + } else { + this.appBlock = html` this.unblockName(name)}>${translate("appspage.schange32")}` + } + this.shadowRoot.getElementById('blockedInfodDialog').open() } - async refreshapps() { - await this.getData(0) - await this.getArbitraryResources() - await this.updateItemsFromPage(1, true) + closeBlockedInfoDialog() { + this.shadowRoot.getElementById('blockedInfodDialog').close() + this.appIconUrl = '' + this.appTitle = '' + this.appPublisher = '' + this.appDescription = '' + this.appTags = '' + this.appStatus = '' + this.appFollow = '' + this.appBlock = '' } - doSearch(e) { - this.searchResult() + renderSearchButton() { + return html` this.openSearchDialog()}>search${translate("appspage.schange4")}` + } + + async doSearch(e) { + await this.searchResult() + } + + searchListener(e) { + if (e.key === 'Enter') { + this.doSearch(e) + } } async searchResult() { @@ -860,34 +1167,106 @@ class QApps extends LitElement { let err1string = get("appspage.schange34") parentEpml.request('showSnackBar', `${err1string}`) } else { - let searchResources = await parentEpml.request('apiCall', { - url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=5&reverse=false&includestatus=true&includemetadata=true` + const searchResourcesRes = await parentEpml.request('apiCall', { + url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&excludeblocked=true` }) - if (this.isEmptyArray(searchResources)) { + if (this.isEmptyArray(searchResourcesRes)) { let err2string = get("appspage.schange17") parentEpml.request('showSnackBar', `${err2string}`) } else { - this.searchResources = searchResources + this.searchResources = searchResourcesRes + this.renderSearchAppsGrid() } } } - renderAvatar(appObj) { - let name = appObj.name + renderSearchAppsGrid() { 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`` + const gridContainer = this.shadowRoot.getElementById('search-container') + this.shadowRoot.getElementById('search-container').innerHTML = '' + + this.searchResources.forEach(item => { + const name = item.name + const title = item.metadata.title + const description = item.metadata.description + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}` + let tags = 'No Tags' + if (item.metadata.tags != null && item.metadata.tags.length > 0) { + tags = item.metadata.tags.join(", ") + } + const status1 = item.status.description + const status2 = item.status.status + + const openDialog = () => {this.openAppInfoDialog(url, title, name, description, tags, status1, status2)} + + let clickTimeout + let isDoubleClick = false + + const widgetElement = document.createElement('div') + + const myImage = document.createElement('img') + myImage.src = `${url}` + myImage.onerror = function() { + myImage.src = '/img/incognito.png' + } + myImage.addEventListener('click', function() { + clickTimeout = setTimeout(function() { + if (!isDoubleClick) { + openDialog() + } + isDoubleClick = false + }, 250) + }) + myImage.addEventListener('dblclick', function() { + clearTimeout(clickTimeout) + isDoubleClick = true + window.location.href = `../qdn/browser/index.html?name=${item.name}&service=APP` + }) + + const myStatus = document.createElement('div') + myStatus.classList.add('round-icon') + + const myContainer = document.createElement('div') + myContainer.classList.add('container') + myContainer.appendChild(myImage) + if (item.status.description === "Published but not yet downloaded" || item.status.status === "MISSING_DATA") { + } else if (item.status.description === "Ready" || item.status.status === "DOWNLOADED") { + myContainer.appendChild(myStatus) + } + + const myAppTitle = document.createElement('div') + myAppTitle.classList.add('myapptitle') + myAppTitle.textContent = item.metadata.title + + widgetElement.appendChild(myContainer) + widgetElement.appendChild(myAppTitle) + + gridContainer.appendChild(widgetElement) + }) + this.shadowRoot.getElementById('searchAppDialog').notifyResize() + } + + openSearchDialog() { + this.searchResources = [] + this.shadowRoot.getElementById('searchName').value = '' + this.shadowRoot.getElementById('search-container').innerHTML = '' + this.shadowRoot.getElementById('searchAppDialog').open() + } + + closeSearchDialog() { + this.searchResources = [] + this.shadowRoot.getElementById('searchName').value = '' + this.shadowRoot.getElementById('search-container').innerHTML = '' + this.shadowRoot.getElementById('searchAppDialog').close() } renderRelayModeText() { if (this.relayMode === true) { return html`
${translate("appspage.schange18")} "relayModeEnabled": false ${translate("appspage.schange19")} settings.json
` - } - else if (this.relayMode === false) { + } else if (this.relayMode === false) { return html`
${translate("appspage.schange20")} "relayModeEnabled": true ${translate("appspage.schange19")} settings.json
` } - return html`` } renderPublishButton() { @@ -897,37 +1276,21 @@ class QApps extends LitElement { return html` this.publishApp()}>add${translate("appspage.schange21")}` } - renderSearchButton() { - return html` this.openSearchDialog()}>search${translate("appspage.schange4")}` - } - - openSearchDialog() { - this.searchResources = [] - this.shadowRoot.getElementById('searchName').value = '' - this.shadowRoot.getElementById('searchAppDialog').show() - } - - renderDownload(downObj) { - if (downObj.status.description === "Published but not yet downloaded" || downObj.status.status === "MISSING_DATA") { - return html` this.downloadApp(downObj)}>` - } else if (downObj.status.description === "Ready" || downObj.status.status === "DOWNLOADED") { - return html`` - } else { - return html`` - } + publishApp() { + window.location.href = `../qdn/publish/index.html?service=${this.service}&identifier=${this.identifier}&uploadType=zip&category=app&showName=true&showService=false&showIdentifier=false&showMetadata=true` } - async downloadApp(downObj) { - this.showChunks(downObj) + async downloadApp(appname) { + this.showChunks(appname) await parentEpml.request('apiCall', { - url: `/arbitrary/resource/status/APP/${downObj.name}?build=true&apiKey=${this.getApiKey()}` + url: `/arbitrary/resource/status/APP/${appname}?build=true&apiKey=${this.getApiKey()}` }) } - showChunks(downObj) { + showChunks(appname) { const checkStatus = async () => { const service = this.service - const name = downObj.name + const name = appname const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port @@ -951,58 +1314,50 @@ class QApps extends LitElement { const status = await response.json() if (status.id === "UNSUPPORTED") { - this.btnDisabled = false this.textProgress = '' clearTimeout(timerDownload) this.textStatus = status.description } else if (status.id === "BLOCKED") { - this.btnDisabled = false this.textProgress = '' this.textStatus = name + " is blocked so content cannot be served" clearTimeout(timerDownload) timerDownload = setTimeout(checkStatus, 5000) } else if (status.id === "READY") { - this.btnDisabled = false clearTimeout(timerDownload) this.textStatus = '' this.textProgress = '' this.shadowRoot.getElementById('downloadProgressDialog').close() - this.getData(0) + this.closeAppInfoDialog() + this.getAppsArrayData() this.getFollowedNamesRefresh() this.getFollowedNamesResource() this.updateComplete.then(() => this.requestUpdate()) } else if (status.id === "BUILDING") { - this.btnDisabled = true this.textProgress = '' this.textStatus = status.description clearTimeout(timerDownload) timerDownload = setTimeout(checkStatus, 1000) } else if (status.id === "BUILD_FAILED") { - this.btnDisabled = false this.textProgress = '' clearTimeout(timerDownload) this.textStatus = status.description } else if (status.id === "NOT_STARTED") { - this.btnDisabled = false this.textProgress = '' this.textStatus = status.description clearTimeout(timerDownload) timerDownload = setTimeout(checkStatus, 1000) } else if (status.id === "DOWNLOADING") { - this.btnDisabled = true this.textStatus = status.description let progressString = get("appspage.schange42") this.textProgress = progressString + ": " + status.localChunkCount + " / " + status.totalChunkCount clearTimeout(timerDownload) timerDownload = setTimeout(checkStatus, 1000) } else if (status.id === "MISSING_DATA") { - this.btnDisabled = true this.textProgress = '' this.textStatus = status.description clearTimeout(timerDownload) timerDownload = setTimeout(checkStatus, 5000) } else if (status.id === "DOWNLOADED") { - this.btnDisabled = true this.textProgress = '' this.textStatus = status.description clearTimeout(timerDownload) @@ -1012,12 +1367,8 @@ class QApps extends LitElement { checkStatus() } - publishApp() { - window.location.href = `../qdn/publish/index.html?service=${this.service}&identifier=${this.identifier}&uploadType=zip&category=app&showName=true&showService=false&showIdentifier=false&showMetadata=true` - } - - async followName(appObj) { - let name = appObj.name + async followName(appName) { + let name = appName let items = [ name ] @@ -1035,6 +1386,7 @@ class QApps extends LitElement { if (ret === true) { this.followedNames = this.followedNames.filter(item => item != name) this.followedNames.push(name) + this.closeAppInfoDialog() this.getFollowedNamesRefresh() this.getFollowedNamesResource() } else { @@ -1044,33 +1396,8 @@ class QApps extends LitElement { return ret } - async unfollowName(appObj) { - let name = appObj.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.followedNames = this.followedNames.filter(item => item != name) - } else { - let err4string = get("appspage.schange23") - parentEpml.request('showSnackBar', `${err4string}`) - } - return ret - } - - async unfollowNameTab(appObj) { - let name = appObj.name + async unfollowName(appName) { + let name = appName let items = [ name ] @@ -1087,17 +1414,18 @@ class QApps extends LitElement { if (ret === true) { this.followedNames = this.followedNames.filter(item => item != name) + this.closeAppInfoDialog() this.getFollowedNamesRefresh() this.getFollowedNamesResource() } else { - let err4string = get("websitespage.schange23") + let err4string = get("appspage.schange23") parentEpml.request('showSnackBar', `${err4string}`) } return ret } - async blockName(appObj) { - let name = appObj.name + async blockName(appName) { + let name = appName let items = [ name ] @@ -1115,6 +1443,10 @@ class QApps extends LitElement { if (ret === true) { this.blockedNames = this.blockedNames.filter(item => item != name) this.blockedNames.push(name) + this.closeAppInfoDialog() + this.getAppsArrayData() + this.getBlockedNamesRefresh() + this.getBlockedNamesResource() } else { let err5string = get("appspage.schange24") parentEpml.request('showSnackBar', `${err5string}`) @@ -1122,33 +1454,8 @@ class QApps extends LitElement { return ret } - async unblockName(appObj) { - let name = appObj.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.blockedNames = this.blockedNames.filter(item => item != name) - } else { - let err6string = get("appspage.schange25") - parentEpml.request('showSnackBar', `${err6string}`) - } - return ret - } - - async unblockNameTab(appObj) { - let name = appObj.name + async unblockName(appName) { + let name = appName let items = [ name ] @@ -1165,132 +1472,24 @@ class QApps extends LitElement { if (ret === true) { this.blockedNames = this.blockedNames.filter(item => item != name) + this.closeBlockedInfoDialog() this.getBlockedNamesRefresh() this.getBlockedNamesResource() } else { - let err6string = get("websitespage.schange25") + let err6string = get("appspage.schange25") parentEpml.request('showSnackBar', `${err6string}`) } return ret } - renderInfo(appObj) { - let name = appObj.name - let title = name - let description = "" - let categoryName = this.renderCatText() - let tags = "" - let sizeReadable = "" - - if (appObj.metadata != null) { - title = appObj.metadata.title - description = appObj.metadata.description - categoryName = appObj.metadata.categoryName - if (appObj.metadata.tags != null && appObj.metadata.tags.length > 0) { - tags = "Tags: " + appObj.metadata.tags.join(", ") - } - } - - if (appObj.size != null) { - sizeReadable = this.bytesToSize(appObj.size) - } - - return html` -
${title}
-
${description}
-
- ${categoryName}  - ${tags.length > 0 ? " | " : ""}  - ${tags}  - ${sizeReadable.length > 0 ? " | " : ""}  - ${translate("appspage.schange27")}: ${sizeReadable} -
- ` - } - - renderPublishedBy(appObj) { - if (appObj.status != null) { - return html` -
${appObj.name}
-
${translate("appspage.schange28")}: ${appObj.status.title}
- ` - } else { - return html` -
${appObj.name}
-
${translate("appspage.schange28")}: Published
- ` - } - } - - renderSize(appObj) { - if (appObj.size === null) { + renderSize(size) { + if (size === null) { return html`` } - let sizeReadable = this.bytesToSize(appObj.size) + let sizeReadable = this.bytesToSize(size) return html`${sizeReadable}` } - renderFollowUnfollowButton(appObj) { - let name = appObj.name - - if (this.followedNames == null || !Array.isArray(this.followedNames)) { - return html`` - } - - if (this.followedNames.indexOf(name) === -1) { - return html` this.followName(appObj)}>add_to_queue ${translate("appspage.schange29")}` - } else { - return html` this.unfollowName(appObj)}>remove_from_queue ${translate("appspage.schange30")}` - } - } - - renderFollowUnfollowButtonTab(appObj) { - let name = appObj.name - - if (this.followedNames == null || !Array.isArray(this.followedNames)) { - return html`` - } - - if (this.followedNames.indexOf(name) === -1) { - return html` this.followNameTab(appObj)}>add_to_queue ${translate("appspage.schange29")}` - } - else { - return html` this.unfollowNameTab(appObj)}>remove_from_queue ${translate("appspage.schange30")}` - } - } - - renderBlockUnblockButton(appObj) { - let name = appObj.name - - if (this.blockedNames == null || !Array.isArray(this.blockedNames)) { - return html`` - } - - if (this.blockedNames.indexOf(name) === -1) { - return html` this.blockName(appObj)}>block ${translate("appspage.schange31")}` - } else { - return html` this.unblockName(appObj)}>radio_button_unchecked ${translate("appspage.schange32")}` - } - } - - renderBlockUnblockButtonTab(appObj) { - let name = appObj.name - - // Only show the block/unblock button if we have permission to modify the list on this node - if (this.blockedNames == null || !Array.isArray(this.blockedNames)) { - return html`` - } - - if (this.blockedNames.indexOf(name) === -1) { - // render block button - return html` this.blockNameTab(appObj)}>block ${translate("appspage.schange31")}` - } - else { - // render unblock button - return html` this.unblockNameTab(appObj)}>radio_button_unchecked ${translate("appspage.schange32")}` - } - } - bytesToSize(bytes) { var sizes = ['bytes', 'KB', 'MB', 'GB', 'TB'] if (bytes == 0) return '0 bytes' @@ -1310,4 +1509,4 @@ class QApps extends LitElement { } } -window.customElements.define('q-apps', QApps) +window.customElements.define('q-apps', QApps) \ No newline at end of file