diff --git a/core/language/us.json b/core/language/us.json index c2c7157c..128d1c66 100644 --- a/core/language/us.json +++ b/core/language/us.json @@ -200,6 +200,8 @@ "snack3": "Successfully added and saved custom node", "snack4": "Nodes successfully saved as", "snack5": "Nodes successfully imported", + "snack6": "Successfully removed custom node", + "snack7": "Successfully edited custom node", "exp1": "Export Private Master Key", "exp2": "Export Master Key", "exp3": "Export", diff --git a/core/src/functional-components/settings-page.js b/core/src/functional-components/settings-page.js index 31b3b330..d414fd1e 100644 --- a/core/src/functional-components/settings-page.js +++ b/core/src/functional-components/settings-page.js @@ -1,419 +1,777 @@ -import { LitElement, html, css } from 'lit' -import { connect } from 'pwa-helpers' -import { store } from '../store.js' -import { doAddNode, doSetNode, doLoadNodeConfig } from '../redux/app/app-actions.js' -import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' -import snackbar from './snackbar.js' -import '../components/language-selector.js' -import '../custom-elements/frag-file-input.js' -import FileSaver from 'file-saver' +import { LitElement, html, css } from 'lit'; +import { connect } from 'pwa-helpers'; +import { store } from '../store.js'; +import { + doAddNode, + doSetNode, + doLoadNodeConfig, + doRemoveNode, + doEditNode, +} from '../redux/app/app-actions.js'; +import { + use, + get, + translate, + translateUnsafeHTML, + registerTranslateConfig, +} from 'lit-translate'; +import snackbar from './snackbar.js'; +import '../components/language-selector.js'; +import '../custom-elements/frag-file-input.js'; +import FileSaver from 'file-saver'; -import '@material/mwc-dialog' -import '@material/mwc-button' -import '@material/mwc-select' -import '@material/mwc-textfield' -import '@material/mwc-icon' -import '@material/mwc-list/mwc-list-item.js' +import '@material/mwc-dialog'; +import '@material/mwc-button'; +import '@material/mwc-select'; +import '@material/mwc-textfield'; +import '@material/mwc-icon'; +import '@material/mwc-list/mwc-list-item.js'; registerTranslateConfig({ - loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) -}) + loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json()), +}); -const checkLanguage = localStorage.getItem('qortalLanguage') +const checkLanguage = localStorage.getItem('qortalLanguage'); if (checkLanguage === null || checkLanguage.length === 0) { - localStorage.setItem('qortalLanguage', 'us') - use('us') + localStorage.setItem('qortalLanguage', 'us'); + use('us'); } else { - use(checkLanguage) + use(checkLanguage); } -let settingsDialog +let settingsDialog; class SettingsPage extends connect(store)(LitElement) { - static get properties() { - return { - lastSelected: { type: Number }, - nodeConfig: { type: Object }, - theme: { type: String, reflect: true }, - nodeIndex: { type: Number } - } - } + static get properties() { + return { + lastSelected: { type: Number }, + nodeConfig: { type: Object }, + theme: { type: String, reflect: true }, + nodeIndex: { type: Number },e + isBeingEdited: { type: Boolean }, + dropdownOpen: { type: Boolean }, + }; + } - static get styles() { - return css` - * { - --mdc-theme-primary: rgb(3, 169, 244); - --mdc-theme-secondary: var(--mdc-theme-primary); - --mdc-dialog-content-ink-color: var(--black); - --mdc-theme-surface: var(--white); - --mdc-theme-text-primary-on-background: var(--black); - --mdc-dialog-min-width: 300px; - --mdc-dialog-max-width: 650px; - --mdc-dialog-max-height: 700px; + static get styles() { + return css` + * { + --mdc-theme-primary: rgb(3, 169, 244); + --mdc-theme-secondary: var(--mdc-theme-primary); + --mdc-dialog-content-ink-color: var(--black); + --mdc-theme-surface: var(--white); + --mdc-theme-text-primary-on-background: var(--black); + --mdc-dialog-min-width: 300px; + --mdc-dialog-max-width: 650px; + --mdc-dialog-max-height: 700px; + --mdc-list-item-text-width: 100%; + } + + #main { + width: 210px; + display: flex; + align-items: center; + } + + .globe { + color: var(--black); + --mdc-icon-size: 36px; + } + + span.name { + display: inline-block; + width: 150px; + font-weight: 600; + color: #03a9f4; + border: 1px solid transparent; + } + + .red { + --mdc-theme-primary: red; + } + + .buttonred { + color: #f44336; + } + + .buttongreen { + color: #03c851; + } + .buttonBlue { + color: #03a9f4; } + .floatleft { + float: left; + } - #main { - width: 210px; + .floatright { + float: right; + } + .list-parent { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + #customSelect { + position: relative; + border: 1px solid #ccc; + cursor: pointer; + background: var(--plugback); + } + + #customSelect .selected { + padding: 10px; + display: flex; + align-items: center; + justify-content: space-between; + } + + #customSelect ul { + position: absolute; + top: 100%; + left: 0; + list-style: none; + margin: 0; + padding: 0; + border: 1px solid #ccc; + display: none; + background: var(--plugback); + width: 100%; + box-sizing: border-box; + z-index: 10; + } + + #customSelect ul.open { + display: block; + } + + #customSelect ul li { + padding: 10px; + transition: 0.2s all; + } + + #customSelect ul li:hover { + background-color: var(--graylight); + } + .selected-left-side{ display: flex; align-items: center; } + `; + } - .globe { - color: var(--black); - --mdc-icon-size: 36px; - } + constructor() { + super(); + this.nodeConfig = {}; + this.nodeIndex = localStorage.getItem('mySelectedNode'); + this.theme = localStorage.getItem('qortalTheme') + ? localStorage.getItem('qortalTheme') + : 'light'; + this.isBeingEdited = false; + this.isBeingEditedIndex = null; + this.dropdownOpen = false; + } - span.name { - display: inline-block; - width: 150px; - font-weight: 600; - color: #03a9f4; - border: 1px solid transparent; - } + render() { + console.log('this.dropdownOpen', this.dropdownOpen); + return html` + +
+

${translate('settings.settings')}

+
+
+
+
+
+
+
+ link + + ${ + this.selectedItem + ? html` +
+ + ${this.selectedItem + .name} + ${this.selectedItem + .protocol + + '://' + + this.selectedItem.domain + + ':' + + this.selectedItem + .port} +
+ ` + : 'Please select an option' + } +
+ expand_more +
+
    + ${this.nodeConfig.knownNodes.map( + (n, index) => html` +
  • +
    +
    + ${n.name} + ${n.protocol + + '://' + + n.domain + + ':' + + n.port} +
    +
    + edit + remove +
    +
    +
  • + ` + )} +
+
- .floatright { - float: right; - } - ` - } + - constructor() { - super() - this.nodeConfig = {} - this.nodeIndex = localStorage.getItem('mySelectedNode') - this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' - } +

+ ${translate('settings.nodehint')} +

+
+ add${translate('settings.addcustomnode')} +
+
+ remove${translate('settings.deletecustomnode')} +
+
+
+ ${this.renderExportNodesListButton()} +
+
+ ${this.renderImportNodesListButton()} +
+

+
+
+
+
+
+
+ language  +
+
+
+ + ${translate('general.close')} + +
- render() { - return html` - -
-

${translate("settings.settings")}

-
-
-
-
- - ${this.nodeConfig.knownNodes.map((n, index) => html` - - ${n.name} - ${n.protocol + '://' + n.domain + ':' + n.port} - - `)} - -

${translate("settings.nodehint")}

-
- add${translate("settings.addcustomnode")} -
-
- remove${translate("settings.deletecustomnode")} -
-
-
${this.renderExportNodesListButton()}
${this.renderImportNodesListButton()}
-

-
-
-

-
-
- language  -
-
-
- - ${translate("general.close")} - -
+ +
+

${translate('settings.addcustomnode')}

+
+
+
+ +
+ + http + https + +
+ + + + ${translate('general.close')} + + + ${translate('settings.addandsave')} + +
- -
-

${translate("settings.addcustomnode")}

-
-
-
- -
- - http - https - -
- - - - ${translate("general.close")} - - - ${translate("settings.addandsave")} - -
- - -
-

${translate("settings.import")}

-
-
-
-
- -

${translate("walletpage.wchange56")}

-
${translate("settings.warning")}
-
- - ${translate("general.close")} - -
- ` - } - - firstUpdated() { - const checkNode = localStorage.getItem('mySelectedNode') - if (checkNode === null || checkNode.length === 0) { - localStorage.setItem('mySelectedNode', 0) - } else { - } - } - - show() { - this.shadowRoot.getElementById('settingsDialog').show() - } - - close() { - this.shadowRoot.getElementById('settingsDialog').close() - } - - removeList() { - localStorage.removeItem("myQortalNodes") - - const obj1 = { - name: 'Local Node', - protocol: 'http', - domain: '127.0.0.1', - port: 12391, - enableManagement: true - } - - const obj2 = { - name: 'Local Testnet', - protocol: 'http', - domain: '127.0.0.1', - port: 62391, - enableManagement: true - } - - var renewNodes = []; - renewNodes.push(obj1,obj2) - localStorage.setItem('myQortalNodes', JSON.stringify(renewNodes)) - - let snack1string = get("settings.snack1") - snackbar.add({ - labelText: `${snack1string}`, - dismiss: true - }) - - localStorage.removeItem('mySelectedNode') - localStorage.setItem('mySelectedNode', 0) - - store.dispatch(doLoadNodeConfig()) - } - - nodeSelected(e) { - const selectedNodeIndex = this.shadowRoot.getElementById('nodeSelect').value - const selectedNode = this.nodeConfig.knownNodes[selectedNodeIndex] - const selectedNodeUrl = `${selectedNode.protocol + '://' + selectedNode.domain + ':' + selectedNode.port}` - - const index = parseInt(selectedNodeIndex) - if (isNaN(index)) return - - store.dispatch(doSetNode(selectedNodeIndex)) - - localStorage.removeItem('mySelectedNode') - localStorage.setItem('mySelectedNode', selectedNodeIndex) - - let snack2string = get("settings.snack2") - snackbar.add({ - labelText: `${snack2string} : ${selectedNodeUrl}`, - dismiss: true - }) - - this.shadowRoot.querySelector('#settingsDialog').close() - } - - addNode() { - const nameInput = this.shadowRoot.getElementById('nameInput').value - const protocolList = this.shadowRoot.getElementById('protocolList').value - const domainInput = this.shadowRoot.getElementById('domainInput').value - const portInput = this.shadowRoot.getElementById('portInput').value - - if (protocolList.length >= 4 && domainInput.length >= 3 && portInput.length >= 2) { - const nodeObject = { - name: nameInput, - protocol: protocolList, - domain: domainInput, - port: portInput, - enableManagement: true - } - - store.dispatch(doAddNode(nodeObject)) - - const haveNodes = JSON.parse(localStorage.getItem('myQortalNodes')) - - if (haveNodes === null || haveNodes.length === 0) { - - var savedNodes = []; - savedNodes.push(nodeObject); - localStorage.setItem('myQortalNodes', JSON.stringify(savedNodes)) - - let snack3string = get("settings.snack3") - snackbar.add({ - labelText: `${snack3string}`, - dismiss: true - }) - - this.shadowRoot.getElementById('nameInput').value = '' - this.shadowRoot.getElementById('protocolList').value = '' - this.shadowRoot.getElementById('domainInput').value = '' - this.shadowRoot.getElementById('portInput').value = '' - - this.shadowRoot.querySelector('#addNodeDialog').close() - - } else { - - var stored = JSON.parse(localStorage.getItem('myQortalNodes')); - stored.push(nodeObject); - localStorage.setItem('myQortalNodes', JSON.stringify(stored)); - - let snack3string = get("settings.snack3") - snackbar.add({ - labelText: `${snack3string}`, - dismiss: true - }) - - this.shadowRoot.getElementById('nameInput').value = '' - this.shadowRoot.getElementById('protocolList').value = '' - this.shadowRoot.getElementById('domainInput').value = '' - this.shadowRoot.getElementById('portInput').value = '' - - this.shadowRoot.querySelector('#addNodeDialog').close() - } - } - } - - openImportNodesDialog() { - this.shadowRoot.querySelector("#importQortalNodesListDialog").show() - } - - closeImportNodesDialog() { - this.shadowRoot.querySelector("#importQortalNodesListDialog").close() - } - - renderExportNodesListButton() { - return html` - - ` - } - - exportQortalNodesList() { - let nodelist = "" - const qortalNodesList = JSON.stringify(localStorage.getItem("myQortalNodes")) - const qortalNodesListSave = JSON.parse((qortalNodesList) || "[]") - const blob = new Blob([qortalNodesListSave], { type: 'text/plain;charset=utf-8' }) - nodelist = "qortal.nodes" - this.saveFileToDisk(blob, nodelist) - } - - async saveFileToDisk(blob, fileName) { - try { - const fileHandle = await self.showSaveFilePicker({ - suggestedName: fileName, - types: [{ - description: "File", - }] - }) - const writeFile = async (fileHandle, contents) => { - const writable = await fileHandle.createWritable() - await writable.write(contents) - await writable.close() - } - writeFile(fileHandle, blob).then(() => console.log("FILE SAVED")) - let snack4string = get("settings.snack4") - snackbar.add({ - labelText: `${snack4string} qortal.nodes`, - dismiss: true - }) - } catch (error) { - if (error.name === 'AbortError') { - return - } - FileSaver.saveAs(blob, fileName) - } - } - - renderImportNodesListButton() { - return html` - - ` - } - - async importQortalNodesList(file) { - localStorage.removeItem("myQortalNodes") - const newItems = JSON.parse((file) || "[]") - localStorage.setItem("myQortalNodes", JSON.stringify(newItems)) - this.shadowRoot.querySelector('#importQortalNodesListDialog').close() - - let snack5string = get("settings.snack5") - snackbar.add({ - labelText: `${snack5string}`, - dismiss: true - }) - - localStorage.removeItem('mySelectedNode') - localStorage.setItem('mySelectedNode', 0) - - store.dispatch(doLoadNodeConfig()) - } - - stateChanged(state) { - this.config = state.config - this.nodeConfig = state.app.nodeConfig + +
+

${translate('settings.import')}

+
+
+
+
+ +

+ ${translate('walletpage.wchange56')} +

+
+ ${translate('settings.warning')} +
+
+ + ${translate('general.close')} + +
+ `; + } -window.customElements.define('settings-page', SettingsPage) + firstUpdated() { + const checkNode = localStorage.getItem('mySelectedNode'); + if (checkNode === null || checkNode.length === 0) { + localStorage.setItem('mySelectedNode', 0); + } else { + } + } -const settings = document.createElement('settings-page') -settingsDialog = document.body.appendChild(settings) + toggleDropdown() { + this.dropdownOpen = !this.dropdownOpen; + } -export default settingsDialog + handleBlur(event) { + if ( + !this.shadowRoot + .querySelector('#customSelect') + .contains(event.relatedTarget) + ) { + this.dropdownOpen = false; + } + } + focusOnCustomSelect() { + const customSelect = this.shadowRoot.querySelector('#customSelect'); + if (customSelect) { + customSelect.focus(); + } + } + + handleSelection(event, node, index) { + event.stopPropagation(); + + this.selectedItem = node; + this.dropdownOpen = false; + this.requestUpdate(); + this.nodeSelected(index); + } + + show() { + this.shadowRoot.getElementById('settingsDialog').show(); + } + + close() { + this.shadowRoot.getElementById('settingsDialog').close(); + } + + removeList() { + localStorage.removeItem('myQortalNodes'); + + const obj1 = { + name: 'Local Node', + protocol: 'http', + domain: '127.0.0.1', + port: 12391, + enableManagement: true, + }; + + const obj2 = { + name: 'Local Testnet', + protocol: 'http', + domain: '127.0.0.1', + port: 62391, + enableManagement: true, + }; + + var renewNodes = []; + renewNodes.push(obj1, obj2); + localStorage.setItem('myQortalNodes', JSON.stringify(renewNodes)); + + let snack1string = get('settings.snack1'); + snackbar.add({ + labelText: `${snack1string}`, + dismiss: true, + }); + + localStorage.removeItem('mySelectedNode'); + localStorage.setItem('mySelectedNode', 0); + + store.dispatch(doLoadNodeConfig()); + } + + nodeSelected(selectedNodeIndex) { + const selectedNode = this.nodeConfig.knownNodes[selectedNodeIndex]; + const selectedNodeUrl = `${ + selectedNode.protocol + + '://' + + selectedNode.domain + + ':' + + selectedNode.port + }`; + + const index = parseInt(selectedNodeIndex); + if (isNaN(index)) return; + + store.dispatch(doSetNode(selectedNodeIndex)); + + localStorage.removeItem('mySelectedNode'); + localStorage.setItem('mySelectedNode', selectedNodeIndex); + + let snack2string = get('settings.snack2'); + snackbar.add({ + labelText: `${snack2string} : ${selectedNodeUrl}`, + dismiss: true, + }); + + // this.shadowRoot.querySelector('#settingsDialog').close(); + } + + addNode(e) { + e.stopPropagation(); + if (this.isBeingEdited) { + this.editNode(this.isBeingEditedIndex); + return; + } + const nameInput = this.shadowRoot.getElementById('nameInput').value; + const protocolList = + this.shadowRoot.getElementById('protocolList').value; + const domainInput = this.shadowRoot.getElementById('domainInput').value; + const portInput = this.shadowRoot.getElementById('portInput').value; + + if ( + protocolList.length >= 4 && + domainInput.length >= 3 && + portInput.length >= 2 + ) { + const nodeObject = { + name: nameInput, + protocol: protocolList, + domain: domainInput, + port: portInput, + enableManagement: true, + }; + + store.dispatch(doAddNode(nodeObject)); + + const haveNodes = JSON.parse(localStorage.getItem('myQortalNodes')); + + if (haveNodes === null || haveNodes.length === 0) { + var savedNodes = []; + savedNodes.push(nodeObject); + localStorage.setItem( + 'myQortalNodes', + JSON.stringify(savedNodes) + ); + + let snack3string = get('settings.snack3'); + snackbar.add({ + labelText: `${snack3string}`, + dismiss: true, + }); + + this.shadowRoot.getElementById('nameInput').value = ''; + this.shadowRoot.getElementById('protocolList').value = ''; + this.shadowRoot.getElementById('domainInput').value = ''; + this.shadowRoot.getElementById('portInput').value = ''; + + this.shadowRoot.querySelector('#addNodeDialog').close(); + } else { + var stored = JSON.parse(localStorage.getItem('myQortalNodes')); + stored.push(nodeObject); + localStorage.setItem('myQortalNodes', JSON.stringify(stored)); + + let snack3string = get('settings.snack3'); + snackbar.add({ + labelText: `${snack3string}`, + dismiss: true, + }); + + this.shadowRoot.getElementById('nameInput').value = ''; + this.shadowRoot.getElementById('protocolList').value = ''; + this.shadowRoot.getElementById('domainInput').value = ''; + this.shadowRoot.getElementById('portInput').value = ''; + + this.shadowRoot.querySelector('#addNodeDialog').close(); + } + } + } + + removeNode(event, index) { + event.stopPropagation(); + let stored = JSON.parse(localStorage.getItem('myQortalNodes')); + stored.splice(index, 1); + localStorage.setItem('myQortalNodes', JSON.stringify(stored)); + store.dispatch(doRemoveNode(index)); + let snack3string = get('settings.snack6'); + snackbar.add({ + labelText: `${snack3string}`, + dismiss: true, + }); + + this.shadowRoot.querySelector('#addNodeDialog').close(); + } + editNode(index) { + const nameInput = this.shadowRoot.getElementById('nameInput').value; + const protocolList = + this.shadowRoot.getElementById('protocolList').value; + const domainInput = this.shadowRoot.getElementById('domainInput').value; + const portInput = this.shadowRoot.getElementById('portInput').value; + + if ( + protocolList.length >= 4 && + domainInput.length >= 3 && + portInput.length >= 2 + ) { + const nodeObject = { + name: nameInput, + protocol: protocolList, + domain: domainInput, + port: portInput, + enableManagement: true, + }; + + let stored = JSON.parse(localStorage.getItem('myQortalNodes')); + const copyStored = [...stored]; + copyStored[index] = nodeObject; + localStorage.setItem('myQortalNodes', JSON.stringify(copyStored)); + store.dispatch(doEditNode(index, nodeObject)); + let snack3string = get('settings.snack7'); + snackbar.add({ + labelText: `${snack3string}`, + dismiss: true, + }); + this.shadowRoot.getElementById('nameInput').value = ''; + this.shadowRoot.getElementById('protocolList').value = ''; + this.shadowRoot.getElementById('domainInput').value = ''; + this.shadowRoot.getElementById('portInput').value = ''; + this.isBeingEdited = false; + this.isBeingEditedIndex = null; + + this.shadowRoot.querySelector('#addNodeDialog').close(); + } + } + + openImportNodesDialog() { + this.shadowRoot.querySelector('#importQortalNodesListDialog').show(); + } + + closeImportNodesDialog() { + this.shadowRoot.querySelector('#importQortalNodesListDialog').close(); + } + + renderExportNodesListButton() { + return html` + + `; + } + + exportQortalNodesList() { + let nodelist = ''; + const qortalNodesList = JSON.stringify( + localStorage.getItem('myQortalNodes') + ); + const qortalNodesListSave = JSON.parse(qortalNodesList || '[]'); + const blob = new Blob([qortalNodesListSave], { + type: 'text/plain;charset=utf-8', + }); + nodelist = 'qortal.nodes'; + this.saveFileToDisk(blob, nodelist); + } + + async saveFileToDisk(blob, fileName) { + try { + const fileHandle = await self.showSaveFilePicker({ + suggestedName: fileName, + types: [ + { + description: 'File', + }, + ], + }); + const writeFile = async (fileHandle, contents) => { + const writable = await fileHandle.createWritable(); + await writable.write(contents); + await writable.close(); + }; + writeFile(fileHandle, blob).then(() => console.log('FILE SAVED')); + let snack4string = get('settings.snack4'); + snackbar.add({ + labelText: `${snack4string} qortal.nodes`, + dismiss: true, + }); + } catch (error) { + if (error.name === 'AbortError') { + return; + } + FileSaver.saveAs(blob, fileName); + } + } + + renderImportNodesListButton() { + return html` + + `; + } + + async importQortalNodesList(file) { + localStorage.removeItem('myQortalNodes'); + const newItems = JSON.parse(file || '[]'); + localStorage.setItem('myQortalNodes', JSON.stringify(newItems)); + this.shadowRoot.querySelector('#importQortalNodesListDialog').close(); + + let snack5string = get('settings.snack5'); + snackbar.add({ + labelText: `${snack5string}`, + dismiss: true, + }); + + localStorage.removeItem('mySelectedNode'); + localStorage.setItem('mySelectedNode', 0); + + store.dispatch(doLoadNodeConfig()); + } + + stateChanged(state) { + this.config = state.config; + this.nodeConfig = state.app.nodeConfig; + } +} + +window.customElements.define('settings-page', SettingsPage); + +const settings = document.createElement('settings-page'); +settingsDialog = document.body.appendChild(settings); + +export default settingsDialog; diff --git a/core/src/redux/app/actions/node-config.js b/core/src/redux/app/actions/node-config.js index 2cf5eca1..700e0c5f 100644 --- a/core/src/redux/app/actions/node-config.js +++ b/core/src/redux/app/actions/node-config.js @@ -1,5 +1,5 @@ // Node Config Actions here... -import { LOAD_NODE_CONFIG, SET_NODE, ADD_NODE } from '../app-action-types.js' +import { LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, REMOVE_NODE, EDIT_NODE } from '../app-action-types.js' import { UI_VERSION } from '../version.js' const nodeConfigUrl = '/getConfig' @@ -72,6 +72,16 @@ export const doAddNode = (nodeObject) => { return dispatch(addNode(nodeObject)) } } +export const doRemoveNode = (index) => { + return (dispatch, getState) => { + return dispatch(removeNode(index)) + } +} +export const doEditNode = (index, nodeObject) => { + return (dispatch, getState) => { + return dispatch(editNode({index, nodeObject})) + } +} const addNode = (payload) => { return { @@ -80,6 +90,18 @@ const addNode = (payload) => { } } +const editNode = (payload) => { + return { + type: EDIT_NODE, + payload + } +} +const removeNode = (payload) => { + return { + type: REMOVE_NODE, + payload + } +} const obj1 = { name: 'Local Node', protocol: 'http', diff --git a/core/src/redux/app/app-action-types.js b/core/src/redux/app/app-action-types.js index ba2cde2a..d98ff2c6 100644 --- a/core/src/redux/app/app-action-types.js +++ b/core/src/redux/app/app-action-types.js @@ -12,6 +12,8 @@ export const UPDATE_NODE_STATUS = 'UPDATE_NODE_STATUS' export const UPDATE_NODE_INFO = 'UPDATE_NODE_INFO' export const SET_NODE = 'SET_NODE' export const ADD_NODE = 'ADD_NODE' +export const EDIT_NODE = 'EDIT_NODE' +export const REMOVE_NODE = 'REMOVE_NODE' export const LOAD_NODE_CONFIG = 'LOAD_NODE_CONFIG' export const PAGE_URL = 'PAGE_URL' export const CHAT_HEADS = 'CHAT_HEADS' diff --git a/core/src/redux/app/app-reducer.js b/core/src/redux/app/app-reducer.js index 11e77486..d8d8abd2 100644 --- a/core/src/redux/app/app-reducer.js +++ b/core/src/redux/app/app-reducer.js @@ -1,9 +1,9 @@ // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' -import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG } from './app-action-types.js' +import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS, IS_OPEN_DEV_DIALOG, REMOVE_NODE, EDIT_NODE } from './app-action-types.js' import { initWorkersReducer } from './reducers/init-workers.js' import { loginReducer } from './reducers/login-reducer.js' -import { setNode, addNode } from './reducers/manage-node.js' +import { setNode, addNode, removeNode, editNode } from './reducers/manage-node.js' import localForage from "localforage"; const chatLastSeen = localForage.createInstance({ name: "chat-last-seen", @@ -120,6 +120,10 @@ export default (state = INITIAL_STATE, action) => { return setNode(state, action) case ADD_NODE: return addNode(state, action) + case EDIT_NODE: + return editNode(state, action) + case REMOVE_NODE: + return removeNode(state, action) case PAGE_URL: return { ...state, diff --git a/core/src/redux/app/reducers/manage-node.js b/core/src/redux/app/reducers/manage-node.js index ad284452..4e42f01f 100644 --- a/core/src/redux/app/reducers/manage-node.js +++ b/core/src/redux/app/reducers/manage-node.js @@ -20,3 +20,26 @@ export const addNode = (state, action) => { } } } + +export const editNode = (state, action) => { + const copyKnownNodes = [...state.nodeConfig.knownNodes] + copyKnownNodes[action.payload.index] = action.payload.nodeObject + return { + ...state, + nodeConfig: { + ...state.nodeConfig, + knownNodes: copyKnownNodes + } + } +} +export const removeNode = (state, action) => { + const copyKnownNodes = [...state.nodeConfig.knownNodes] + copyKnownNodes.splice(action.payload, 1); + return { + ...state, + nodeConfig: { + ...state.nodeConfig, + knownNodes: copyKnownNodes + } + } +}