Merge pull request #12531 from Ultimaker/CURA-8555_link_ufp_to_3mf_in_digital_library

Cura 8555 link ufp to 3mf in digital library
This commit is contained in:
Remco Burema 2022-06-15 15:16:11 +02:00 committed by GitHub
commit 188b63703b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 55 deletions

View file

@ -14,6 +14,9 @@ import DigitalFactory 1.0 as DF
Item
{
id: base
property variant catalog: UM.I18nCatalog { name: "cura" }
width: parent.width
height: parent.height
@ -190,53 +193,29 @@ Item
text: "Save"
enabled: (asProjectCheckbox.checked || asSlicedCheckbox.checked) && dfFilenameTextfield.text.length >= 1 && dfFilenameTextfield.state !== 'invalid'
onClicked:
{
let saveAsFormats = [];
if (asProjectCheckbox.checked)
{
saveAsFormats.push("3mf");
}
if (asSlicedCheckbox.checked)
{
saveAsFormats.push("ufp");
}
manager.saveFileToSelectedProject(dfFilenameTextfield.text, saveAsFormats);
}
onClicked: manager.saveFileToSelectedProject(dfFilenameTextfield.text, asProjectComboBox.currentValue)
busy: false
}
Row
Cura.ComboBox
{
id: asProjectComboBox
id: saveAsFormatRow
width: UM.Theme.getSize("combobox_wide").width
height: saveButton.height
anchors.verticalCenter: saveButton.verticalCenter
anchors.right: saveButton.left
anchors.rightMargin: UM.Theme.getSize("thin_margin").height
width: childrenRect.width
spacing: UM.Theme.getSize("default_margin").width
UM.CheckBox
{
id: asProjectCheckbox
height: UM.Theme.getSize("checkbox").height
anchors.verticalCenter: parent.verticalCenter
checked: true
text: "Save Cura project"
font: UM.Theme.getFont("medium")
}
enabled: UM.Backend.state == UM.Backend.Done
currentIndex: UM.Backend.state == UM.Backend.Done ? 0 : 1
textRole: "text"
valueRole: "value"
UM.CheckBox
{
id: asSlicedCheckbox
height: UM.Theme.getSize("checkbox").height
anchors.verticalCenter: parent.verticalCenter
enabled: UM.Backend.state == UM.Backend.Done
checked: UM.Backend.state == UM.Backend.Done
text: "Save print file"
font: UM.Theme.getFont("medium")
}
model: [
{ text: catalog.i18nc("@option", "Save Cura project and print file"), key: "3mf_ufp", value: ["3mf", "ufp"] },
{ text: catalog.i18nc("@option", "Save Cura project"), key: "3mf", value: ["3mf"] },
]
}
Component.onCompleted:

View file

@ -37,17 +37,18 @@ class DFFileExportAndUploadManager:
formats: List[str],
on_upload_error: Callable[[], Any],
on_upload_success: Callable[[], Any],
on_upload_finished: Callable[[], Any] ,
on_upload_finished: Callable[[], Any],
on_upload_progress: Callable[[int], Any]) -> None:
self._file_handlers = file_handlers # type: Dict[str, FileHandler]
self._nodes = nodes # type: List[SceneNode]
self._library_project_id = library_project_id # type: str
self._library_project_name = library_project_name # type: str
self._file_name = file_name # type: str
self._upload_jobs = [] # type: List[ExportFileJob]
self._formats = formats # type: List[str]
self._file_handlers: Dict[str, FileHandler] = file_handlers
self._nodes: List[SceneNode] = nodes
self._library_project_id: str = library_project_id
self._library_project_name: str = library_project_name
self._file_name: str = file_name
self._upload_jobs: List[ExportFileJob] = []
self._formats: List[str] = formats
self._api = DigitalFactoryApiClient(application = CuraApplication.getInstance(), on_error = lambda error: Logger.log("e", str(error)))
self._source_file_id: Optional[str] = None
# Functions of the parent class that should be called based on the upload process output
self._on_upload_error = on_upload_error
@ -59,7 +60,7 @@ class DFFileExportAndUploadManager:
# show the success message (once both upload jobs are done)
self._message_lock = threading.Lock()
self._file_upload_job_metadata = self.initializeFileUploadJobMetadata() # type: Dict[str, Dict[str, Any]]
self._file_upload_job_metadata: Dict[str, Dict[str, Any]] = self.initializeFileUploadJobMetadata()
self.progress_message = Message(
title = "Uploading...",
@ -113,7 +114,8 @@ class DFFileExportAndUploadManager:
content_type = job.getMimeType(),
job_name = job.getFileName(),
file_size = len(job.getOutput()),
library_project_id = self._library_project_id
library_project_id = self._library_project_id,
source_file_id = self._source_file_id
)
self._api.requestUploadUFP(request, on_finished = self._uploadFileData, on_error = self._onRequestUploadPrintFileFailed)
@ -125,6 +127,9 @@ class DFFileExportAndUploadManager:
"""
if isinstance(file_upload_response, DFLibraryFileUploadResponse):
file_name = file_upload_response.file_name
# store the `file_id` so it can be as `source_file_id` when uploading the print file
self._source_file_id = file_upload_response.file_id
elif isinstance(file_upload_response, DFPrintJobUploadResponse):
file_name = file_upload_response.job_name if file_upload_response.job_name is not None else ""
else:
@ -145,6 +150,8 @@ class DFFileExportAndUploadManager:
on_progress = self._onUploadProgress,
on_error = self._onUploadError)
self._handleNextUploadJob()
def _onUploadProgress(self, filename: str, progress: int) -> None:
"""
Updates the progress message according to the total progress of the two files and displays it to the user. It is
@ -325,8 +332,13 @@ class DFFileExportAndUploadManager:
message.hide()
def start(self) -> None:
for job in self._upload_jobs:
job.start()
self._handleNextUploadJob()
def _handleNextUploadJob(self):
match self._upload_jobs:
case [job, *jobs]:
job.start()
self._upload_jobs = jobs
def initializeFileUploadJobMetadata(self) -> Dict[str, Any]:
metadata = {}

View file

@ -39,8 +39,8 @@ class DFFileUploader:
:param on_error: The method to be called when an error occurs.
"""
self._http = http # type: HttpRequestManager
self._df_file = df_file # type: Union[DFLibraryFileUploadResponse, DFPrintJobUploadResponse]
self._http: HttpRequestManager = http
self._df_file: Union[DFLibraryFileUploadResponse, DFPrintJobUploadResponse] = df_file
self._file_name = ""
if isinstance(self._df_file, DFLibraryFileUploadResponse):
self._file_name = self._df_file.file_name
@ -51,7 +51,7 @@ class DFFileUploader:
self._file_name = ""
else:
raise TypeError("Incorrect input type")
self._data = data # type: bytes
self._data: bytes = data
self._on_finished = on_finished
self._on_success = on_success

View file

@ -1,12 +1,14 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional
from .BaseModel import BaseModel
# Model that represents the request to upload a print job to the cloud
class DFPrintJobUploadRequest(BaseModel):
def __init__(self, job_name: str, file_size: int, content_type: str, library_project_id: str, **kwargs) -> None:
def __init__(self, job_name: str, file_size: int, content_type: str, library_project_id: str, source_file_id: str, **kwargs) -> None:
"""Creates a new print job upload request.
:param job_name: The name of the print job.
@ -18,4 +20,5 @@ class DFPrintJobUploadRequest(BaseModel):
self.file_size = file_size
self.content_type = content_type
self.library_project_id = library_project_id
self.source_file_id = source_file_id
super().__init__(**kwargs)

View file

@ -40,7 +40,7 @@ class DigitalFactoryApiClient:
DEFAULT_REQUEST_TIMEOUT = 10 # seconds
# In order to avoid garbage collection we keep the callbacks in this list.
_anti_gc_callbacks = [] # type: List[Callable[[Any], None]]
_anti_gc_callbacks: List[Callable[[Any], None]] = []
def __init__(self, application: CuraApplication, on_error: Callable[[List[CloudError]], None], projects_limit_per_page: Optional[int] = None) -> None:
"""Initializes a new digital factory API client.
@ -54,7 +54,7 @@ class DigitalFactoryApiClient:
self._scope = JsonDecoratorScope(UltimakerCloudScope(application))
self._http = HttpRequestManager.getInstance()
self._on_error = on_error
self._file_uploader = None # type: Optional[DFFileUploader]
self._file_uploader: Optional[DFFileUploader] = None
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]