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
+
+
+
+
+ this.doSearch(e)}">
+
+ Search
+
+
+
+
+
+ {
+ 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
}