Skip to content

Commit 1bb95f3

Browse files
committed
New Version 1.14.0
- E #21, #59, #94, #124 reprint feature, if gcode is still available in local file-system - E disabling of filemanttracking is now possible - E grab all informations from SpoolManager-Plugin 1.4+ - E reduce plugin zip-size - B #146, #139 CSV Import fix and ignoring empty lines - B #123 strip M117 camera-expression
1 parent 766d0a5 commit 1bb95f3

16 files changed

+599
-133
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
script:
66
# debug - echo 'Hello World'
77
- export PLUGIN_VERSION=$(cat setup.py | grep 'plugin_version = "*"' | cut -d '"' -f2)
8-
- zip -r master *
8+
- zip -r master.zip * -i '\octoprint_*' 'translations' 'README.md' 'requirements.txt' 'setup.py'
99
# debug - ls -al
1010

1111
## see "Fix travis automatic build and deploy"

octoprint_PrintJobHistory/__init__.py

+184-86
Large diffs are not rendered by default.

octoprint_PrintJobHistory/api/PrintJobHistoryAPI.py

+47-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919

2020
from werkzeug.datastructures import Headers
2121

22+
from octoprint.filemanager import FileDestinations
23+
2224
from octoprint_PrintJobHistory import PrintJobModel, TemperatureModel, FilamentModel
2325
from octoprint_PrintJobHistory.api import TransformPrintJob2JSON, TransformSlicerSettings2JSON
2426

2527
from octoprint_PrintJobHistory.common import StringUtils
28+
from octoprint_PrintJobHistory.common import PrintJobUtils
29+
2630
from octoprint_PrintJobHistory.common.SettingsKeys import SettingsKeys
2731

2832
from octoprint_PrintJobHistory.CameraManager import CameraManager
@@ -164,6 +168,14 @@ def _createSamplePrintModel(self):
164168
################################################### APIs
165169

166170

171+
####################################################################################### CONFIRM MESSAGE
172+
@octoprint.plugin.BlueprintPlugin.route("/confirmMessageDialog", methods=["PUT"])
173+
def put_confirmMessageDialog(self):
174+
self._settings.set([SettingsKeys.SETTINGS_KEY_MESSAGE_CONFIRM_DATA], None)
175+
self._settings.save()
176+
177+
return flask.jsonify([])
178+
167179
####################################################################################### DEACTIVATE PLUGIN CHECK
168180
@octoprint.plugin.BlueprintPlugin.route("/deactivatePluginCheck", methods=["PUT"])
169181
def put_pluginDependencyCheck(self):
@@ -172,7 +184,6 @@ def put_pluginDependencyCheck(self):
172184

173185
return flask.jsonify([])
174186

175-
176187
####################################################################################### LOAD STATISTIC BY QUERY
177188
@octoprint.plugin.BlueprintPlugin.route("/loadStatisticByQuery", methods=["GET"])
178189
def get_statisticByQuery(self):
@@ -182,7 +193,6 @@ def get_statisticByQuery(self):
182193

183194
return flask.jsonify(statistic)
184195

185-
186196
####################################################################################### COMPARE Slicer Settings
187197
@octoprint.plugin.BlueprintPlugin.route("/compareSlicerSettings/", methods=["GET"])
188198
def get_compareSlicerSettings(self):
@@ -212,23 +222,53 @@ def get_compareSlicerSettings(self):
212222

213223
return flask.jsonify()
214224

215-
216-
217225
####################################################################################### LOAD ALL JOBS BY QUERY
218226
@octoprint.plugin.BlueprintPlugin.route("/loadPrintJobHistoryByQuery", methods=["GET"])
219227
def get_printjobhistoryByQuery(self):
220228

221229
tableQuery = flask.request.values
222230
allJobsModels = self._databaseManager.loadPrintJobsByQuery(tableQuery)
223231
# allJobsAsDict = self._convertPrintJobHistoryModelsToDict(allJobsModels)
224-
allJobsAsDict = TransformPrintJob2JSON.transformAllPrintJobModels(allJobsModels)
232+
# selectedFile = self._file_manager.path_on_disk(fileLocation, selectedFilename)
233+
allJobsAsDict = TransformPrintJob2JSON.transformAllPrintJobModels(allJobsModels, self._file_manager)
225234

226235
totalItemCount = self._databaseManager.countPrintJobsByQuery(tableQuery)
227236
return flask.jsonify({
228237
"totalItemCount": totalItemCount,
229238
"allPrintJobs": allJobsAsDict
230239
})
231240

241+
####################################################################################### SELECT JOB FOR PRINTING
242+
@octoprint.plugin.BlueprintPlugin.route("/selectPrintJobForPrint/<int:databaseId>", methods=["PUT"])
243+
def put_select_printjob(self, databaseId):
244+
245+
printJobModel = self._databaseManager.loadPrintJob(databaseId);
246+
if (printJobModel == None):
247+
# PrintJob was deleted
248+
message = "PrintJob not in database anymore! Selection not possible."
249+
self._logger.error(message)
250+
self._sendDataToClient(dict(action="errorPopUp",
251+
title="Print selection not possible",
252+
message=message))
253+
return flask.jsonify()
254+
255+
printJobPrintable = PrintJobUtils.isPrintJobReprintable(self._file_manager,
256+
printJobModel.fileOrigin,
257+
printJobModel.filePathName,
258+
printJobModel.fileName)
259+
fullFileLocation = printJobPrintable["fullFileLocation"]
260+
if (printJobPrintable["isRePrintable"] == False):
261+
message = "PrintJob not found in: " +fullFileLocation
262+
self._logger.error(message)
263+
self._sendDataToClient(dict(action="errorPopUp",
264+
title="Print selection not possible",
265+
message=message))
266+
return flask.jsonify()
267+
sd = False if (printJobModel.fileOrigin != None and printJobModel.fileOrigin == "local") else True
268+
self._printer.select_file(fullFileLocation, sd)
269+
270+
return flask.jsonify()
271+
232272
####################################################################################### DELETE JOB
233273
@octoprint.plugin.BlueprintPlugin.route("/removePrintJob/<int:databaseId>", methods=["DELETE"])
234274
def delete_printjob(self, databaseId):
@@ -369,7 +409,7 @@ def delete_snapshot(self, snapshotFilename):
369409

370410
####################################################################################### DOWNLOAD DATABASE-FILE
371411
@octoprint.plugin.BlueprintPlugin.route("/downloadDatabase", methods=["GET"])
372-
def download_database(self):
412+
def get_download_database(self):
373413
return send_file(self._databaseManager.getDatabaseFileLocation(),
374414
mimetype='application/octet-stream',
375415
attachment_filename='printJobHistory.db',
@@ -388,7 +428,7 @@ def delete_database(self):
388428

389429
####################################################################################### EXPORT DATABASE as CSV
390430
@octoprint.plugin.BlueprintPlugin.route("/exportPrintJobHistory/<string:exportType>", methods=["GET"])
391-
def exportPrintJobHistoryData(self, exportType):
431+
def get_exportPrintJobHistoryData(self, exportType):
392432

393433
if exportType == "CSV":
394434
if "databaseIds" in flask.request.values:

octoprint_PrintJobHistory/api/TransformPrintJob2JSON.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# coding=utf-8
22
from __future__ import absolute_import
33

4+
45
from octoprint_PrintJobHistory.CameraManager import CameraManager
56
from octoprint_PrintJobHistory.common import StringUtils
7+
from octoprint_PrintJobHistory.common import PrintJobUtils
68

79

810

9-
def transformPrintJobModel(job):
11+
def transformPrintJobModel(job, fileManager):
1012
jobAsDict = job.__data__
1113

1214
jobAsDict["printStartDateTimeFormatted"] = job.printStartDateTime.strftime('%d.%m.%Y %H:%M')
@@ -55,13 +57,19 @@ def transformPrintJobModel(job):
5557
del jobAsDict["printEndDateTime"]
5658
del jobAsDict["created"]
5759

60+
# not the best approach to check this value here
61+
printJobReprintable = PrintJobUtils.isPrintJobReprintable(fileManager, job.fileOrigin, job.filePathName, job.fileName)
62+
63+
jobAsDict["isRePrintable"] = printJobReprintable["isRePrintable"]
64+
jobAsDict["fullFileLocation"] = printJobReprintable["fullFileLocation"]
65+
5866
return jobAsDict
5967

60-
def transformAllPrintJobModels(allJobsModels):
68+
def transformAllPrintJobModels(allJobsModels, fileManager):
6169

6270
result = []
6371
for job in allJobsModels:
64-
jobAsDict = transformPrintJobModel(job)
72+
jobAsDict = transformPrintJobModel(job, fileManager)
6573
result.append(jobAsDict)
6674

6775
return result

octoprint_PrintJobHistory/common/CSVExportImporter.py

+28-19
Original file line numberDiff line numberDiff line change
@@ -270,44 +270,43 @@ def parseAndAssignFieldValue(self, fieldLabel, fieldName, fieldValue, printJobMo
270270
# check if mandatory
271271
return
272272

273-
filemanentModel = None
274-
allFilemanentModel = printJobModel.getFilamentModels()
275-
if (allFilemanentModel != None and len(allFilemanentModel) > 0):
276-
filemanentModel = allFilemanentModel[0]
277-
else:
278-
filemanentModel = FilamentModel()
279-
filemanentModel.toolId = "total"
280-
printJobModel.addFilamentModel(filemanentModel)
273+
# allFilemanentModel = printJobModel.getFilamentModels()
274+
filamanentModel = printJobModel.getFilamentModelByToolId("total")
275+
276+
if (filamanentModel == None):
277+
filamanentModel = FilamentModel()
278+
filamanentModel.toolId = "total"
279+
printJobModel.addFilamentModel(filamanentModel)
281280

282281
if (COLUMN_SPOOL_VENDOR == fieldLabel):
283-
filemanentModel.vendor = fieldValue
282+
filamanentModel.vendor = fieldValue
284283
pass
285284
elif (COLUMN_SPOOL_NAME == fieldLabel):
286-
filemanentModel.spoolName = fieldValue
285+
filamanentModel.spoolName = fieldValue
287286
pass
288287
elif (COLUMN_MATERIAL == fieldLabel):
289-
filemanentModel.material = fieldValue
288+
filamanentModel.material = fieldValue
290289
pass
291290
elif (COLUMN_DIAMETER == fieldLabel):
292-
filemanentModel.diameter = float(fieldValue)
291+
filamanentModel.diameter = float(fieldValue)
293292
pass
294293
elif (COLUMN_DENSITY == fieldLabel):
295-
filemanentModel.density = float(fieldValue)
294+
filamanentModel.density = float(fieldValue)
296295
pass
297296
elif (COLUMN_USED_LENGTH == fieldLabel):
298-
filemanentModel.usedLength = float(fieldValue)
297+
filamanentModel.usedLength = float(fieldValue)
299298
pass
300299
elif (COLUMN_CALCULATED_LENGTH == fieldLabel):
301-
filemanentModel.calculatedLength = float(fieldValue)
300+
filamanentModel.calculatedLength = float(fieldValue)
302301
pass
303302
elif (COLUMN_USED_WEIGHT == fieldLabel):
304-
filemanentModel.usedWeight = float(fieldValue)
303+
filamanentModel.usedWeight = float(fieldValue)
305304
pass
306305
elif (COLUMN_USED_FILAMENT_COSTS == fieldLabel):
307306
costUnit = fieldValue[-1]
308307
if (costUnit.isdigit()):
309308
# no unit present
310-
filemanentModel.usedCost = float(fieldValue)
309+
filamanentModel.usedCost = float(fieldValue)
311310
else:
312311
# Split between cost and unit
313312
costValue = ""
@@ -318,8 +317,8 @@ def parseAndAssignFieldValue(self, fieldLabel, fieldName, fieldValue, printJobMo
318317
else:
319318
costUnit = fieldValue[i:]
320319
break
321-
filemanentModel.usedCost = float(costValue)
322-
filemanentModel.spoolCostUnit = costUnit
320+
filamanentModel.usedCost = float(costValue)
321+
filamanentModel.spoolCostUnit = costUnit
323322

324323
pass
325324
pass
@@ -463,6 +462,16 @@ def parseCSV(csvFile4Import, updateParsingStatus, errorCollection, logger, delet
463462
errorCollection.append("Mandatory column is missing! <br/><b>'" + "".join(mandatoryFieldMissing) + "'</b><br/>")
464463
break
465464
else:
465+
# pre check, do we have values in the line?
466+
isEmptyLine = True
467+
for columnValue in row:
468+
if (StringUtils.isNotEmpty(columnValue)):
469+
isEmptyLine = False
470+
break
471+
if (isEmptyLine == True):
472+
# errorCollection.append("CSV Line: "+str(lineNumber)+" without values! <br/>")
473+
# just skip this line
474+
continue
466475
printJobModel = PrintJobModel()
467476
# parse line with header defined order
468477
columnIndex = 0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# coding=utf-8
2+
from __future__ import absolute_import
3+
from octoprint.filemanager import FileDestinations
4+
from octoprint_PrintJobHistory.common import StringUtils
5+
6+
def isPrintJobReprintable(fileManager, fileOrigin, filePathName, fileName):
7+
resultPrintJobPrintable = {}
8+
9+
isRePrintable = False
10+
fullFileLocation = ""
11+
filePath = filePathName if StringUtils.isNotEmpty(filePathName) else fileName
12+
13+
if (fileOrigin == None):
14+
# could be during csv import, assumption it is local
15+
fileOrigin = FileDestinations.LOCAL
16+
17+
if (fileOrigin == FileDestinations.LOCAL):
18+
# local filesystem
19+
fullFileLocation = fileManager.path_on_disk(fileOrigin, filePath)
20+
isRePrintable = _isFileReadable(fullFileLocation)
21+
pass
22+
else:
23+
# sd-card
24+
# - no readable check (positiv thinking)
25+
isRePrintable = True
26+
fullFileLocation = fileOrigin + ":/" + filePath
27+
28+
resultPrintJobPrintable["isRePrintable"] = isRePrintable
29+
resultPrintJobPrintable["fullFileLocation"] = fullFileLocation
30+
return resultPrintJobPrintable
31+
32+
33+
34+
35+
def _isFileReadable(fullFileLocation):
36+
result = False
37+
try:
38+
with open(fullFileLocation) as fp:
39+
result = True
40+
except IOError as err:
41+
print ("Error reading the file {0}: {1}".format(fullFileLocation, err))
42+
return result

octoprint_PrintJobHistory/common/SettingsKeys.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SettingsKeys():
2121
SETTINGS_KEY_SELECTED_FILAMENTTRACKER_PLUGIN = "selectedFilamentTrackerPlugin"
2222
KEY_SELECTED_SPOOLMANAGER_PLUGIN = "SpoolManager Plugin" # visible inn plugin-settings
2323
KEY_SELECTED_FILAMENTMANAGER_PLUGIN = "FilamentManager Plugin" # visible inn plugin-settings
24-
KEY_SELECTED_NONE_PLUGIN = "no plugin installed/enabled"
24+
KEY_SELECTED_NONE_PLUGIN = "none"
2525

2626
SETTINGS_KEY_SLICERSETTINGS_KEYVALUE_EXPRESSION = "slicerSettingsKeyValueExpression"
2727

@@ -50,3 +50,6 @@ class SettingsKeys():
5050

5151
## Debugging
5252
SETTINGS_KEY_SQL_LOGGING_ENABLED = "sqlLoggingEnabled"
53+
54+
# Other stuff
55+
SETTINGS_KEY_MESSAGE_CONFIRM_DATA = "messageConfirmData"

octoprint_PrintJobHistory/static/js/PrintJobHistory-APIClient.js

+21
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ function PrintJobHistoryAPIClient(pluginId, baseUrl) {
146146
});
147147
}
148148

149+
// select PrintJob-Item for printing
150+
this.callSelectPrintJobForPrinting = function (databaseId, responseHandler){
151+
$.ajax({
152+
//url: API_BASEURL + "plugin/"+PLUGIN_ID+"/loadPrintJobHistory",
153+
url: this.baseUrl + "plugin/" + this.pluginId + "/selectPrintJobForPrint/" + databaseId,
154+
type: "PUT"
155+
}).done(function( data ){
156+
responseHandler();
157+
});
158+
}
159+
160+
// confirm the message dialog
161+
this.callConfirmMessageDialog = function (){
162+
$.ajax({
163+
url: this.baseUrl + "plugin/"+ this.pluginId +"/confirmMessageDialog",
164+
type: "PUT"
165+
}).done(function( data ){
166+
//responseHandler(data)
167+
});
168+
}
169+
149170
// deactivate the Plugin/Check
150171
this.callDeactivatePluginCheck = function (){
151172
$.ajax({

octoprint_PrintJobHistory/static/js/PrintJobHistory-EditJobDialog.js

+28-2
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,10 @@ function PrintJobHistoryEditDialog(){
183183
});
184184
}
185185

186-
187186
this.closeSlicerSettingsDialog = function(){
188187
self.slicerSettingsDialog.modal('hide');
189188
}
190189

191-
192190
this.isInitialized = function() {
193191
return self.apiClient != null;
194192
}
@@ -265,6 +263,11 @@ function PrintJobHistoryEditDialog(){
265263
calcDuration();
266264
});
267265

266+
self.printJobItemForEdit.isRePrintable.subscribe(function(newValue){
267+
self.tooltipForSelection(self._buildTooltipForSelection());
268+
});
269+
// trigger
270+
self.printJobItemForEdit.isRePrintable.valueHasMutated();
268271

269272
self.editPrintJobItemDialog.modal({
270273
//minHeight: function() { return Math.max($.fn.modal.defaults.maxHeight() - 80, 250); }
@@ -353,6 +356,29 @@ function PrintJobHistoryEditDialog(){
353356
}
354357
}
355358

359+
/////////////////////////////////////////////////////////////////////////////////////////////////// SELECT PRINT JOB
360+
self.tooltipForSelection = ko.observable("");
361+
362+
this.selectForPrinting = function(){
363+
self.apiClient.callSelectPrintJobForPrinting(self.printJobItemForEdit.databaseId(), function(responseData) {
364+
self.editPrintJobItemDialog.modal('hide');
365+
self.closeDialogHandler(true);
366+
});
367+
}
368+
369+
this._buildTooltipForSelection = function(){
370+
var toolTip = "";
371+
if (self.printJobItemForEdit != null ){
372+
var fullPath = self.printJobItemForEdit.fullFileLocation();
373+
if (self.printJobItemForEdit.isRePrintable() == true){
374+
toolTip = "Print file: " + fullPath;
375+
} else {
376+
toolTip = "Selecting not possible! File not found in " + fullPath;
377+
}
378+
}
379+
return toolTip;
380+
};
381+
356382
/////////////////////////////////////////////////////////////////////////////////////////////////// DELETE IMAGE
357383
this.deleteImage = function(){
358384

0 commit comments

Comments
 (0)