feature/api-controller-improvements (#567)

* added error handler for api controller
* while downloading the config from the api, the Connecting status is now displayed
* added a button to delete container config for api servers
* added crc check to avoid re-import of api configs
* fixed currentIndex of serversMenuContent after DefaultServerIndexChanged
* added closing the import window after re-importing the config from api
This commit is contained in:
Nethius 2024-02-09 23:23:26 +05:00 committed by GitHub
parent dba05aab07
commit e0863a58aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 275 additions and 113 deletions

View file

@ -91,12 +91,11 @@ void AmneziaApplication::init()
initControllers(); initControllers();
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
if(!AndroidController::initLogging()) { if (!AndroidController::initLogging()) {
qFatal("Android logging initialization failed"); qFatal("Android logging initialization failed");
} }
AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs()); AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs());
connect(m_settings.get(), &Settings::saveLogsChanged, connect(m_settings.get(), &Settings::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
AndroidController::instance(), &AndroidController::setSaveLogs);
connect(AndroidController::instance(), &AndroidController::initConnectionState, this, connect(AndroidController::instance(), &AndroidController::initConnectionState, this,
[this](Vpn::ConnectionState state) { [this](Vpn::ConnectionState state) {
@ -331,8 +330,8 @@ void AmneziaApplication::initModels()
m_clientManagementModel.reset(new ClientManagementModel(m_settings, this)); m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get()); m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
m_serversModel.get(), &ServersModel::clearCachedProfile); &ServersModel::clearCachedProfile);
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this, connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this,
[this](const QString &clientId, const QString &clientName, const DockerContainer container, [this](const QString &clientId, const QString &clientName, const DockerContainer container,
@ -370,12 +369,13 @@ void AmneziaApplication::initControllers()
m_settings, m_configurator)); m_settings, m_configurator));
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get()); m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_sitesModel, m_settings)); m_settingsController.reset(
new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_sitesModel, m_settings));
m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get()); m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) { if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); }); QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
} }
connect(m_settingsController.get(), &SettingsController::amneziaDnsToggled , m_serversModel.get(), connect(m_settingsController.get(), &SettingsController::amneziaDnsToggled, m_serversModel.get(),
&ServersModel::toggleAmneziaDns); &ServersModel::toggleAmneziaDns);
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel)); m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
@ -384,6 +384,11 @@ void AmneziaApplication::initControllers()
m_systemController.reset(new SystemController(m_settings)); m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get()); m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
m_cloudController.reset(new ApiController(m_serversModel, m_containersModel)); m_apiController.reset(new ApiController(m_serversModel, m_containersModel));
m_engine->rootContext()->setContextProperty("ApiController", m_cloudController.get()); m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get());
connect(m_apiController.get(), &ApiController::updateStarted, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); });
connect(m_apiController.get(), &ApiController::errorOccurred, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected); });
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(), &ConnectionController::toggleConnection);
} }

View file

@ -121,7 +121,7 @@ private:
QScopedPointer<SettingsController> m_settingsController; QScopedPointer<SettingsController> m_settingsController;
QScopedPointer<SitesController> m_sitesController; QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController; QScopedPointer<SystemController> m_systemController;
QScopedPointer<ApiController> m_cloudController; QScopedPointer<ApiController> m_apiController;
}; };
#endif // AMNEZIA_APPLICATION_H #endif // AMNEZIA_APPLICATION_H

View file

@ -88,7 +88,11 @@ namespace amnezia
ImportInvalidConfigError = 900, ImportInvalidConfigError = 900,
// Android errors // Android errors
AndroidError = 1000 AndroidError = 1000,
// Api errors
ApiConfigDownloadError = 1100,
ApiConfigAlreadyAdded = 1101
}; };
} // namespace amnezia } // namespace amnezia

View file

@ -64,6 +64,10 @@ QString errorString(ErrorCode code) {
// Android errors // Android errors
case (AndroidError): errorMessage = QObject::tr("VPN connection error"); break; case (AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
// Api errors
case (ApiConfigDownloadError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
case (ApiConfigAlreadyAdded): errorMessage = QObject::tr("This config has already been added to the application"); break;
case(InternalError): case(InternalError):
default: default:
errorMessage = QObject::tr("Internal error"); break; errorMessage = QObject::tr("Internal error"); break;

View file

@ -85,6 +85,8 @@ namespace amnezia
constexpr char splitTunnelSites[] = "splitTunnelSites"; constexpr char splitTunnelSites[] = "splitTunnelSites";
constexpr char splitTunnelType[] = "splitTunnelType"; constexpr char splitTunnelType[] = "splitTunnelType";
constexpr char crc[] = "crc";
} }
namespace protocols namespace protocols

View file

@ -3,9 +3,11 @@
#include <QEventLoop> #include <QEventLoop>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QtConcurrent>
#include "configurators/openvpn_configurator.h" #include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h" #include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h"
namespace namespace
{ {
@ -28,7 +30,8 @@ ApiController::ApiController(const QSharedPointer<ServersModel> &serversModel,
{ {
} }
void ApiController::processCloudConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config) void ApiController::processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData,
QString &config)
{ {
if (protocol == configKey::cloak) { if (protocol == configKey::cloak) {
config.replace("<key>", "<key>\n"); config.replace("<key>", "<key>\n");
@ -64,73 +67,91 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
return obj; return obj;
} }
bool ApiController::updateServerConfigFromApi() void ApiController::updateServerConfigFromApi()
{
QtConcurrent::run([this]() {
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
bool isConfigUpdateStarted = false;
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
isConfigUpdateStarted = true;
QNetworkAccessManager manager;
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization",
"Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
request.setUrl(endpoint.replace("https", "http")); // todo remove
QString protocol = serverConfig.value(configKey::protocol).toString();
auto apiPayloadData = generateApiPayloadData(protocol);
QByteArray requestBody = QJsonDocument(fillApiPayload(protocol, apiPayloadData)).toJson();
QScopedPointer<QNetworkReply> reply;
reply.reset(manager.post(request, requestBody));
QEventLoop wait;
QObject::connect(reply.get(), &QNetworkReply::finished, &wait, &QEventLoop::quit);
wait.exec();
if (reply->error() == QNetworkReply::NoError) {
QString contents = QString::fromUtf8(reply->readAll());
auto data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
processApiConfig(protocol, apiPayloadData, configStr);
QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig.insert(config_key::dns1, apiConfig.value(config_key::dns1));
serverConfig.insert(config_key::dns2, apiConfig.value(config_key::dns2));
serverConfig.insert(config_key::containers, apiConfig.value(config_key::containers));
serverConfig.insert(config_key::hostName, apiConfig.value(config_key::hostName));
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig);
emit m_serversModel->defaultContainerChanged(ContainerProps::containerFromString(defaultContainer));
} else {
qDebug() << reply->error();
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
return;
}
}
emit updateFinished(isConfigUpdateStarted);
return;
});
}
void ApiController::clearApiConfig()
{ {
auto serverConfig = m_serversModel->getDefaultServerConfig(); auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray(); serverConfig.remove(config_key::dns1);
serverConfig.remove(config_key::dns2);
serverConfig.remove(config_key::containers);
serverConfig.remove(config_key::hostName);
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) { serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
QNetworkAccessManager manager;
QNetworkRequest request; m_serversModel->editServer(serverConfig);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization",
"Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
request.setUrl(endpoint.replace("https", "http")); // todo remove
QString protocol = serverConfig.value(configKey::protocol).toString();
auto apiPayloadData = generateApiPayloadData(protocol);
QByteArray requestBody = QJsonDocument(fillApiPayload(protocol, apiPayloadData)).toJson();
QScopedPointer<QNetworkReply> reply;
reply.reset(manager.post(request, requestBody));
QEventLoop wait;
QObject::connect(reply.get(), &QNetworkReply::finished, &wait, &QEventLoop::quit);
wait.exec();
if (reply->error() == QNetworkReply::NoError) {
QString contents = QString::fromUtf8(reply->readAll());
auto data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
processCloudConfig(protocol, apiPayloadData, configStr);
QJsonObject cloudConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig.insert("cloudConfig", cloudConfig);
serverConfig.insert(config_key::dns1, cloudConfig.value(config_key::dns1));
serverConfig.insert(config_key::dns2, cloudConfig.value(config_key::dns2));
serverConfig.insert(config_key::containers, cloudConfig.value(config_key::containers));
serverConfig.insert(config_key::hostName, cloudConfig.value(config_key::hostName));
auto defaultContainer = cloudConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig);
emit m_serversModel->defaultContainerChanged(ContainerProps::containerFromString(defaultContainer));
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll()); //todo remove debug output
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(tr("Error when retrieving configuration from cloud server"));
return false;
}
}
return true;
} }

View file

@ -16,9 +16,13 @@ public:
const QSharedPointer<ContainersModel> &containersModel, QObject *parent = nullptr); const QSharedPointer<ContainersModel> &containersModel, QObject *parent = nullptr);
public slots: public slots:
bool updateServerConfigFromApi(); void updateServerConfigFromApi();
void clearApiConfig();
signals: signals:
void updateStarted();
void updateFinished(bool isConfigUpdateStarted);
void errorOccurred(const QString &errorMessage); void errorOccurred(const QString &errorMessage);
private: private:
@ -31,7 +35,7 @@ private:
ApiPayloadData generateApiPayloadData(const QString &protocol); ApiPayloadData generateApiPayloadData(const QString &protocol);
QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData); QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData);
void processCloudConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config); void processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config);
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;

View file

@ -25,6 +25,11 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
void ConnectionController::openConnection() void ConnectionController::openConnection()
{ {
if (!m_containersModel->isAnyContainerInstalled()) {
emit noInstalledContainers();
return;
}
int serverIndex = m_serversModel->getDefaultServerIndex(); int serverIndex = m_serversModel->getDefaultServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
@ -129,6 +134,17 @@ QString ConnectionController::connectionStateText() const
return m_connectionStateText; return m_connectionStateText;
} }
void ConnectionController::toggleConnection(bool skipConnectionInProgressCheck)
{
if (!skipConnectionInProgressCheck && isConnectionInProgress()) {
closeConnection();
} else if (isConnected()) {
closeConnection();
} else {
openConnection();
}
}
bool ConnectionController::isConnectionInProgress() const bool ConnectionController::isConnectionInProgress() const
{ {
return m_isConnectionInProgress; return m_isConnectionInProgress;

View file

@ -26,6 +26,8 @@ public:
QString connectionStateText() const; QString connectionStateText() const;
public slots: public slots:
void toggleConnection(bool skipConnectionInProgressCheck);
void openConnection(); void openConnection();
void closeConnection(); void closeConnection();
@ -45,6 +47,8 @@ signals:
void connectionErrorOccurred(const QString &errorMessage); void connectionErrorOccurred(const QString &errorMessage);
void reconnectWithUpdatedContainer(const QString &message); void reconnectWithUpdatedContainer(const QString &message);
void noInstalledContainers();
private: private:
Vpn::ConnectionState getCurrentConnectionState(); Vpn::ConnectionState getCurrentConnectionState();

View file

@ -123,12 +123,19 @@ void ImportController::importConfig()
credentials.userName = m_config.value(config_key::userName).toString(); credentials.userName = m_config.value(config_key::userName).toString();
credentials.secretData = m_config.value(config_key::password).toString(); credentials.secretData = m_config.value(config_key::password).toString();
if (credentials.isValid() if (credentials.isValid() || m_config.contains(config_key::containers)) {
|| m_config.contains(config_key::containers)
|| m_config.contains(config_key::configVersion)) { // todo
m_serversModel->addServer(m_config); m_serversModel->addServer(m_config);
emit importFinished(); emit importFinished();
} else if (m_config.contains(config_key::configVersion)) {
quint16 crc = qChecksum(QJsonDocument(m_config).toJson());
if (m_serversModel->isServerFromApiAlreadyExists(crc)) {
emit importErrorOccurred(errorString(ErrorCode::ApiConfigAlreadyAdded), true);
} else {
m_config.insert(config_key::crc, crc);
m_serversModel->addServer(m_config);
emit importFinished();
}
} else { } else {
qDebug() << "Failed to import profile"; qDebug() << "Failed to import profile";
qDebug().noquote() << QJsonDocument(m_config).toJson(); qDebug().noquote() << QJsonDocument(m_config).toJson();

View file

@ -39,7 +39,7 @@ public slots:
signals: signals:
void importFinished(); void importFinished();
void importErrorOccurred(const QString &errorMessage); void importErrorOccurred(const QString &errorMessage, bool goToPageHome = false);
void qrDecodingFinished(); void qrDecodingFinished();

View file

@ -53,7 +53,7 @@ QVariant ContainersModel::data(const int index, int role) const
return data(modelIndex, role); return data(modelIndex, role);
} }
void ContainersModel::updateModel(QJsonArray &containers) void ContainersModel::updateModel(const QJsonArray &containers)
{ {
beginResetModel(); beginResetModel();
m_containers.clear(); m_containers.clear();

View file

@ -40,7 +40,7 @@ public:
QVariant data(const int index, int role) const; QVariant data(const int index, int role) const;
public slots: public slots:
void updateModel(QJsonArray &containers); void updateModel(const QJsonArray &containers);
DockerContainer getDefaultContainer(); DockerContainer getDefaultContainer();
void setDefaultContainer(const int containerIndex); void setDefaultContainer(const int containerIndex);

View file

@ -331,6 +331,11 @@ QJsonObject ServersModel::getDefaultServerConfig()
return m_servers.at(m_defaultServerIndex).toObject(); return m_servers.at(m_defaultServerIndex).toObject();
} }
QJsonObject ServersModel::getCurrentlyProcessedServerConfig()
{
return m_servers.at(m_currentlyProcessedServerIndex).toObject();
}
void ServersModel::reloadContainerConfig() void ServersModel::reloadContainerConfig()
{ {
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject(); QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
@ -544,3 +549,18 @@ bool ServersModel::isDefaultServerFromApi()
return m_settings->server(m_defaultServerIndex).value(config_key::configVersion).toInt(); return m_settings->server(m_defaultServerIndex).value(config_key::configVersion).toInt();
} }
bool ServersModel::isCurrentlyProcessedServerFromApi()
{
return m_settings->server(m_currentlyProcessedServerIndex).value(config_key::configVersion).toInt();
}
bool ServersModel::isServerFromApiAlreadyExists(const quint16 crc)
{
for (const auto &server : qAsConst(m_servers)) {
if (static_cast<quint16>(server.toObject().value(config_key::crc).toInt()) == crc) {
return true;
}
}
return false;
}

View file

@ -78,6 +78,7 @@ public slots:
bool isAmneziaDnsContainerInstalled(const int serverIndex); bool isAmneziaDnsContainerInstalled(const int serverIndex);
QJsonObject getDefaultServerConfig(); QJsonObject getDefaultServerConfig();
QJsonObject getCurrentlyProcessedServerConfig();
void reloadContainerConfig(); void reloadContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config); void updateContainerConfig(const int containerIndex, const QJsonObject config);
@ -99,6 +100,9 @@ public slots:
void toggleAmneziaDns(bool enabled); void toggleAmneziaDns(bool enabled);
bool isDefaultServerFromApi(); bool isDefaultServerFromApi();
bool isCurrentlyProcessedServerFromApi();
bool isServerFromApiAlreadyExists(const quint16 crc);
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
@ -109,7 +113,7 @@ signals:
void defaultServerNameChanged(); void defaultServerNameChanged();
void defaultServerDescriptionChanged(); void defaultServerDescriptionChanged();
void containersUpdated(QJsonArray &containers); void containersUpdated(const QJsonArray &containers);
void defaultContainerChanged(const int containerIndex); void defaultContainerChanged(const int containerIndex);
private: private:

View file

@ -138,26 +138,8 @@ Button {
} }
onClicked: { onClicked: {
if (!ApiController.updateServerConfigFromApi()) { if (!ConnectionController.isConnectionInProgress) {
return ApiController.updateServerConfigFromApi()
}
if (!ContainersModel.isAnyContainerInstalled()) {
PageController.setTriggeredBtConnectButton(true)
ServersModel.currentlyProcessedIndex = ServersModel.getDefaultServerIndex()
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardEasy)
return
}
if (ConnectionController.isConnectionInProgress) {
ConnectionController.closeConnection()
} else if (ConnectionController.isConnected) {
ConnectionController.closeConnection()
} else {
ConnectionController.openConnection()
} }
} }
} }

View file

@ -401,6 +401,13 @@ PageType {
model: ServersModel model: ServersModel
currentIndex: ServersModel.defaultIndex currentIndex: ServersModel.defaultIndex
Connections {
target: ServersModel
function onDefaultServerIndexChanged(serverIndex) {
serversMenuContent.currentIndex = serverIndex
}
}
clip: true clip: true
interactive: false interactive: false
@ -429,19 +436,19 @@ PageType {
text: name text: name
descriptionText: { descriptionText: {
var description = "" var fullDescription = ""
if (hasWriteAccess) { if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled() if (SettingsController.isAmneziaDnsEnabled()
&& ServersModel.isAmneziaDnsContainerInstalled(index)) { && ServersModel.isAmneziaDnsContainerInstalled(index)) {
description += "Amnezia DNS | " fullDescription += "Amnezia DNS | "
} }
} else { } else {
if (containsAmneziaDns) { if (containsAmneziaDns) {
description += "Amnezia DNS | " fullDescription += "Amnezia DNS | "
} }
} }
return description += hostName return fullDescription += serverDescription
} }
checked: index === serversMenuContent.currentIndex checked: index === serversMenuContent.currentIndex

View file

@ -227,6 +227,68 @@ PageType {
visible: content.isServerWithWriteAccess visible: content.isServerWithWriteAccess
} }
LabelWithButtonType {
visible: content.isServerWithWriteAccess
Layout.fillWidth: true
text: qsTr("Clear server from Amnezia software")
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to clear server from Amnezia software?")
questionDrawer.descriptionText = qsTr("All containers will be deleted on the server. This means that configuration files, keys and certificates will be deleted.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.goToPage(PageEnum.PageDeinstalling)
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
ConnectionController.closeConnection()
}
InstallController.removeAllContainers()
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {
visible: content.isServerWithWriteAccess
}
LabelWithButtonType {
visible: ServersModel.isCurrentlyProcessedServerFromApi()
Layout.fillWidth: true
text: qsTr("Reset API config")
textColor: "#EB5757"
clickedFunction: function() {
questionDrawer.headerText = qsTr("Do you want to reset API config?")
questionDrawer.descriptionText = ""
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.visible = false
PageController.showBusyIndicator(true)
ApiController.clearApiConfig()
PageController.showBusyIndicator(false)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.visible = false
}
questionDrawer.visible = true
}
}
DividerType {
visible: ServersModel.isCurrentlyProcessedServerFromApi()
}
QuestionDrawer { QuestionDrawer {
id: questionDrawer id: questionDrawer
} }

View file

@ -18,8 +18,12 @@ PageType {
Connections { Connections {
target: ImportController target: ImportController
function onImportErrorOccurred(errorMessage) { function onImportErrorOccurred(errorMessage, goToPageHome) {
PageController.closePage() if (goToPageHome) {
PageController.goToStartPage()
} else {
PageController.closePage()
}
PageController.showErrorMessage(errorMessage) PageController.showErrorMessage(errorMessage)
} }

View file

@ -111,6 +111,22 @@ PageType {
PageController.showNotificationMessage(message) PageController.showNotificationMessage(message)
PageController.closePage() PageController.closePage()
} }
function onNoInstalledContainers() {
PageController.setTriggeredBtConnectButton(true)
ServersModel.currentlyProcessedIndex = ServersModel.getDefaultServerIndex()
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardEasy)
}
}
Connections {
target: ApiController
function onErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
}
} }
StackViewType { StackViewType {