From 0ab0f2f4ffb61fd28db52036a497f6d5f3cd186c Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Fri, 15 Sep 2023 09:54:45 +0200 Subject: [PATCH] feat(GODT-2772): setup wizard report knowledge base article opening event. --- .../bridge-gui-tester/GRPCService.cpp | 26 +++++++++++++++++++ .../bridge-gui-tester/GRPCService.h | 3 +++ .../bridge-gui/bridge-gui/QMLBackend.cpp | 15 ++++++++++- .../bridge-gui/bridge-gui/QMLBackend.h | 3 ++- .../bridge-gui/bridge-gui/qml/HelpView.qml | 3 +-- .../bridge-gui/bridge-gui/qml/MainWindow.qml | 2 +- .../qml/Notifications/Notifications.qml | 5 +--- .../SetupWizard/ClientConfigParameters.qml | 2 +- .../bridge-gui/qml/SetupWizard/HelpButton.qml | 3 +-- .../bridge-gui/qml/SetupWizard/LeftPane.qml | 6 ++--- 10 files changed, 53 insertions(+), 15 deletions(-) diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp index 89a15e4f..ac171993 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp @@ -802,6 +802,32 @@ Status GRPCService::InstallTLSCertificate(ServerContext *, Empty const *, Empty } +//**************************************************************************************************************************************************** +/// \param[in] request The request. +//**************************************************************************************************************************************************** +Status GRPCService::KBArticleClicked(::grpc::ServerContext *, ::google::protobuf::StringValue const *request, ::google::protobuf::Empty *) { + app().log().debug(QString("%1 - URL = %2").arg(__FUNCTION__, QString::fromStdString(request->value()))); + return Status::OK; +} + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +Status GRPCService::ReportBugClicked(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::Empty *) { + app().log().debug(__FUNCTION__); + return Status::OK; +} + + +//**************************************************************************************************************************************************** +/// \param[in] request The request. +//**************************************************************************************************************************************************** +Status GRPCService::AutoconfigClicked(::grpc::ServerContext *, ::google::protobuf::StringValue const *request, ::google::protobuf::Empty *response) { + app().log().debug(QString("%1 - Client = %2").arg(__FUNCTION__, QString::fromStdString(request->value()))); + return Status::OK; +} + + //**************************************************************************************************************************************************** /// \param[in] request The request /// \param[in] writer The writer diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h index 224108c5..fe7ec6ab 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h @@ -96,6 +96,9 @@ public: // member functions. grpc::Status IsTLSCertificateInstalled(::grpc::ServerContext *, ::google::protobuf::Empty const*, ::google::protobuf::BoolValue *response) override; grpc::Status InstallTLSCertificate(::grpc::ServerContext *, ::google::protobuf::Empty const*, ::google::protobuf::Empty *) override; grpc::Status ExportTLSCertificates(::grpc::ServerContext *, ::google::protobuf::StringValue const *request, ::google::protobuf::Empty *) override; + grpc::Status ReportBugClicked(::grpc::ServerContext *context, ::google::protobuf::Empty const *request, ::google::protobuf::Empty *) override; + grpc::Status AutoconfigClicked(::grpc::ServerContext *context, ::google::protobuf::StringValue const *request, ::google::protobuf::Empty *) override; + grpc::Status KBArticleClicked(::grpc::ServerContext *, ::google::protobuf::StringValue const *request, ::google::protobuf::Empty *) override; grpc::Status RunEventStream(::grpc::ServerContext *ctx, ::grpc::EventStreamRequest const *request, ::grpc::ServerWriter<::grpc::StreamEvent> *writer) override; grpc::Status StopEventStream(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::Empty *) override; bool sendEvent(bridgepp::SPStreamEvent const &event); ///< Queue an event for sending through the event stream. diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp index 3bdd3012..d7b60760 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp @@ -40,7 +40,8 @@ using namespace bridgepp; namespace { - QString const bugReportFile = ":qml/Resources/bug_report_flow.json"; +QString const bugReportFile = ":qml/Resources/bug_report_flow.json"; +QString const bridgeKBUrl = "https://proton.me/support/bridge"; ///< The URL for the root of the bridge knowledge base. } @@ -290,6 +291,18 @@ bool QMLBackend::isTLSCertificateInstalled() { } +//**************************************************************************************************************************************************** +/// \param[in] url The URL of the knowledge base article. If empty/invalid, the home page for the Bridge knowledge base is opened. +//**************************************************************************************************************************************************** +void QMLBackend::openKBArticle(QString const &url) { + HANDLE_EXCEPTION( + QString const u = url.isEmpty() ? bridgeKBUrl : url; + QDesktopServices::openUrl(u); + emit notifyKBArticleClicked(u); + ) +} + + //**************************************************************************************************************************************************** /// \return The value for the 'showOnStartup' property. //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h index f19f3113..775d3e7e 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h @@ -65,6 +65,7 @@ public: // member functions. Q_INVOKABLE QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions. Q_INVOKABLE void clearAnswers(); ///< Clear all collected answers. Q_INVOKABLE bool isTLSCertificateInstalled(); ///< Check if the bridge certificate is installed in the OS keychain. + Q_INVOKABLE void openKBArticle(QString const & url = QString()); ///< Open a knowledge base article. public: // Qt/QML properties. Note that the NOTIFY-er signal is required even for read-only properties (QML warning otherwise) Q_PROPERTY(bool showOnStartup READ showOnStartup NOTIFY showOnStartupChanged) @@ -276,7 +277,7 @@ signals: // Signals received from the Go backend, to be forwarded to QML void showMainWindow(); ///< Signal for the 'showMainWindow' gRPC stream event. void hideMainWindow(); ///< Signal for the 'hideMainWindow' gRPC stream event. void showHelp(); ///< Signal for the 'showHelp' event (from the context menu). - void showSettings(); ///< Signal for the 'showHelp' event (from the context menu). + void showSettings(); ///< Signal for the 'showSettings' event (from the context menu). void selectUser(QString const& userID, bool forceShowWindow); ///< Signal emitted in order to selected a user with a given ID in the list. void genericError(QString const &title, QString const &description); ///< Signal for the 'genericError' gRPC stream event. void imapLoginWhileSignedOut(QString const& username); ///< Signal for the notification of IMAP login attempt on a signed out account. diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml index e12516f6..3f2199b1 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml @@ -36,8 +36,7 @@ SettingsView { type: SettingsItem.PrimaryButton onClicked: { - Backend.notifyKBArticleClicked("https://proton.me/support/bridge"); - Backend.showHelp() + Backend.openKBArticle(); } } SettingsItem { diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml index 7d012e84..dcb9b5b7 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml @@ -55,7 +55,7 @@ ApplicationWindow { setupWizard.showClientConfig(user, address, justLoggedIn); } function showHelp() { - Qt.openUrlExternally("https://proton.me/support/bridge"); + contentWrapper.showHelp(); } function showLocalCacheSettings() { contentWrapper.showLocalCacheSettings(); diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml index 04b2398d..4aacc22a 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml @@ -788,8 +788,6 @@ QtObject { } } property Notification rebuildKeychain: Notification { - property var supportLink: "https://proton.me/support/bridge" - brief: title description: qsTr("Bridge is not able to access your macOS keychain. Please consult the instructions on our support page.") group: Notifications.Group.Dialogs | Notifications.Group.Configuration @@ -802,8 +800,7 @@ QtObject { text: qsTr("Open the support page") onTriggered: { - Backend.notifyKBArticleClicked(root.rebuildKeychain.supportLink); - Qt.openUrlExternally(root.rebuildKeychain.supportLink); + Backend.openKBArticle(); Backend.quit(); } } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/ClientConfigParameters.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/ClientConfigParameters.qml index eed7ff89..924c4f1a 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/ClientConfigParameters.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/ClientConfigParameters.qml @@ -79,7 +79,7 @@ Rectangle { text: qsTr("Open guide") onClicked: function () { - Qt.openUrlExternally(wizard.setupGuideLink()); + Backend.openKBArticle(wizard.setupGuideLink()); } } } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/HelpButton.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/HelpButton.qml index 7dcf4e80..8040793b 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/HelpButton.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/HelpButton.qml @@ -49,8 +49,7 @@ Button { text: qsTr("Get help") onClicked: { - Backend.notifyKBArticleClicked("https://proton.me/support/bridge"); - Backend.showHelp(); + Backend.openKBArticle(); } } MenuItem { diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml index 054f66f6..20c7e0ff 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/LeftPane.qml @@ -26,7 +26,7 @@ Item { function showAppleMailAutoconfigCertificateInstall() { showAppleMailAutoconfigCommon(); descriptionLabel.text = qsTr("Apple Mail configuration is mostly automated, but in order to work, Bridge needs to install a certificate in your keychain."); - linkLabel1.setLink("https://proton.me/support/bridge", qsTr("Why is this certificate needed?"), true); ///< TODO GODT-2772: replace link with link to KB article. + linkLabel1.setCallback(function() { Backend.openKBArticle(); }, qsTr("Why is this certificate needed?"), true); ///< TODO GODT-2772: replace link with link to KB article. linkLabel2.clear(); } function showAppleMailAutoconfigCommon() { @@ -40,7 +40,7 @@ Item { function showAppleMailAutoconfigProfileInstall() { showAppleMailAutoconfigCommon(); descriptionLabel.text = qsTr("The final step before you can start using Apple Mail is to install the Bridge server profile in the system preferences.\n\nAdding a server profile is necessary to ensure that your Mac can receive and send Proton Mails."); - linkLabel1.setLink("https://proton.me/support/bridge", qsTr("Why is there a yellow warning sign?"), true); ///< TODO GODT-2772: replace link with link to KB article. + linkLabel1.setCallback(function() { Backend.openKBArticle(); }, qsTr("Why is there a yellow warning sign?"), true); ///< TODO GODT-2772: replace link with link to KB article. linkLabel2.setCallback(wizard.showClientParams, qsTr("Configure Apple Mail manually"), false); } function showClientSelector(newAccount = true) { @@ -64,7 +64,7 @@ Item { function showOnboarding() { titleLabel.text = (Backend.users.count === 0) ? qsTr("Welcome to\nProton Mail Bridge") : qsTr("Add a Proton Mail account"); descriptionLabel.text = qsTr("Bridge is the gateway between your Proton account and your email client. It runs in the background and encrypts and decrypts your messages seamlessly. "); - linkLabel1.setLink("https://proton.me/support/bridge", qsTr("Why do I need Bridge?"), true); ///< TODO GODT-2772: replace link with link to KB article. + linkLabel1.setCallback(function() { Backend.openKBArticle(); }, qsTr("Why do I need Bridge?"), true); ///< TODO GODT-2772: replace link with link to KB article. linkLabel2.clear(); root.iconSource = "/qml/icons/img-welcome.svg"; root.iconHeight = 148;