From 22826bc4d89a425812b2d003edeb273c8a10cdab Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Jul 2021 17:16:16 +0200 Subject: [PATCH 01/15] Add text field in a layout for search The text field is not stylised yet, so far. Will do, but let's first make it functional. Contributes to issue CURA-8009. --- .../resources/qml/SelectProjectPage.qml | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 2de0e78cc7..4fcccac61e 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -1,10 +1,12 @@ // Copyright (C) 2021 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.10 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 as OldControls // TableView doesn't exist in the QtQuick Controls 2.x in 5.10, so use the old one import QtQuick.Controls 2.3 import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.1 import UM 1.2 as UM import Cura 1.6 as Cura @@ -29,31 +31,37 @@ Item margins: UM.Theme.getSize("default_margin").width } - Label + RowLayout { - id: selectProjectLabel + id: headerRow - text: "Select Project" - font: UM.Theme.getFont("medium") - color: UM.Theme.getColor("small_button_text") - anchors.top: parent.top - anchors.left: parent.left - visible: projectListContainer.visible - } - - Cura.SecondaryButton - { - id: createNewProjectButton - - anchors.verticalCenter: selectProjectLabel.verticalCenter - anchors.right: parent.right - text: "New Library project" - - onClicked: + anchors { - createNewProjectPopup.open() + top: parent.top + left: parent.left + right: parent.right + } + height: childrenRect.height + + TextField + { + id: searchBar + Layout.fillWidth: true + height: createNewProjectButton.height + } + + Cura.SecondaryButton + { + id: createNewProjectButton + + text: "New Library project" + + onClicked: + { + createNewProjectPopup.open() + } + busy: manager.creatingNewProjectStatus == DF.RetrievalStatus.InProgress } - busy: manager.creatingNewProjectStatus == DF.RetrievalStatus.InProgress } Item @@ -106,7 +114,7 @@ Item id: projectListContainer anchors { - top: selectProjectLabel.bottom + top: headerRow.bottom topMargin: UM.Theme.getSize("default_margin").height bottom: parent.bottom left: parent.left From 65f7eb5ea8f0cd5a8c1c7e56e08f1c08fcfc71f4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Jul 2021 17:41:10 +0200 Subject: [PATCH 02/15] Add function to update search filter when the user types Seems to work fine. The pyqtSignal is not technically necessary unless we display this filter in the interface anywhere. We don't currently. If the signal is not present it would complain about non-notifyable properties. And making it a slot instead of a signal seems a bit unintuitive to me in how the field is being used. Contributes to issue CURA-8009. --- .../resources/qml/SelectProjectPage.qml | 2 + .../src/DigitalFactoryController.py | 39 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 4fcccac61e..ecec9556c9 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -48,6 +48,8 @@ Item id: searchBar Layout.fillWidth: true height: createNewProjectButton.height + + onTextEdited: manager.projectFilter = text } Cura.SecondaryButton diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 368b29219a..3d1cc178f8 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -1,4 +1,6 @@ # Copyright (c) 2021 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + import json import math import os @@ -8,7 +10,7 @@ from enum import IntEnum from pathlib import Path from typing import Optional, List, Dict, Any, cast -from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot, pyqtProperty, Q_ENUMS, QUrl +from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot, pyqtProperty, Q_ENUMS, QTimer, QUrl from PyQt5.QtNetwork import QNetworkReply from PyQt5.QtQml import qmlRegisterType, qmlRegisterUncreatableType @@ -116,6 +118,11 @@ class DigitalFactoryController(QObject): self._project_model = DigitalFactoryProjectModel() self._selected_project_idx = -1 self._project_creation_error_text = "Something went wrong while creating a new project. Please try again." + self._project_filter = "" + self._project_filter_change_timer = QTimer() + self._project_filter_change_timer.setInterval(1000) + self._project_filter_change_timer.setSingleShot(True) + self._project_filter_change_timer.timeout.connect(self._applyProjectFilter) # Initialize the file model self._file_model = DigitalFactoryFileModel() @@ -302,6 +309,36 @@ class DigitalFactoryController(QObject): self._selected_file_indices = file_indices self.selectedFileIndicesChanged.emit(file_indices) + def setProjectFilter(self, new_filter) -> None: + """ + Called when the user wants to change the search filter for projects. + + The filter is not immediately applied. There is some delay to allow the user to finish typing. + :param new_filter: The new filter that the user wants to apply. + """ + self._project_filter = new_filter + self._project_filter_change_timer.start() + + """ + Signal to notify Qt that the applied filter has changed. + """ + projectFilterChanged = pyqtSignal() + + @pyqtProperty(str, notify = projectFilterChanged, fset = setProjectFilter) + def projectFilter(self) -> str: + """ + The current search filter being applied to the project list. + :return: The current search filter being applied to the project list. + """ + return self._project_filter + + def _applyProjectFilter(self): + """ + Actually apply the current filter to search for projects with the user-defined search string. + :return: + """ + self.projectFilterChanged.emit() + @pyqtProperty(QObject, constant = True) def digitalFactoryProjectModel(self) -> "DigitalFactoryProjectModel": return self._project_model From 02932a1f62dd62f17d405666ae932d0dec78537a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Jul 2021 18:43:02 +0200 Subject: [PATCH 03/15] Add filter to API call for project list This passes the filter on to the API call and causes the API call, so that we only get the projects that the user searched for. Contributes to issue CURA-8009. --- plugins/DigitalLibrary/src/DigitalFactoryApiClient.py | 11 ++++++++--- .../DigitalLibrary/src/DigitalFactoryController.py | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py index e1a62fdd5c..4ebb3cb051 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryApiClient.py @@ -95,7 +95,7 @@ class DigitalFactoryApiClient: error_callback = failed, timeout = self.DEFAULT_REQUEST_TIMEOUT) - def getProjectsFirstPage(self, on_finished: Callable[[List[DigitalFactoryProjectResponse]], Any], failed: Callable) -> None: + def getProjectsFirstPage(self, search_filter: str, on_finished: Callable[[List[DigitalFactoryProjectResponse]], Any], failed: Callable) -> None: """ Retrieves digital factory projects for the user that is currently logged in. @@ -103,13 +103,18 @@ class DigitalFactoryApiClient: according to the limit set in the pagination manager. If there is no projects pagination manager, this function leaves the project limit to the default set on the server side (999999). + :param search_filter: Text to filter the search results. If given an empty string, results are not filtered. :param on_finished: The function to be called after the result is parsed. :param failed: The function to be called if the request fails. """ - url = "{}/projects".format(self.CURA_API_ROOT) + url = f"{self.CURA_API_ROOT}/projects" + query_character = "?" if self._projects_pagination_mgr: self._projects_pagination_mgr.reset() # reset to clear all the links and response metadata - url += "?limit={}".format(self._projects_pagination_mgr.limit) + url += f"{query_character}limit={self._projects_pagination_mgr.limit}" + query_character = "&" + if search_filter != "": + url += f"{query_character}search={search_filter}" self._http.get(url, scope = self._scope, diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 3d1cc178f8..a5cc2936a3 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -183,7 +183,7 @@ class DigitalFactoryController(QObject): if preselected_project_id: self._api.getProject(preselected_project_id, on_finished = self.setProjectAsPreselected, failed = self._onGetProjectFailed) else: - self._api.getProjectsFirstPage(on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) + self._api.getProjectsFirstPage(search_filter = self._project_filter, on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) def setProjectAsPreselected(self, df_project: DigitalFactoryProjectResponse) -> None: """ @@ -338,6 +338,7 @@ class DigitalFactoryController(QObject): :return: """ self.projectFilterChanged.emit() + self._api.getProjectsFirstPage(search_filter = self._project_filter, on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) @pyqtProperty(QObject, constant = True) def digitalFactoryProjectModel(self) -> "DigitalFactoryProjectModel": From 94e229aa446a291370bcfa06690907d8233a1793 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Jul 2021 18:44:11 +0200 Subject: [PATCH 04/15] Clear list of projects every time we load the first page Otherwise when we refresh the project list after searching it would put the new results at the end. That's not what we want. Contributes to issue CURA-8009. --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index a5cc2936a3..80f4d37f66 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -211,6 +211,7 @@ class DigitalFactoryController(QObject): :param df_projects: A list of all the Digital Factory Library projects linked to the user's account """ + self.clear() self.setHasMoreProjectsToLoad(self._api.hasMoreProjectsToLoad()) self._project_model.setProjects(df_projects) self.setRetrievingProjectsStatus(RetrievalStatus.Success) From 1269c28d0a14d53a1a2630666b5f9ac8b9241020 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 12 Jul 2021 18:46:54 +0200 Subject: [PATCH 05/15] Reduce wait time before sending query Most people should be able to type 5 characters per second. And those that can't will just have to see it refresh after every stroke. Contributes to issue CURA-8009. --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 80f4d37f66..796937a9d9 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -120,7 +120,7 @@ class DigitalFactoryController(QObject): self._project_creation_error_text = "Something went wrong while creating a new project. Please try again." self._project_filter = "" self._project_filter_change_timer = QTimer() - self._project_filter_change_timer.setInterval(1000) + self._project_filter_change_timer.setInterval(200) self._project_filter_change_timer.setSingleShot(True) self._project_filter_change_timer.timeout.connect(self._applyProjectFilter) From 13ca30ed98c9ab2c2155d2d60465a58dbda92137 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 14:40:04 +0200 Subject: [PATCH 06/15] Stylise search bar This is the standard style for text fields in Cura. The spacing around the search icon is customised with the best approximation I could get using a simple string of placeholderText. Contributes to issue CURA-8009. --- .../resources/qml/SelectProjectPage.qml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index ecec9556c9..08bf8aec7c 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -43,13 +43,20 @@ Item } height: childrenRect.height - TextField + Cura.TextField { id: searchBar Layout.fillWidth: true height: createNewProjectButton.height - onTextEdited: manager.projectFilter = text + onTextEdited: manager.projectFilter = text //Update the search filter when editing this text field. + + placeholderText: + { + var image_size = "width=\"" + UM.Theme.getSize("small_button_icon").width + "\" height=\"" + UM.Theme.getSize("small_button_icon").height + "\" "; + var image_source = "src=\"" + UM.Theme.getIcon("Magnifier") + "\""; + return "   Search"; + } } Cura.SecondaryButton From 1566a282dcad5f5405f4e3d5ac6ecdd431513007 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 15:16:09 +0200 Subject: [PATCH 07/15] Replace text and image if there's no projects due to search It's a bit weird if it shows that you didn't add any projects yet if you just type in a gibberish search keyword. Contributes to issue CURA-8009. --- .../resources/images/projects_not_found.svg | 62 +++++++++++++++++++ .../resources/qml/SelectProjectPage.qml | 5 +- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 plugins/DigitalLibrary/resources/images/projects_not_found.svg diff --git a/plugins/DigitalLibrary/resources/images/projects_not_found.svg b/plugins/DigitalLibrary/resources/images/projects_not_found.svg new file mode 100644 index 0000000000..8aee7b797c --- /dev/null +++ b/plugins/DigitalLibrary/resources/images/projects_not_found.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 08bf8aec7c..3f1799b9ae 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -93,7 +93,7 @@ Item { id: digitalFactoryImage anchors.horizontalCenter: parent.horizontalCenter - source: "../images/digital_factory.svg" + source: searchBar.text === "" ? "../images/digital_factory.svg" : "../images/projects_not_found.svg" fillMode: Image.PreserveAspectFit width: parent.width - 2 * UM.Theme.getSize("thick_margin").width sourceSize.width: width @@ -104,7 +104,7 @@ Item { id: noLibraryProjectsLabel anchors.horizontalCenter: parent.horizontalCenter - text: "It appears that you don't have any projects in the Library yet." + text: searchBar.text === "" ? "It appears that you don't have any projects in the Library yet." : "No projects found that match the search query." font: UM.Theme.getFont("medium") } @@ -114,6 +114,7 @@ Item anchors.horizontalCenter: parent.horizontalCenter text: "Visit Digital Library" onClicked: Qt.openUrlExternally(CuraApplication.ultimakerDigitalFactoryUrl + "/app/library") + visible: searchBar.text === "" //Show the link to Digital Library when there are no projects in the user's Library. } } } From bec83920e46d3f5f82ded82a8c26b4a4fb5b3a4d Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 15:47:21 +0200 Subject: [PATCH 08/15] Keep showing search icon while typing search query This adds an option to the TextField element to show an icon on the left side in the text field. The icon remains visible when the user types in something (it's not part of the placeholder string). Then we use that optional icon for the search bar in the Digital Library. Contributes to issue CURA-8009. --- .../resources/qml/SelectProjectPage.qml | 9 +++----- resources/qml/Widgets/TextField.qml | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 3f1799b9ae..36e3de3da7 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -51,12 +51,8 @@ Item onTextEdited: manager.projectFilter = text //Update the search filter when editing this text field. - placeholderText: - { - var image_size = "width=\"" + UM.Theme.getSize("small_button_icon").width + "\" height=\"" + UM.Theme.getSize("small_button_icon").height + "\" "; - var image_source = "src=\"" + UM.Theme.getIcon("Magnifier") + "\""; - return "   Search"; - } + leftIcon: UM.Theme.getIcon("Magnifier") + placeholderText: "Search" } Cura.SecondaryButton @@ -106,6 +102,7 @@ Item anchors.horizontalCenter: parent.horizontalCenter text: searchBar.text === "" ? "It appears that you don't have any projects in the Library yet." : "No projects found that match the search query." font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") } Cura.TertiaryButton diff --git a/resources/qml/Widgets/TextField.qml b/resources/qml/Widgets/TextField.qml index 28074d4415..2643609eaf 100644 --- a/resources/qml/Widgets/TextField.qml +++ b/resources/qml/Widgets/TextField.qml @@ -15,6 +15,8 @@ TextField { id: textField + property alias leftIcon: iconLeft.source + UM.I18nCatalog { id: catalog; name: "cura" } hoverEnabled: true @@ -22,6 +24,7 @@ TextField font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") renderType: Text.NativeRendering + leftPadding: iconLeft.visible ? iconLeft.width + UM.Theme.getSize("default_margin").width * 2 : UM.Theme.getSize("thin_margin") states: [ State @@ -67,5 +70,23 @@ TextField } return UM.Theme.getColor("setting_control_border") } + + //Optional icon added on the left hand side. + UM.RecolorImage + { + id: iconLeft + + anchors + { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + } + + visible: source != "" + height: UM.Theme.getSize("small_button_icon").height + width: visible ? height : 0 + color: textField.color + } } } From 7fdf1dbdd4a511f626133547f7cb1eb1441f7e07 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 16:02:29 +0200 Subject: [PATCH 09/15] Fix height of search bar Because this item is in a layout, the height gets overridden. We should use the preferredHeight, or the one it defaults to, implicitHeight. Contributes to issue CURA-8009. --- 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 36e3de3da7..529f28213b 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -47,7 +47,7 @@ Item { id: searchBar Layout.fillWidth: true - height: createNewProjectButton.height + implicitHeight: createNewProjectButton.height onTextEdited: manager.projectFilter = text //Update the search filter when editing this text field. From 3d6601a37ecc176a6e26e2727d0e067fc46768dd Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 16:04:01 +0200 Subject: [PATCH 10/15] Fix margins The margin around the icon didn't work if the icon source was none, because it was provided a QSize rather than a real. The margin around the background didn't work at all because the background is automatically adjusted to fill the parent element, so it's best left out. Contributes to issue CURA-8009. --- resources/qml/Widgets/TextField.qml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resources/qml/Widgets/TextField.qml b/resources/qml/Widgets/TextField.qml index 2643609eaf..c126c8a6e0 100644 --- a/resources/qml/Widgets/TextField.qml +++ b/resources/qml/Widgets/TextField.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Ultimaker B.V. +// Copyright (c) 2021 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.10 @@ -24,7 +24,7 @@ TextField font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") renderType: Text.NativeRendering - leftPadding: iconLeft.visible ? iconLeft.width + UM.Theme.getSize("default_margin").width * 2 : UM.Theme.getSize("thin_margin") + leftPadding: iconLeft.visible ? iconLeft.width + UM.Theme.getSize("default_margin").width * 2 : UM.Theme.getSize("thin_margin").width states: [ State @@ -55,7 +55,6 @@ TextField color: UM.Theme.getColor("main_background") - anchors.margins: Math.round(UM.Theme.getSize("default_lining").width) radius: UM.Theme.getSize("setting_control_radius").width border.color: From eb2a315e4234ff7bc78a50b2064fbf5d6bf1a658 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 16:09:02 +0200 Subject: [PATCH 11/15] Specify spacing between search bar and button Instead of using the default of 5 pixels, we should use this element from the theme to match the margin around the page. Contributes to issue CURA-8009. --- plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml index 529f28213b..1a3c1723b3 100644 --- a/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml +++ b/plugins/DigitalLibrary/resources/qml/SelectProjectPage.qml @@ -42,6 +42,7 @@ Item right: parent.right } height: childrenRect.height + spacing: UM.Theme.getSize("default_margin").width Cura.TextField { From 72eb839d079dfb137e09af31cbd234d9ec887010 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 16:18:36 +0200 Subject: [PATCH 12/15] Add missing search filter parameter to refresh query Thank you, automated tests. Contributes to issue CURA-8009. --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 796937a9d9..5f160a4b8f 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -555,7 +555,7 @@ class DigitalFactoryController(QObject): # false, we also need to clean it from the projects model self._project_model.clearProjects() self.setSelectedProjectIndex(-1) - self._api.getProjectsFirstPage(on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) + self._api.getProjectsFirstPage(search_filter = self._project_filter, on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed) self.setRetrievingProjectsStatus(RetrievalStatus.InProgress) self._has_preselected_project = new_has_preselected_project self.preselectedProjectChanged.emit() From 7f2e951b9c8ccfdd2f2be2ad6308299cc8ea88bb Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 13 Jul 2021 16:24:21 +0200 Subject: [PATCH 13/15] Update tests to test filter too Contributes to issue CURA-8009. --- .../tests/TestDigitalLibraryApiClient.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/DigitalLibrary/tests/TestDigitalLibraryApiClient.py b/plugins/DigitalLibrary/tests/TestDigitalLibraryApiClient.py index ba0a0b15b4..9751838ddf 100644 --- a/plugins/DigitalLibrary/tests/TestDigitalLibraryApiClient.py +++ b/plugins/DigitalLibrary/tests/TestDigitalLibraryApiClient.py @@ -1,3 +1,6 @@ +# Copyright (c) 2021 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + from unittest.mock import MagicMock import pytest @@ -37,7 +40,7 @@ def test_getProjectsFirstPage(api_client): failed_callback = MagicMock() # Call - api_client.getProjectsFirstPage(on_finished = finished_callback, failed = failed_callback) + api_client.getProjectsFirstPage(search_filter = "filter", on_finished = finished_callback, failed = failed_callback) # Asserts pagination_manager.reset.assert_called_once() # Should be called since we asked for new set of projects @@ -45,16 +48,16 @@ def test_getProjectsFirstPage(api_client): args = http_manager.get.call_args_list[0] # Ensure that it's called with the right limit - assert args[0][0] == "https://api.ultimaker.com/cura/v1/projects?limit=20" + assert args[0][0] == "https://api.ultimaker.com/cura/v1/projects?limit=20&search=filter" # Change the limit & try again http_manager.get.reset_mock() pagination_manager.limit = 80 - api_client.getProjectsFirstPage(on_finished = finished_callback, failed = failed_callback) + api_client.getProjectsFirstPage(search_filter = "filter", on_finished = finished_callback, failed = failed_callback) args = http_manager.get.call_args_list[0] # Ensure that it's called with the right limit - assert args[0][0] == "https://api.ultimaker.com/cura/v1/projects?limit=80" + assert args[0][0] == "https://api.ultimaker.com/cura/v1/projects?limit=80&search=filter" def test_getMoreProjects_noNewProjects(api_client): From 888f62a9ea39eefc705d658bfc2da6f1b8d5936b Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Tue, 13 Jul 2021 16:55:28 +0200 Subject: [PATCH 14/15] Add missing typing CURA-8009 --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 5f160a4b8f..9c412a9747 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -310,7 +310,7 @@ class DigitalFactoryController(QObject): self._selected_file_indices = file_indices self.selectedFileIndicesChanged.emit(file_indices) - def setProjectFilter(self, new_filter) -> None: + def setProjectFilter(self, new_filter: str) -> None: """ Called when the user wants to change the search filter for projects. @@ -333,7 +333,7 @@ class DigitalFactoryController(QObject): """ return self._project_filter - def _applyProjectFilter(self): + def _applyProjectFilter(self) -> None: """ Actually apply the current filter to search for projects with the user-defined search string. :return: From fd322c051258c089b41c83d5d86b2b2a6eec1913 Mon Sep 17 00:00:00 2001 From: Konstantinos Karmas Date: Wed, 14 Jul 2021 15:32:57 +0200 Subject: [PATCH 15/15] Fix having no "load more projects" available when using the search When the `_onGetProjectsFirstPageFinished` is reached, the pagination manager already contains the correct pagination metadata and links, so calling `clear()` there resets them giving the impression that there is no next page. This commit fixed that by calling the `clear()` function should when the search filter is applied, instead. CURA-8009 --- plugins/DigitalLibrary/src/DigitalFactoryController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/DigitalLibrary/src/DigitalFactoryController.py b/plugins/DigitalLibrary/src/DigitalFactoryController.py index 9c412a9747..0821cc6925 100644 --- a/plugins/DigitalLibrary/src/DigitalFactoryController.py +++ b/plugins/DigitalLibrary/src/DigitalFactoryController.py @@ -211,7 +211,6 @@ class DigitalFactoryController(QObject): :param df_projects: A list of all the Digital Factory Library projects linked to the user's account """ - self.clear() self.setHasMoreProjectsToLoad(self._api.hasMoreProjectsToLoad()) self._project_model.setProjects(df_projects) self.setRetrievingProjectsStatus(RetrievalStatus.Success) @@ -338,6 +337,7 @@ class DigitalFactoryController(QObject): Actually apply the current filter to search for projects with the user-defined search string. :return: """ + self.clear() self.projectFilterChanged.emit() self._api.getProjectsFirstPage(search_filter = self._project_filter, on_finished = self._onGetProjectsFirstPageFinished, failed = self._onGetProjectsFailed)