mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-24 12:38:57 +00:00
366 lines
14 KiB
QML
366 lines
14 KiB
QML
import QtQuick 2.13
|
||
import QtQuick.Layouts 1.13
|
||
|
||
import StatusQ 0.1
|
||
import StatusQ.Controls 0.1
|
||
import StatusQ.Components 0.1
|
||
import StatusQ.Core 0.1
|
||
import StatusQ.Core.Backpressure 0.1
|
||
import StatusQ.Core.Theme 0.1
|
||
import StatusQ.Core.Utils 0.1
|
||
import StatusQ.Popups 0.1
|
||
|
||
import SortFilterProxyModel 0.2
|
||
|
||
import shared.panels 1.0
|
||
import utils 1.0
|
||
|
||
ColumnLayout {
|
||
id: root
|
||
|
||
property var network
|
||
property var rpcProviders
|
||
property var networksModule
|
||
property var networkRPCChanged
|
||
signal evaluateRpcEndPoint(string url, bool isMainUrl)
|
||
signal updateNetworkValues(int chainId, string newMainRpcInput, string newFailoverRpcUrl)
|
||
|
||
enum EvaluationState {
|
||
UnTouched,
|
||
Pending,
|
||
Verified,
|
||
InvalidURL,
|
||
PingUnsuccessful,
|
||
SameAsOther,
|
||
NotSameChain,
|
||
Empty,
|
||
RestartRequired
|
||
}
|
||
|
||
QtObject {
|
||
id: d
|
||
|
||
readonly property SortFilterProxyModel userRpcProvidersModel: SortFilterProxyModel {
|
||
sourceModel: root.rpcProviders
|
||
filters: [
|
||
ValueFilter { roleName: "chainId"; value: network.chainId },
|
||
ValueFilter { roleName: "providerType"; value: Constants.rpcProviderTypes.user }
|
||
]
|
||
}
|
||
readonly property int userRpcProvidersModelCount: d.userRpcProvidersModel.ModelCount.count ?? 0
|
||
|
||
property var mainRpcProvider
|
||
readonly property string mainRpcProviderUrl: !!d.mainRpcProvider ? d.mainRpcProvider.url : ""
|
||
property var fallbackRpcProvider
|
||
readonly property string fallbackRpcProviderUrl: !!d.fallbackRpcProvider ? d.fallbackRpcProvider.url : ""
|
||
|
||
function fetchProviders() {
|
||
mainRpcProvider = d.userRpcProvidersModelCount > 0 ? ModelUtils.get(d.userRpcProvidersModel, 0) : undefined
|
||
fallbackRpcProvider = d.userRpcProvidersModelCount > 1 ? ModelUtils.get(d.userRpcProvidersModel, 1) : undefined
|
||
}
|
||
|
||
onUserRpcProvidersModelCountChanged: d.fetchProviders()
|
||
Component.onCompleted: d.fetchProviders()
|
||
|
||
property int evaluationStatusMainRpc: EditNetworkForm.UnTouched
|
||
property int evaluationStatusFallBackRpc: EditNetworkForm.UnTouched
|
||
property var evaluateRpcEndPoint: Backpressure.debounce(root, 400, function (value, isMainUrl) {
|
||
if(!Utils.isURL(value)) {
|
||
if(isMainUrl)
|
||
d.evaluationStatusMainRpc = EditNetworkForm.InvalidURL
|
||
else
|
||
d.evaluationStatusFallBackRpc = EditNetworkForm.InvalidURL
|
||
return
|
||
}
|
||
root.evaluateRpcEndPoint(value, isMainUrl)
|
||
})
|
||
|
||
function getUrlStatusText(status, text) {
|
||
switch(status) {
|
||
case EditNetworkForm.Pending:
|
||
return qsTr("Checking RPC...")
|
||
case EditNetworkForm.InvalidURL:
|
||
return qsTr("What is %1? This isn’t a URL 😒").arg(text)
|
||
case EditNetworkForm.PingUnsuccessful:
|
||
return qsTr("RPC appears to be either offline or this is not a valid JSON RPC endpoint URL")
|
||
case EditNetworkForm.Verified:
|
||
return qsTr("RPC successfully reached")
|
||
case EditNetworkForm.SameAsOther:
|
||
return qsTr("JSON RPC URLs are the same")
|
||
case EditNetworkForm.NotSameChain:
|
||
return qsTr("Chain ID returned from JSON RPC doesn’t match %1").arg(network.chainName)
|
||
case EditNetworkForm.RestartRequired:
|
||
return qsTr("Restart required for changes to take effect")
|
||
default: return ""
|
||
}
|
||
}
|
||
|
||
function getErrorMessageColor(status) {
|
||
switch(status) {
|
||
case EditNetworkForm.Pending:
|
||
return Theme.palette.baseColor1
|
||
case EditNetworkForm.SameAsOther:
|
||
case EditNetworkForm.NotSameChain:
|
||
case EditNetworkForm.RestartRequired:
|
||
return Theme.palette.warningColor1
|
||
case EditNetworkForm.Verified:
|
||
return Theme.palette.successColor1
|
||
default: return Theme.palette.dangerColor1
|
||
}
|
||
}
|
||
|
||
function getErrorMessageAlignment(status) {
|
||
switch(status) {
|
||
case EditNetworkForm.Pending:
|
||
case EditNetworkForm.Verified:
|
||
case EditNetworkForm.SameAsOther:
|
||
case EditNetworkForm.NotSameChain:
|
||
case EditNetworkForm.RestartRequired:
|
||
return Text.AlignLeft
|
||
default: return Text.AlignRight
|
||
}
|
||
}
|
||
|
||
function save() {
|
||
if (d.evaluationStatusMainRpc == EditNetworkForm.UnTouched && d.evaluationStatusFallBackRpc == EditNetworkForm.UnTouched) {
|
||
return
|
||
}
|
||
|
||
let main = mainRpcInput.text
|
||
let fallback = failoverRpcUrlInput.text
|
||
root.updateNetworkValues(network.chainId, main, fallback)
|
||
root.networkRPCChanged[network.chainId] = true
|
||
}
|
||
}
|
||
|
||
Connections {
|
||
target: networksModule
|
||
function onChainIdFetchedForUrl(url, chainId, success, isMainUrl) {
|
||
let status = EditNetworkForm.PingUnsuccessful
|
||
if(success) {
|
||
if (network.chainId !== chainId) {
|
||
status = EditNetworkForm.NotSameChain
|
||
}
|
||
else if((isMainUrl && url === network.fallbackURL) ||
|
||
(!isMainUrl && url === network.rpcURL)) {
|
||
status = EditNetworkForm.SameAsOther
|
||
}
|
||
else
|
||
status = EditNetworkForm.Verified
|
||
}
|
||
if(isMainUrl)
|
||
d.evaluationStatusMainRpc = status
|
||
else
|
||
d.evaluationStatusFallBackRpc = status
|
||
}
|
||
}
|
||
|
||
spacing: 20
|
||
|
||
StatusInput {
|
||
Layout.fillWidth: true
|
||
label: qsTr("Network name")
|
||
input.edit.objectName: "editNetworkNameInput"
|
||
text: !!network ? network.chainName : ""
|
||
input.enabled: false
|
||
}
|
||
|
||
StatusInput {
|
||
Layout.fillWidth: true
|
||
label: qsTr("Short name")
|
||
input.edit.objectName: "editNetworkShortNameInput"
|
||
text: !!network ? network.shortName : ""
|
||
input.enabled: false
|
||
}
|
||
|
||
StatusInput {
|
||
Layout.fillWidth: true
|
||
input.edit.objectName: "editNetworkChainIdInput"
|
||
label: qsTr("Chain ID")
|
||
text: !!network ? network.chainId : ""
|
||
input.enabled: false
|
||
}
|
||
|
||
StatusInput {
|
||
Layout.fillWidth: true
|
||
input.edit.objectName: "editNetworkSymbolInput"
|
||
label: qsTr("Native Token Symbol")
|
||
text: !!network ? network.nativeCurrencySymbol : ""
|
||
input.enabled: false
|
||
}
|
||
|
||
Item {
|
||
Layout.fillWidth: true
|
||
Layout.preferredHeight: childrenRect.height
|
||
StatusInput {
|
||
id: mainRpcInput
|
||
objectName: "mainRpcInputObject"
|
||
input.edit.objectName: "editNetworkMainRpcInput"
|
||
width: parent.width
|
||
label: qsTr("User JSON RPC URL #1")
|
||
text: d.mainRpcProviderUrl
|
||
onTextChanged: {
|
||
if (text === "") {
|
||
d.evaluationStatusMainRpc = EditNetworkForm.Empty
|
||
return
|
||
} else {
|
||
if (d.mainRpcProviderUrl === text) {
|
||
d.evaluationStatusMainRpc = EditNetworkForm.UnTouched
|
||
if (root.networkRPCChanged[network.chainId]) {
|
||
d.evaluationStatusMainRpc = EditNetworkForm.RestartRequired
|
||
}
|
||
} else {
|
||
d.evaluationStatusMainRpc = EditNetworkForm.Pending
|
||
Qt.callLater(d.evaluateRpcEndPoint, text, true);
|
||
}
|
||
}
|
||
}
|
||
errorMessageCmp.horizontalAlignment: d.getErrorMessageAlignment(d.evaluationStatusMainRpc)
|
||
errorMessageCmp.visible: d.evaluationStatusMainRpc !== EditNetworkForm.UnTouched
|
||
|
||
errorMessageCmp.color: d.getErrorMessageColor(d.evaluationStatusMainRpc)
|
||
errorMessageCmp.text: d.getUrlStatusText(d.evaluationStatusMainRpc, text)
|
||
}
|
||
}
|
||
|
||
Item {
|
||
Layout.fillWidth: true
|
||
Layout.preferredHeight: childrenRect.height
|
||
StatusInput {
|
||
id: failoverRpcUrlInput
|
||
objectName: "failoverRpcUrlInputObject"
|
||
input.edit.objectName: "editNetworkFailoverRpcUrlInput"
|
||
width: parent.width
|
||
label: qsTr("User JSON RPC URL #2")
|
||
text: d.fallbackRpcProviderUrl
|
||
onTextChanged: {
|
||
if (text === "") {
|
||
d.evaluationStatusFallBackRpc = EditNetworkForm.Empty
|
||
return
|
||
}
|
||
|
||
if (d.fallbackRpcProviderUrl === text) {
|
||
d.evaluationStatusFallBackRpc = EditNetworkForm.UnTouched
|
||
if (root.networkRPCChanged[network.chainId]) {
|
||
d.evaluationStatusFallBackRpc = EditNetworkForm.RestartRequired
|
||
}
|
||
} else {
|
||
d.evaluationStatusFallBackRpc = EditNetworkForm.Pending
|
||
Qt.callLater(d.evaluateRpcEndPoint, text, false);
|
||
}
|
||
}
|
||
errorMessageCmp.horizontalAlignment: d.getErrorMessageAlignment(d.evaluationStatusFallBackRpc)
|
||
errorMessageCmp.visible: d.evaluationStatusFallBackRpc !== EditNetworkForm.UnTouched
|
||
errorMessageCmp.text: d.getUrlStatusText(d.evaluationStatusFallBackRpc, text)
|
||
errorMessageCmp.color: d.getErrorMessageColor(d.evaluationStatusFallBackRpc)
|
||
}
|
||
}
|
||
|
||
StatusInput {
|
||
input.edit.objectName: "editNetworkExplorerInput"
|
||
Layout.fillWidth: true
|
||
label: qsTr("Block Explorer")
|
||
text: !!network ? network.blockExplorerURL : ""
|
||
input.enabled: false
|
||
}
|
||
|
||
StatusCheckBox {
|
||
id: warningCheckbox
|
||
objectName: "editNetworkAknowledgmentCheckbox"
|
||
Layout.fillWidth: true
|
||
text: qsTr("I understand that changing network settings can cause unforeseen issues, errors, security risks and potentially even loss of funds.")
|
||
checkState: Qt.Unchecked
|
||
font.pixelSize: 15
|
||
}
|
||
|
||
Separator {}
|
||
|
||
Row {
|
||
Layout.alignment: Qt.AlignRight
|
||
StatusButton {
|
||
objectName: "editNetworkSaveButton"
|
||
text: qsTr("Save Changes")
|
||
enabled: (
|
||
d.evaluationStatusMainRpc === EditNetworkForm.Verified ||
|
||
d.evaluationStatusFallBackRpc === EditNetworkForm.Verified ||
|
||
d.evaluationStatusMainRpc === EditNetworkForm.SameAsOther ||
|
||
d.evaluationStatusFallBackRpc === EditNetworkForm.SameAsOther ||
|
||
d.evaluationStatusMainRpc === EditNetworkForm.Empty ||
|
||
d.evaluationStatusFallBackRpc === EditNetworkForm.Empty ||
|
||
d.evaluationStatusMainRpc === EditNetworkForm.NotSameChain ||
|
||
d.evaluationStatusFallBackRpc === EditNetworkForm.NotSameChain ||
|
||
d.evaluationStatusMainRpc === EditNetworkForm.RestartRequired ||
|
||
d.evaluationStatusFallBackRpc === EditNetworkForm.RestartRequired
|
||
) && warningCheckbox.checked
|
||
|
||
onClicked: {
|
||
Global.openPopup(confirmationDialogComponent)
|
||
}
|
||
}
|
||
}
|
||
|
||
Component {
|
||
id: confirmationDialogComponent
|
||
StatusModal {
|
||
headerSettings.title: qsTr("RPC URL change requires app restart")
|
||
contentItem: Item {
|
||
width: parent.width
|
||
implicitHeight: childrenRect.height
|
||
Column {
|
||
width: parent.width - 32
|
||
anchors.horizontalCenter: parent.horizontalCenter
|
||
|
||
Item {
|
||
width: parent.width
|
||
height: 16
|
||
}
|
||
|
||
StatusBaseText {
|
||
objectName: "mustBeRestartedText"
|
||
text: qsTr("For new JSON RPC URLs to take effect, Status must be restarted. Are you ready to do this now?")
|
||
font.pixelSize: 15
|
||
anchors.left: parent.left
|
||
anchors.right: parent.right
|
||
wrapMode: Text.WordWrap
|
||
color: Theme.palette.directColor1
|
||
}
|
||
|
||
Item {
|
||
width: parent.width
|
||
height: 16
|
||
}
|
||
}
|
||
}
|
||
|
||
rightButtons: [
|
||
StatusFlatButton {
|
||
id: laterButton
|
||
objectName: "laterButton"
|
||
text: qsTr("Save and restart later")
|
||
type: StatusBaseButton.Type.Normal
|
||
onClicked: {
|
||
close()
|
||
d.save()
|
||
d.evaluationStatusMainRpc = EditNetworkForm.RestartRequired
|
||
}
|
||
},
|
||
StatusButton {
|
||
id: saveButton
|
||
objectName: "saveButton"
|
||
type: StatusBaseButton.Type.Normal
|
||
text: qsTr("Save and restart Status")
|
||
focus: true
|
||
Keys.onReturnPressed: function(event) {
|
||
saveButton.clicked()
|
||
}
|
||
onClicked: {
|
||
close()
|
||
d.save()
|
||
Qt.quit()
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|