diff --git a/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js b/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js index 2d55c0d0..f10fef02 100644 --- a/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js @@ -4,7 +4,11 @@ import { Epml } from '../../../../epml' import '@material/mwc-icon' import '@material/mwc-button' +import '@vaadin/button' import '@vaadin/grid' +import '@vaadin/icon' +import '@vaadin/icons' +import '@vaadin/text-field' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -12,6 +16,9 @@ class DataManagement extends LitElement { static get properties() { return { loading: { type: Boolean }, + searchBlockedNames: { type: Array }, + searchFollowedNames: { type: Array }, + searchDatres: { type: Array }, blockedNames: { type: Array }, followedNames: { type: Array }, datres: { type: Array } @@ -70,6 +77,12 @@ class DataManagement extends LitElement { padding: 12px 24px; } + #search { + display: flex; + width: 50%; + align-items: center; + } + .divCard { border: 1px solid #eee; padding: 1em; @@ -135,6 +148,9 @@ class DataManagement extends LitElement { constructor() { super() this.selectedAddress = {} + this.searchBlockedNames = [] + this.searchFollowedNames = [] + this.searchDatres = [] this.blockedNames = [] this.followedNames = [] this.datres = [] @@ -147,6 +163,34 @@ class DataManagement extends LitElement {

Data Management

+
+

Search in hosted data by this node

+
+ + + + { + render(html`${this.renderSearchIdentifier(data.item)}`, root) + }}> + + { + render(html`${this.renderSearchDeleteButton(data.item)}`, root); + }}> + + { + render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root); + }}> + + +

Data hosted by this node

@@ -207,6 +251,10 @@ class DataManagement extends LitElement { setTimeout(this.getBlockedNames, 1) setInterval(this.getFollowedNames, 30 * 1000) setInterval(this.getBlockedNames, 30 * 1000) + setTimeout(this.getSearchFollowedNames, 1) + setTimeout(this.getSearchBlockedNames, 1) + setInterval(this.getSearchFollowedNames, 30 * 1000) + setInterval(this.getSearchBlockedNames, 30 * 1000) setInterval(this.getManagementDetails, 30 * 1000) configLoaded = true } @@ -222,6 +270,32 @@ class DataManagement extends LitElement { parentEpml.imReady() } + searchListener(e) { + if (e.key === 'Enter') { + this.doSearch(e); + } + } + + doSearch(e) { + this.searchResult() + } + + async searchResult() { + let searchName = this.shadowRoot.getElementById('searchName').value + if (searchName.length === 0) { + parentEpml.request('showSnackBar', 'Data Name Can Not Be Empty!') + } else { + let searchDatres = await parentEpml.request('apiCall', { + url: `/arbitrary/hosted/resources?includestatus=true&limit=20&offset=0&query=${searchName}&apiKey=${this.getApiKey()}` + }) + if (this.isEmptyArray(searchDatres)) { + parentEpml.request('showSnackBar', 'Data Not Found!') + } else { + this.searchDatres = searchDatres + } + } + } + renderDefaultText() { if (this.datres == null || !Array.isArray(this.datres)) { return html`
Couldn't fetch hosted data list from node` @@ -232,6 +306,151 @@ class DataManagement extends LitElement { return ''; } + renderSearchIdentifier(search) { + return search.identifier == null ? html`default` : html`${search.identifier}` + } + + renderSearchDeleteButton(search) { + let name = search.name + + // Only show the block/unblock button if we have permission to modify the list on this node + // We can use the blocked names list for this, as it won't be a valid array if we have no access + if (this.searchBlockedNames == null || !Array.isArray(this.searchBlockedNames)) { + return html`` + } + + // We need to check if we are following this name, as if we are, there is no point in deleting anything + // as it will be re-fetched immediately. In these cases we should show an UNFOLLOW button. + if (this.searchFollowedNames.indexOf(name) != -1) { + // render unfollow button + return html` this.searchUnfollowName(search)}>remove_from_queue Unfollow` + } + + // render delete button + return html` this.deleteSearchResource(search)} onclick="this.blur();">delete Delete` + } + + renderSearchBlockUnblockButton(search) { + let name = search.name + + // Only show the block/unblock button if we have permission to modify the list on this node + if (this.searchBlockedNames == null || !Array.isArray(this.searchBlockedNames)) { + return html`` + } + + if (this.searchBlockedNames.indexOf(name) === -1) { + // render block button + return html` this.searchBlockName(search)}>block Block` + } + else { + // render unblock button + return html` this.searchUnblockName(search)}>radio_button_unchecked Unblock` + } + } + + async searchBlockName(search) { + let name = search.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) { + // Successfully blocked - add to local list + // Remove it first by filtering the list - doing it this way ensures the UI updates + // immediately, as apposed to only adding if it doesn't already exist + this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); + this.searchBlockedNames.push(name) + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to block this registered name. Please try again') + } + + return ret + } + + async searchUnfollowName(search) { + let name = search.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) { + // Successfully unfollowed - remove from local list + this.searchFollowedNames = this.searchFollowedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') + } + + return ret + } + + async searchUnblockName(search) { + let name = search.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) { + // Successfully unblocked - remove from local list + this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') + } + + return ret + } + + async deleteSearchResource(search) { + let identifier = search.identifier == null ? "default" : search.identifier; + + let ret = await parentEpml.request('apiCall', { + url: `/arbitrary/resource/${search.service}/${search.name}/${identifier}?apiKey=${this.getApiKey()}`, + method: 'DELETE' + }) + + if (ret === true) { + // Successfully deleted - so refresh the page + window.location.reload(); + } + else { + parentEpml.request('showSnackBar', 'Error occurred when trying to delete this resource. Please try again') + } + + return ret + } + renderIdentifier(resource) { return resource.identifier == null ? html`default` : html`${resource.identifier}` } @@ -493,23 +712,31 @@ class DataManagement extends LitElement { await this.updateItemsFromPage(1, true) } + getSearchBlockedNames = async () => { + let searchBlockedNames = await parentEpml.request('apiCall', { + url: `/lists/blockedNames?apiKey=${this.getApiKey()}` + }) + this.searchBlockedNames = searchBlockedNames + } + getSearchFollowedNames = async () => { + let searchFollowedNames = await parentEpml.request('apiCall', { + url: `/lists/followedNames?apiKey=${this.getApiKey()}` + }) + this.searchFollowedNames = searchFollowedNames + } getBlockedNames = async () => { - let blockedNames = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}` }) - this.blockedNames = blockedNames } getFollowedNames = async () => { - let followedNames = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}` }) - this.followedNames = followedNames }