Merge pull request #7011 from Ultimaker/CURA-7090-addition

CURA-7090/Added check to reevaluate dismissed incompatible packages
This commit is contained in:
ninovanhooff 2020-01-27 14:33:13 +01:00 committed by GitHub
commit 3a0bd48e1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 90 deletions

View File

@ -20,6 +20,8 @@ UM.Dialog{
maximumHeight: minimumHeight maximumHeight: minimumHeight
margin: 0 margin: 0
property string actionButtonText: subscribedPackagesModel.hasIncompatiblePackages && !subscribedPackagesModel.hasCompatiblePackages ? catalog.i18nc("@button", "Dismiss") : catalog.i18nc("@button", "Next")
Rectangle Rectangle
{ {
id: root id: root
@ -125,26 +127,6 @@ UM.Dialog{
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
elide: Text.ElideRight elide: Text.ElideRight
} }
UM.TooltipArea
{
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip", "Dismisses the package and won't be shown in this dialog anymore")
anchors.right: parent.right
anchors.verticalCenter: packageIcon.verticalCenter
Label
{
text: "(Dismiss)"
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text")
MouseArea
{
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: handler.dismissIncompatiblePackage(subscribedPackagesModel, model.package_id)
}
}
}
} }
} }
} }
@ -158,7 +140,7 @@ UM.Dialog{
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.margins: UM.Theme.getSize("default_margin").height anchors.margins: UM.Theme.getSize("default_margin").height
text: catalog.i18nc("@button", "Next") text: actionButtonText
onClicked: accept() onClicked: accept()
leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width leftPadding: UM.Theme.getSize("dialog_primary_button_padding").width
rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width rightPadding: UM.Theme.getSize("dialog_primary_button_padding").width

View File

@ -8,11 +8,12 @@ from UM import i18nCatalog
from UM.Logger import Logger from UM.Logger import Logger
from UM.Message import Message from UM.Message import Message
from UM.Signal import Signal from UM.Signal import Signal
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication, ApplicationMetadata
from ..CloudApiModel import CloudApiModel from ..CloudApiModel import CloudApiModel
from .SubscribedPackagesModel import SubscribedPackagesModel from .SubscribedPackagesModel import SubscribedPackagesModel
from ..UltimakerCloudScope import UltimakerCloudScope from ..UltimakerCloudScope import UltimakerCloudScope
from typing import List, Dict, Any
class CloudPackageChecker(QObject): class CloudPackageChecker(QObject):
def __init__(self, application: CuraApplication) -> None: def __init__(self, application: CuraApplication) -> None:
@ -25,12 +26,12 @@ class CloudPackageChecker(QObject):
self._application.initializationFinished.connect(self._onAppInitialized) self._application.initializationFinished.connect(self._onAppInitialized)
self._i18n_catalog = i18nCatalog("cura") self._i18n_catalog = i18nCatalog("cura")
self._sdk_version = ApplicationMetadata.CuraSDKVersion
# This is a plugin, so most of the components required are not ready when # This is a plugin, so most of the components required are not ready when
# this is initialized. Therefore, we wait until the application is ready. # this is initialized. Therefore, we wait until the application is ready.
def _onAppInitialized(self) -> None: def _onAppInitialized(self) -> None:
self._package_manager = self._application.getPackageManager() self._package_manager = self._application.getPackageManager()
# initial check # initial check
self._fetchUserSubscribedPackages() self._fetchUserSubscribedPackages()
# check again whenever the login state changes # check again whenever the login state changes
@ -38,25 +39,51 @@ class CloudPackageChecker(QObject):
def _fetchUserSubscribedPackages(self) -> None: def _fetchUserSubscribedPackages(self) -> None:
if self._application.getCuraAPI().account.isLoggedIn: if self._application.getCuraAPI().account.isLoggedIn:
self._getUserPackages() self._getUserSubscribedPackages()
def _handleCompatibilityData(self, json_data) -> None: def _getUserSubscribedPackages(self) -> None:
user_subscribed_packages = [plugin["package_id"] for plugin in json_data] Logger.debug("Requesting subscribed packages metadata from server.")
url = CloudApiModel.api_url_user_packages
self._application.getHttpRequestManager().get(url,
callback = self._onUserPackagesRequestFinished,
error_callback = self._onUserPackagesRequestFinished,
scope = self._scope)
def _onUserPackagesRequestFinished(self, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"] = None) -> None:
if error is not None or reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("w",
"Requesting user packages failed, response code %s while trying to connect to %s",
reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url())
return
try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
# Check for errors:
if "errors" in json_data:
for error in json_data["errors"]:
Logger.log("e", "%s", error["title"])
return
self._handleCompatibilityData(json_data["data"])
except json.decoder.JSONDecodeError:
Logger.log("w", "Received invalid JSON for user subscribed packages from the Web Marketplace")
def _handleCompatibilityData(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
user_subscribed_packages = [plugin["package_id"] for plugin in subscribed_packages_payload]
user_installed_packages = self._package_manager.getUserInstalledPackages() user_installed_packages = self._package_manager.getUserInstalledPackages()
# We need to re-evaluate the dismissed packages
# (i.e. some package might got updated to the correct SDK version in the meantime,
# hence remove them from the Dismissed Incompatible list)
self._package_manager.reEvaluateDismissedPackages(subscribed_packages_payload, self._sdk_version)
user_dismissed_packages = self._package_manager.getDismissedPackages() user_dismissed_packages = self._package_manager.getDismissedPackages()
if user_dismissed_packages: if user_dismissed_packages:
user_installed_packages += user_dismissed_packages user_installed_packages += user_dismissed_packages
# We check if there are packages installed in Cloud Marketplace but not in Cura marketplace
# We check if there are packages installed in Web Marketplace but not in Cura marketplace
package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages)) package_discrepancy = list(set(user_subscribed_packages).difference(user_installed_packages))
self._model.setMetadata(json_data)
self._model.addDiscrepancies(package_discrepancy)
self._model.initialize()
if not self._model.hasCompatiblePackages:
return None
if package_discrepancy: if package_discrepancy:
self._model.addDiscrepancies(package_discrepancy)
self._model.initialize(subscribed_packages_payload)
self._handlePackageDiscrepancies() self._handlePackageDiscrepancies()
def _handlePackageDiscrepancies(self) -> None: def _handlePackageDiscrepancies(self) -> None:
@ -77,34 +104,3 @@ class CloudPackageChecker(QObject):
def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None: def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None:
sync_message.hide() sync_message.hide()
self.discrepancies.emit(self._model) self.discrepancies.emit(self._model)
def _getUserPackages(self) -> None:
Logger.log("d", "Requesting subscribed packages metadata from server.")
url = CloudApiModel.api_url_user_packages
self._application.getHttpRequestManager().get(url,
callback = self._onUserPackagesRequestFinished,
error_callback = self._onUserPackagesRequestFinished,
scope = self._scope)
def _onUserPackagesRequestFinished(self,
reply: "QNetworkReply",
error: Optional["QNetworkReply.NetworkError"] = None) -> None:
if error is not None or reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
Logger.log("w",
"Requesting user packages failed, response code %s while trying to connect to %s",
reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url())
return
try:
json_data = json.loads(bytes(reply.readAll()).decode("utf-8"))
# Check for errors:
if "errors" in json_data:
for error in json_data["errors"]:
Logger.log("e", "%s", error["title"])
return
self._handleCompatibilityData(json_data["data"])
except json.decoder.JSONDecodeError:
Logger.log("w", "Received invalid JSON for user packages")

View File

@ -28,13 +28,12 @@ class DiscrepanciesPresenter(QObject):
assert self._dialog assert self._dialog
self._dialog.accepted.connect(lambda: self._onConfirmClicked(model)) self._dialog.accepted.connect(lambda: self._onConfirmClicked(model))
@pyqtSlot("QVariant", str)
def dismissIncompatiblePackage(self, model: SubscribedPackagesModel, package_id: str) -> None:
model.dismissPackage(package_id) # update the model to update the view
self._package_manager.dismissPackage(package_id) # adds this package_id as dismissed in the user config file
def _onConfirmClicked(self, model: SubscribedPackagesModel) -> None: def _onConfirmClicked(self, model: SubscribedPackagesModel) -> None:
# If there are incompatible packages - automatically dismiss them
if model.getIncompatiblePackages():
self._package_manager.dismissAllIncompatiblePackages(model.getIncompatiblePackages())
# For now, all compatible packages presented to the user should be installed. # For now, all compatible packages presented to the user should be installed.
# Later, we might remove items for which the user unselected the package # Later, we might remove items for which the user unselected the package
if model.getCompatiblePackages():
model.setItems(model.getCompatiblePackages()) model.setItems(model.getCompatiblePackages())
self.packageMutations.emit(model) self.packageMutations.emit(model)

View File

@ -37,27 +37,18 @@ class SubscribedPackagesModel(ListModel):
return True return True
return False return False
# Sets the "is_compatible" to True for the given package, in memory
@pyqtSlot()
def dismissPackage(self, package_id: str) -> None:
package = self.find(key="package_id", value=package_id)
if package != -1:
self.setProperty(package, property="is_dismissed", value=True)
Logger.debug("Package {} has been dismissed".format(package_id))
def setMetadata(self, data: List[Dict[str, List[Any]]]) -> None:
self._metadata = data
def addDiscrepancies(self, discrepancy: List[str]) -> None: def addDiscrepancies(self, discrepancy: List[str]) -> None:
self._discrepancies = discrepancy self._discrepancies = discrepancy
def getCompatiblePackages(self): def getCompatiblePackages(self) -> List[Dict[str, Any]]:
return [x for x in self._items if x["is_compatible"]] return [package for package in self._items if package["is_compatible"]]
def initialize(self) -> None: def getIncompatiblePackages(self) -> List[str]:
return [package["package_id"] for package in self._items if not package["is_compatible"]]
def initialize(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
self._items.clear() self._items.clear()
for item in self._metadata: for item in subscribed_packages_payload:
if item["package_id"] not in self._discrepancies: if item["package_id"] not in self._discrepancies:
continue continue
package = { package = {