From 9d8286d90c79ca891986e44d886dc3666fa9ed79 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Tue, 13 Jul 2021 16:52:36 +0200 Subject: [PATCH 01/16] Set the correct initial value in the feature budget attributes They were defined as `Optional[int]` but started with the default value as `False`. CURA-8112 --- .../src/DigitalFactoryFeatureBudgetResponse.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryFeatureBudgetResponse.py b/plugins/DigitalLibrary/src/DigitalFactoryFeatureBudgetResponse.py index 016306a478..192f58685a 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryFeatureBudgetResponse.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryFeatureBudgetResponse.py @@ -16,9 +16,9 @@ class DigitalFactoryFeatureBudgetResponse(BaseModel): library_can_use_status: Optional[bool] = False, library_can_use_tags: Optional[bool] = False, library_can_use_technical_requirements: Optional[bool] = False, - library_max_organization_shared_projects: Optional[int] = False, # -1 means unlimited - library_max_private_projects: Optional[int] = False, # -1 means unlimited - library_max_team_shared_projects: Optional[int] = False, # -1 means unlimited + library_max_organization_shared_projects: Optional[int] = None, # -1 means unlimited + library_max_private_projects: Optional[int] = None, # -1 means unlimited + library_max_team_shared_projects: Optional[int] = None, # -1 means unlimited **kwargs) -> None: self.library_can_use_business_value = library_can_use_business_value From 9ddb3b7713c48856acd8a6748202099123dbd6d0 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Tue, 13 Jul 2021 16:53:02 +0200 Subject: [PATCH 02/16] Fix icon being ignored in message action buttons CURA-8112 --- resources/qml/Cura.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 191ae712d4..80b8880aae 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -417,6 +417,7 @@ UM.MainWindow Cura.PrimaryButton { text: model.name + iconSource: UM.Theme.getIcon(model.icon) height: UM.Theme.getSize("message_action_button").height } } @@ -426,6 +427,7 @@ UM.MainWindow Cura.SecondaryButton { text: model.name + iconSource: UM.Theme.getIcon(model.icon) height: UM.Theme.getSize("message_action_button").height } } @@ -434,6 +436,11 @@ UM.MainWindow Cura.TertiaryButton { text: model.name + iconSource: { + if (model.icon == null || model.icon == "") + return UM.Theme.getIcon("LinkExternal") + return UM.Theme.getIcon(model.icon) + } height: UM.Theme.getSize("message_action_button").height } } From 2d45b8c2cd7ca7e72b44b16c7543299e1688b4b5 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Tue, 13 Jul 2021 17:28:38 +0200 Subject: [PATCH 03/16] Show an "Upgrade plan" button to users that have reached maximum projects Instead of letting users go through the project creation process only to get rejected with a "subscription limits reached" message, now the "New Library project" button is being replaced with an "Upgrade plan" button when the maximum allowed projects have been reached for the specific amount. The button is accompanied by a tooltip that explains the situation to the user. Once clicked, the user is redirected to the subscriptions page. CURA-8112 --- .../resources/qml/SelectProjectPage.qml | 17 +++++++++++++- .../src/DigitalFactoryApiClient.py | 23 +++++++++++++++++++ .../src/DigitalFactoryController.py | 18 +++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 2de0e78cc7..0f8544285f 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -18,7 +18,7 @@ Item width: parent.width height: parent.height - property alias createNewProjectButtonVisible: createNewProjectButton.visible + property bool createNewProjectButtonVisible: true anchors { @@ -48,6 +48,7 @@ Item anchors.verticalCenter: selectProjectLabel.verticalCenter anchors.right: parent.right text: "New Library project" + visible: createNewProjectButtonVisible && manager.userAccountCanCreateNewLibraryProject && (manager.retrievingProjectsStatus == DF.RetrievalStatus.Success || manager.retrievingProjectsStatus == DF.RetrievalStatus.Failed) onClicked: { @@ -56,6 +57,20 @@ Item busy: manager.creatingNewProjectStatus == DF.RetrievalStatus.InProgress } + + Cura.SecondaryButton + { + id: upgradePlanButton + + anchors.verticalCenter: selectProjectLabel.verticalCenter + anchors.right: parent.right + text: "Upgrade plan" + visible: createNewProjectButtonVisible && !manager.userAccountCanCreateNewLibraryProject && (manager.retrievingProjectsStatus == DF.RetrievalStatus.Success || manager.retrievingProjectsStatus == DF.RetrievalStatus.Failed) + tooltip: "You have reached the maximum number of projects allowed by your subscription. Please upgrade to the Professional subscription to create more projects." + + onClicked: Qt.openUrlExternally("https://ultimaker.com/software/enterprise-software") + } + Item { id: noLibraryProjectsContainer diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index e1a62fdd5c..acb7b9a5a5 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -55,6 +55,7 @@ class DigitalFactoryApiClient: self._http = HttpRequestManager.getInstance() self._on_error = on_error self._file_uploader = None # type: Optional[DFFileUploader] + self._library_max_private_projects: Optional[int] = None self._projects_pagination_mgr = PaginationManager(limit = projects_limit_per_page) if projects_limit_per_page else None # type: Optional[PaginationManager] @@ -69,6 +70,7 @@ class DigitalFactoryApiClient: callback( response.library_max_private_projects == -1 or # Note: -1 is unlimited response.library_max_private_projects > 0) + self._library_max_private_projects = response.library_max_private_projects else: Logger.warning(f"Digital Factory: Response is not a feature budget, likely an error: {str(response)}") callback(False) @@ -79,6 +81,27 @@ class DigitalFactoryApiClient: error_callback = callbackWrap, timeout = self.DEFAULT_REQUEST_TIMEOUT) + def checkUserCanCreateNewLibraryProject(self, callback: Callable) -> None: + """ + Checks if the user is allowed to create new library projects. + A user is allowed to create new library projects if the haven't reached their maximum allowed private projects. + """ + + def callbackWrap(response: Optional[Any] = None, *args, **kwargs) -> None: + if response is not None: + if self._library_max_private_projects == -1 or isinstance(response, DigitalFactoryProjectResponse): + callback(True) + elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response): + callback(len(response) < self._library_max_private_projects) + else: + Logger.warning(f"Digital Factory: Incorrect response type received when requesting private projects: {str(response)}") + callback(False) + else: + Logger.warning(f"Digital Factory: Response is empty, likely an error: {str(response)}") + callback(False) + + self.getProjectsFirstPage(on_finished = callbackWrap, failed = callbackWrap) + def getProject(self, library_project_id: str, on_finished: Callable[[DigitalFactoryProjectResponse], Any], failed: Callable) -> None: """ Retrieves a digital factory project by its library project id. diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 368b29219a..cf4174d7c9 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -92,6 +92,9 @@ class DigitalFactoryController(QObject): """Signal to inform about the state of user access.""" userAccessStateChanged = pyqtSignal(bool) + """Signal to inform whether the user is allowed to create more Library projects.""" + userCanCreateNewLibraryProjectChanged = pyqtSignal(bool) + def __init__(self, application: CuraApplication) -> None: super().__init__(parent = None) @@ -136,6 +139,7 @@ class DigitalFactoryController(QObject): self._application.initializationFinished.connect(self._applicationInitializationFinished) self._user_has_access = False + self._user_account_can_create_new_project = False def clear(self) -> None: self._project_model.clearProjects() @@ -166,6 +170,11 @@ class DigitalFactoryController(QObject): subscriptions = self._account.userProfile.get("subscriptions", []) if len(subscriptions) > 0: return True + if self._user_has_access: + # The user has access even though they have no subscriptions. This means they are an Essential user and they + # have limited personal private projects available. In this case, we need to check whether they have already + # reached their limit. + self._api.checkUserCanCreateNewLibraryProject(callback = self.setCanCreateNewLibraryProject) return self._user_has_access def initialize(self, preselected_project_id: Optional[str] = None) -> None: @@ -517,6 +526,7 @@ class DigitalFactoryController(QObject): self._project_model.clearProjects() self.setSelectedProjectIndex(-1) self._api.getProjectsFirstPage(on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) + self._api.checkUserCanCreateNewLibraryProject(callback = self.setCanCreateNewLibraryProject) self.setRetrievingProjectsStatus(RetrievalStatus.InProgress) self._has_preselected_project = new_has_preselected_project self.preselectedProjectChanged.emit() @@ -525,6 +535,14 @@ class DigitalFactoryController(QObject): def hasPreselectedProject(self) -> bool: return self._has_preselected_project + def setCanCreateNewLibraryProject(self, can_create_new_library_project: bool) -> None: + self._user_account_can_create_new_project = can_create_new_library_project + self.userCanCreateNewLibraryProjectChanged.emit(self._user_account_can_create_new_project) + + @pyqtProperty(bool, fset = setCanCreateNewLibraryProject, notify = userCanCreateNewLibraryProjectChanged) + def userAccountCanCreateNewLibraryProject(self) -> bool: + return self._user_account_can_create_new_project + @pyqtSlot(str, "QStringList") def saveFileToSelectedProject(self, filename: str, formats: List[str]) -> None: """ From f643f19af63c649bd94d292cc627eb6ec177c479 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Tue, 13 Jul 2021 17:30:30 +0200 Subject: [PATCH 04/16] Fix tooltip not shown when the tooltip text is too long When the tooltip text is too long and the tooltip width ends up being longer than the window it is supposed to be drawn into, the tooltip is not drawn at all. This commit fixed that by allowing the tooltip width of the ActionButton to be changed within QML, limiting it to a certain size that fits the purpose. CURA-8112 --- plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml | 1 + resources/qml/ActionButton.qml | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 0f8544285f..b638082853 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -67,6 +67,7 @@ Item text: "Upgrade plan" visible: createNewProjectButtonVisible && !manager.userAccountCanCreateNewLibraryProject && (manager.retrievingProjectsStatus == DF.RetrievalStatus.Success || manager.retrievingProjectsStatus == DF.RetrievalStatus.Failed) tooltip: "You have reached the maximum number of projects allowed by your subscription. Please upgrade to the Professional subscription to create more projects." + tooltipWidth: parent.width * 3 / 4 onClicked: Qt.openUrlExternally("https://ultimaker.com/software/enterprise-software") } diff --git a/resources/qml/ActionButton.qml b/resources/qml/ActionButton.qml index 31d5c35d2c..582df3d87c 100644 --- a/resources/qml/ActionButton.qml +++ b/resources/qml/ActionButton.qml @@ -18,6 +18,7 @@ Button property alias textFont: buttonText.font property alias cornerRadius: backgroundRect.radius property alias tooltip: tooltip.tooltipText + property alias tooltipWidth: tooltip.width property color color: UM.Theme.getColor("primary") property color hoverColor: UM.Theme.getColor("primary_hover") From 2961d20c04ff5262d29dd69d65b6e0ccb78c57af Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Tue, 13 Jul 2021 17:38:15 +0200 Subject: [PATCH 05/16] Fix mypy complaint CURA-8112 --- plugins/DigitalLibrary/src/DigitalFactoryApiClient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index acb7b9a5a5..c0c6099b0d 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -91,7 +91,7 @@ class DigitalFactoryApiClient: if response is not None: if self._library_max_private_projects == -1 or isinstance(response, DigitalFactoryProjectResponse): callback(True) - elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response): + elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response) and self._library_max_private_projects is not None: callback(len(response) < self._library_max_private_projects) else: Logger.warning(f"Digital Factory: Incorrect response type received when requesting private projects: {str(response)}") From 11f66b2a78bc6d29ac8f47b4ef9659b065854357 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 12:54:31 +0200 Subject: [PATCH 06/16] Add brackets CURA-8112 --- resources/qml/Cura.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 80b8880aae..e91dd39091 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -438,7 +438,9 @@ UM.MainWindow text: model.name iconSource: { if (model.icon == null || model.icon == "") + { return UM.Theme.getIcon("LinkExternal") + } return UM.Theme.getIcon(model.icon) } height: UM.Theme.getSize("message_action_button").height From 3dbbe7276baa3b201698e19bfbacbef45a3d8464 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 12:55:28 +0200 Subject: [PATCH 07/16] Remove check for account subscriptions Since the variable `self._user_has_access` already contains the information on whether the user can access the Digital Library. CURA-8112 --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index cf4174d7c9..5caaca2e25 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -166,14 +166,7 @@ class DigitalFactoryController(QObject): :return: True if the user account has Digital Library access, else False """ - if self._account.userProfile: - subscriptions = self._account.userProfile.get("subscriptions", []) - if len(subscriptions) > 0: - return True if self._user_has_access: - # The user has access even though they have no subscriptions. This means they are an Essential user and they - # have limited personal private projects available. In this case, we need to check whether they have already - # reached their limit. self._api.checkUserCanCreateNewLibraryProject(callback = self.setCanCreateNewLibraryProject) return self._user_has_access From 300176cdc69d728fc27a01a35356a2d37eb51186 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 13:03:03 +0200 Subject: [PATCH 08/16] Check for the maximum **private** projects When checking whether the user is allowed to create a new library project, we need to retrieve the **private** (aka non-shared) projects that are linked to the user's account. If the user has reached the maximum private projects, then they are no longer allowed to create new ones. **Note**: We need to set the `pagination_manager` to `None` when doing this get request, or else the next/previous links of the pagination will become mixed up with the pagination links of the list of projects shown to the user, corrupting them and creating the wrong "get more projects" link. CURA-8112 --- .../src/DigitalFactoryApiClient.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index c0c6099b0d..91f1daf2f7 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -89,9 +89,9 @@ class DigitalFactoryApiClient: def callbackWrap(response: Optional[Any] = None, *args, **kwargs) -> None: if response is not None: - if self._library_max_private_projects == -1 or isinstance(response, DigitalFactoryProjectResponse): + if isinstance(response, DigitalFactoryProjectResponse): # The user has only one private project callback(True) - elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response) and self._library_max_private_projects is not None: + elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response): callback(len(response) < self._library_max_private_projects) else: Logger.warning(f"Digital Factory: Incorrect response type received when requesting private projects: {str(response)}") @@ -100,7 +100,21 @@ class DigitalFactoryApiClient: Logger.warning(f"Digital Factory: Response is empty, likely an error: {str(response)}") callback(False) - self.getProjectsFirstPage(on_finished = callbackWrap, failed = callbackWrap) + if self._library_max_private_projects is not None and self._library_max_private_projects > 0: + # The user has a limit in the number of private projects they can create. Check whether they have already + # reached that limit. + # Note: Set the pagination manager to None when doing this get request, or else the next/previous links + # of the pagination will become corrupted + url = f"{self.CURA_API_ROOT}/projects?shared=false&limit={self._library_max_private_projects}" + self._http.get(url, + scope = self._scope, + callback = self._parseCallback(callbackWrap, DigitalFactoryProjectResponse, callbackWrap, pagination_manager = None), + error_callback = callbackWrap, + timeout = self.DEFAULT_REQUEST_TIMEOUT) + else: + # If the limit is -1, then the user is allowed unlimited projects. If its 0 then they are not allowed to + # create any projects + callback(self._library_max_private_projects == -1) def getProject(self, library_project_id: str, on_finished: Callable[[DigitalFactoryProjectResponse], Any], failed: Callable) -> None: """ From 7027a8f904311251f0d20e1a02061d226986f72a Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 13:08:51 +0200 Subject: [PATCH 09/16] Fix mypy complaint again Mypy doesn't recognize that the check for `None` has happened before calling the `callbackWrap` (before the get request has been made). CURA-8112 --- plugins/DigitalLibrary/src/DigitalFactoryApiClient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index 91f1daf2f7..460438e365 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -92,7 +92,7 @@ class DigitalFactoryApiClient: if isinstance(response, DigitalFactoryProjectResponse): # The user has only one private project callback(True) elif isinstance(response, list) and all(isinstance(r, DigitalFactoryProjectResponse) for r in response): - callback(len(response) < self._library_max_private_projects) + callback(len(response) < cast(int, self._library_max_private_projects)) else: Logger.warning(f"Digital Factory: Incorrect response type received when requesting private projects: {str(response)}") callback(False) From 016371d77160eb07b9187fd65157ded2b535caac Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 14:34:00 +0200 Subject: [PATCH 10/16] Add the external link icon to the Upgrade plan button CURA-8112 --- plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index b638082853..a4eefd13f6 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -65,9 +65,10 @@ Item anchors.verticalCenter: selectProjectLabel.verticalCenter anchors.right: parent.right text: "Upgrade plan" + iconSource: UM.Theme.getIcon("LinkExternal") visible: createNewProjectButtonVisible && !manager.userAccountCanCreateNewLibraryProject && (manager.retrievingProjectsStatus == DF.RetrievalStatus.Success || manager.retrievingProjectsStatus == DF.RetrievalStatus.Failed) tooltip: "You have reached the maximum number of projects allowed by your subscription. Please upgrade to the Professional subscription to create more projects." - tooltipWidth: parent.width * 3 / 4 + tooltipWidth: parent.width * 0.5 onClicked: Qt.openUrlExternally("https://ultimaker.com/software/enterprise-software") } From 26a17e06038e94536efb1929e8c174f714ec0e66 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Thu, 15 Jul 2021 10:02:57 +0200 Subject: [PATCH 11/16] Code-style improvement CURA-8112 Co-authored-by: Ghostkeeper --- resources/qml/Cura.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index e91dd39091..7782ace3af 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -436,7 +436,8 @@ UM.MainWindow Cura.TertiaryButton { text: model.name - iconSource: { + iconSource: + { if (model.icon == null || model.icon == "") { return UM.Theme.getIcon("LinkExternal") From 82c189327d9deae7fd7f0320ae76dc6ce668476a Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Thu, 15 Jul 2021 16:36:49 +0200 Subject: [PATCH 12/16] Change link of "Upgrade plan" button CURA-8112 --- plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 98b0c5ca02..2b0ca664cc 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -81,7 +81,7 @@ Item tooltip: "You have reached the maximum number of projects allowed by your subscription. Please upgrade to the Professional subscription to create more projects." tooltipWidth: parent.width * 0.5 - onClicked: Qt.openUrlExternally("https://ultimaker.com/software/enterprise-software") + onClicked: Qt.openUrlExternally("https://ultimaker.com/software/ultimaker-essentials/sign-up-cura?utm_source=cura&utm_medium=software&utm_campaign=lib-max") } } From 65a2cd30fe0ee6116efba818f467e1a2551c2ace Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Jul 2021 09:48:40 +0200 Subject: [PATCH 13/16] Corrections to the paths to log files These have been wrong for years, I reckon... --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ff39e4142a..345a55d12f 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ For crashes and similar issues, please attach the following information: * (On Windows) The log as produced by dxdiag (start -> run -> dxdiag -> save output) * The Cura GUI log file, located at - * `%APPDATA%\cura\\cura.log` (Windows), or usually `C:\Users\\\AppData\Roaming\cura\\cura.log` - * `$USER/Library/Application Support/cura//cura.log` (OSX) - * `$USER/.local/share/cura//cura.log` (Ubuntu/Linux) + * `%APPDATA%\cura\\cura.log` (Windows), or usually `C:\Users\\AppData\Roaming\cura\\cura.log` + * `$HOME/Library/Application Support/cura//cura.log` (OSX) + * `$HOME/.local/share/cura//cura.log` (Ubuntu/Linux) If the Cura user interface still starts, you can also reach this directory from the application menu in Help -> Show settings folder From 503293fbebd3ee0c1c1481287c4a005a951d6d27 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Jul 2021 10:15:40 +0200 Subject: [PATCH 14/16] Revert "Also show error message if connection got reset without error code" This reverts commit 40fe8b577d004d1357235e931ee7344b013d96ad. --- plugins/CuraEngineBackend/CuraEngineBackend.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 272ad3a7e9..fa9a8c5474 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -610,15 +610,10 @@ class CuraEngineBackend(QObject, Backend): if error.getErrorCode() not in [Arcus.ErrorCode.BindFailedError, Arcus.ErrorCode.ConnectionResetError, Arcus.ErrorCode.Debug]: Logger.log("w", "A socket error caused the connection to be reset") - elif error.getErrorCode() == Arcus.ErrorCode.ConnectionResetError: - Logger.error("CuraEngine crashed abnormally! The socket connection was reset unexpectedly.") - self._slicing_error_message.show() - self.setState(BackendState.Error) - self.stopSlicing() # _terminate()' function sets the job status to 'cancel', after reconnecting to another Port the job status # needs to be updated. Otherwise backendState is "Unable To Slice" - elif error.getErrorCode() == Arcus.ErrorCode.BindFailedError and self._start_slice_job is not None: + if error.getErrorCode() == Arcus.ErrorCode.BindFailedError and self._start_slice_job is not None: self._start_slice_job.setIsCancelled(False) # Check if there's any slicable object in the scene. From c2f23045122b112902239ccf12be9c73a3015569 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 16 Jul 2021 10:48:24 +0200 Subject: [PATCH 15/16] Move Kossel Pro platform mesh a bit lower to prevent Z-fighting As reported in #8296. --- resources/definitions/anycubic_kossel_linear_plus.def.json | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/definitions/anycubic_kossel_linear_plus.def.json b/resources/definitions/anycubic_kossel_linear_plus.def.json index a4aeac75a0..9683cf61cf 100644 --- a/resources/definitions/anycubic_kossel_linear_plus.def.json +++ b/resources/definitions/anycubic_kossel_linear_plus.def.json @@ -5,6 +5,7 @@ "metadata": { "visible": true, "platform": "kossel_pro_build_platform.3mf", + "platform_offset": [0, -0.25, 0], "machine_extruder_trains": { "0": "anycubic_kossel_extruder_0" } From f9557295fa3fa329260856ed790af86668274b11 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Fri, 16 Jul 2021 12:39:41 +0200 Subject: [PATCH 16/16] Allow non-ASCII characters for DL project names. CURA-8395 --- plugins/DigitalLibrary/src/DigitalFactoryApiClient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index 9a3157ccd6..a9a1ab360b 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -366,7 +366,7 @@ class DigitalFactoryApiClient: :param on_error: The function to be called if anything goes wrong. """ - display_name = re.sub(r"[^a-zA-Z0-9- ./™®ö+']", " ", project_name) + display_name = re.sub(r"^[\\w\\-\\. ()]+\\.[a-zA-Z0-9]+$", " ", project_name) Logger.log("i", "Attempt to create new DF project '{}'.".format(display_name)) url = "{}/projects".format(self.CURA_API_ROOT)