mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-18 20:28:01 -06:00
Introduce the SyncOrchestrator
CURA-6983
This commit is contained in:
parent
6eab5e2492
commit
1a816ad010
8 changed files with 84 additions and 21 deletions
|
@ -2,7 +2,8 @@
|
|||
# Toolbox is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from .src import Toolbox
|
||||
from .src.SubscriptionChecker import SubscriptionChecker
|
||||
from plugins.Toolbox.src.CloudSync.CloudPackageChecker import CloudPackageChecker
|
||||
from .src.CloudSync.SyncOrchestrator import SyncOrchestrator
|
||||
|
||||
|
||||
def getMetaData():
|
||||
|
@ -11,6 +12,5 @@ def getMetaData():
|
|||
|
||||
def register(app):
|
||||
return {
|
||||
"extension": Toolbox.Toolbox(app),
|
||||
"subscription_checker": SubscriptionChecker(app)
|
||||
"extension": [Toolbox.Toolbox(app), SyncOrchestrator(app)]
|
||||
}
|
||||
|
|
|
@ -139,6 +139,7 @@ UM.Dialog{
|
|||
anchors.right: parent.right
|
||||
anchors.margins: UM.Theme.getSize("default_margin").height
|
||||
text: catalog.i18nc("@button", "Next")
|
||||
onClicked: accept()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
import json
|
||||
import os
|
||||
from typing import Dict, Optional
|
||||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import QObject
|
||||
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
|
||||
from UM.Extension import Extension
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Signal import Signal
|
||||
from UM.TaskManagement.HttpRequestScope import UltimakerCloudScope
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from plugins.Toolbox.src.CloudApiModel import CloudApiModel
|
||||
from plugins.Toolbox.src.SubscribedPackagesModel import SubscribedPackagesModel
|
||||
from plugins.Toolbox.src.CloudSync.SubscribedPackagesModel import SubscribedPackagesModel
|
||||
from plugins.Toolbox.src.Toolbox import i18n_catalog
|
||||
|
||||
|
||||
class SubscriptionChecker(QObject, Extension):
|
||||
class CloudPackageChecker(QObject):
|
||||
|
||||
def __init__(self, application: CuraApplication) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.discrepancies = Signal() # Emits SubscribedPackagesModel
|
||||
self._application = application # type: CuraApplication
|
||||
self._scope = UltimakerCloudScope(application)
|
||||
self._model = SubscribedPackagesModel()
|
||||
|
@ -39,7 +38,7 @@ class SubscriptionChecker(QObject, Extension):
|
|||
|
||||
def _fetchUserSubscribedPackages(self):
|
||||
if self._application.getCuraAPI().account.isLoggedIn:
|
||||
self._getUserPackages("subscribed_packages")
|
||||
self._getUserPackages()
|
||||
|
||||
def _handleCompatibilityData(self, json_data) -> None:
|
||||
user_subscribed_packages = [plugin["package_id"] for plugin in json_data]
|
||||
|
@ -53,9 +52,9 @@ class SubscriptionChecker(QObject, Extension):
|
|||
self._model.update()
|
||||
|
||||
if package_discrepancy:
|
||||
self._handlePackageDiscrepancies(package_discrepancy)
|
||||
self._handlePackageDiscrepancies()
|
||||
|
||||
def _handlePackageDiscrepancies(self, package_discrepancy):
|
||||
def _handlePackageDiscrepancies(self):
|
||||
Logger.log("d", "Discrepancy found between Cloud subscribed packages and Cura installed packages")
|
||||
sync_message = Message(i18n_catalog.i18nc(
|
||||
"@info:generic",
|
||||
|
@ -72,14 +71,10 @@ class SubscriptionChecker(QObject, Extension):
|
|||
|
||||
def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None:
|
||||
sync_message.hide()
|
||||
compatibility_dialog_path = "resources/qml/dialogs/CompatibilityDialog.qml"
|
||||
plugin_path_prefix = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
|
||||
if plugin_path_prefix:
|
||||
path = os.path.join(plugin_path_prefix, compatibility_dialog_path)
|
||||
self.compatibility_dialog_view = self._application.createQmlComponent(path, {"subscribedPackagesModel": self._model})
|
||||
self.discrepancies.emit(self._model)
|
||||
|
||||
def _getUserPackages(self, request_type: str) -> None:
|
||||
Logger.log("d", "Requesting [%s] metadata from server.", request_type)
|
||||
def _getUserPackages(self) -> None:
|
||||
Logger.log("d", "Requesting subscribed packages metadata from server.")
|
||||
url = CloudApiModel.api_url_user_packages
|
||||
|
||||
self._application.getHttpRequestManager().get(url,
|
33
plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py
Normal file
33
plugins/Toolbox/src/CloudSync/DiscrepanciesPresenter.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
import os
|
||||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import QObject
|
||||
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from UM.Signal import Signal
|
||||
from plugins.Toolbox.src.CloudSync.SubscribedPackagesModel import SubscribedPackagesModel
|
||||
|
||||
|
||||
## Shows a list of packages to be added or removed. The user can select which packages to (un)install. The user's
|
||||
# choices are emitted on the `packageMutations` Signal.
|
||||
class DiscrepanciesPresenter(QObject):
|
||||
|
||||
def __init__(self, app: QtApplication):
|
||||
super().__init__(app)
|
||||
|
||||
self.packageMutations = Signal() # {"SettingsGuide" : "install", "PrinterSettings" : "uninstall"}
|
||||
|
||||
self._app = app
|
||||
self._dialog = None # type: Optional[QObject]
|
||||
self._compatibility_dialog_path = "resources/qml/dialogs/CompatibilityDialog.qml"
|
||||
|
||||
def present(self, plugin_path: str, model: SubscribedPackagesModel):
|
||||
path = os.path.join(plugin_path, self._compatibility_dialog_path)
|
||||
self._dialog = self._app.createQmlComponent(path, {"subscribedPackagesModel": model})
|
||||
self._dialog.accepted.connect(lambda: self._onConfirmClicked(model))
|
||||
|
||||
def _onConfirmClicked(self, model: SubscribedPackagesModel):
|
||||
# For now, all packages presented to the user should be installed.
|
||||
# Later, we will support uninstall ?or ignoring? of a certain package
|
||||
choices = {item["package_id"]: "install" for item in model.items}
|
||||
self.packageMutations.emit(choices)
|
|
@ -33,7 +33,7 @@ class SubscribedPackagesModel(ListModel):
|
|||
for item in self._metadata:
|
||||
if item["package_id"] not in self._discrepancies:
|
||||
continue
|
||||
package = {"name": item["display_name"], "sdk_versions": item["sdk_versions"]}
|
||||
package = {"package_id": item["package_id"], "name": item["display_name"], "sdk_versions": item["sdk_versions"]}
|
||||
if self._sdk_version not in item["sdk_versions"]:
|
||||
package.update({"is_compatible": False})
|
||||
else:
|
34
plugins/Toolbox/src/CloudSync/SyncOrchestrator.py
Normal file
34
plugins/Toolbox/src/CloudSync/SyncOrchestrator.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
from UM.Extension import Extension
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from plugins.Toolbox import CloudPackageChecker
|
||||
from plugins.Toolbox.src.CloudSync.DiscrepanciesPresenter import DiscrepanciesPresenter
|
||||
from plugins.Toolbox.src.CloudSync.SubscribedPackagesModel import SubscribedPackagesModel
|
||||
|
||||
|
||||
## Orchestrates the synchronizing of packages from the user account to the installed packages
|
||||
# Example flow:
|
||||
# - CloudPackageChecker compares a list of packages the user `subscribed` to in their account
|
||||
# If there are `discrepancies` between the account and locally installed packages, they are emitted
|
||||
# - DiscrepanciesPresenter shows a list of packages to be added or removed to the user. It emits the `packageMutations`
|
||||
# the user selected to be performed
|
||||
# - The SyncOrchestrator uses PackageManager to remove local packages the users wants to see removed
|
||||
# - The DownloadPresenter shows a download progress dialog
|
||||
# - The LicencePresenter extracts licences from the downloaded packages and presents a licence for each package to
|
||||
# - be installed. It emits the `licenceAnswers` {'packageId' : bool} for accept or declines
|
||||
# - The CloudPackageManager removes the declined packages from the account
|
||||
# - The SyncOrchestrator uses PackageManager to install the downloaded packages.
|
||||
# - Bliss / profit / done
|
||||
class SyncOrchestrator(Extension):
|
||||
|
||||
def __init__(self, app: CuraApplication):
|
||||
super().__init__()
|
||||
|
||||
self._checker = CloudPackageChecker(app)
|
||||
self._checker.discrepancies.connect(self._onDiscrepancies)
|
||||
|
||||
self._discrepanciesPresenter = DiscrepanciesPresenter(app)
|
||||
|
||||
def _onDiscrepancies(self, model: SubscribedPackagesModel):
|
||||
plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
|
||||
self._discrepanciesPresenter.present(plugin_path, model)
|
0
plugins/Toolbox/src/CloudSync/__init__.py
Normal file
0
plugins/Toolbox/src/CloudSync/__init__.py
Normal file
|
@ -23,7 +23,7 @@ from plugins.Toolbox.src.CloudApiModel import CloudApiModel
|
|||
|
||||
from .AuthorsModel import AuthorsModel
|
||||
from .PackagesModel import PackagesModel
|
||||
from .SubscribedPackagesModel import SubscribedPackagesModel
|
||||
from .CloudSync.SubscribedPackagesModel import SubscribedPackagesModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.TaskManagement.HttpRequestData import HttpRequestData
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue