Merge branch 'staging/maintenance' into maintenance

This commit is contained in:
Gina Häußge 2017-10-04 15:02:26 +02:00
commit 807b44a35e
18 changed files with 3131 additions and 1163 deletions

View file

@ -22,10 +22,10 @@ maintenance 1.3.6 1a6dbb3f4a5bef857cdeb13c031b9deca2cf30a2 pep440-dev
fix/.* 1.3.6 1a6dbb3f4a5bef857cdeb13c031b9deca2cf30a2 pep440-dev
improve/.* 1.3.6 1a6dbb3f4a5bef857cdeb13c031b9deca2cf30a2 pep440-dev
# staging/maintenance is currently the branch for preparation of 1.3.5rc4
# staging/maintenance is currently the branch for preparation of 1.3.5rc5
# so is regressionfix/...
staging/maintenance 1.3.5rc4 679674df2282af0c4500367fa93864c6defa3802 pep440-dev
regressionfix/.* 1.3.5rc4 679674df2282af0c4500367fa93864c6defa3802 pep440-dev
staging/maintenance 1.3.5rc5 e88e6ba29203757b07a3237a51f1346ab1e5aaae pep440-dev
regressionfix/.* 1.3.5rc5 e88e6ba29203757b07a3237a51f1346ab1e5aaae pep440-dev
# every other branch is a development branch and thus gets resolved to 1.4.0-dev for now
.* 1.4.0 7f5d03d0549bcbd26f40e7e4a3297ea5204fb1cc pep440-dev

View file

@ -1,5 +1,16 @@
# OctoPrint Changelog
## 1.3.5rc4 (2017-10-04)
### Bug fixes
* [#2135](https://github.com/foosel/OctoPrint/issues/2135) - Fix an issue causing import errors inside the GCODE analysis tool in certain environments due to `sys.path` entries causing relative imports.
* [#2136](https://github.com/foosel/OctoPrint/issues/2136) - Fix wrong minimum version for `sockjs-tornado` dependency.
* [#2137](https://github.com/foosel/OctoPrint/issues/2137) - Fix issue with session cookies getting lost when running an OctoPrint instance on a subpath of another (e.g. `octopi.local/` and `octopi.local/octoprint2`).
* [#2140](https://github.com/foosel/OctoPrint/issues/2140) - Fix issue with locale dependent sorting of sub wizards during first time setup causing issues leading to the wizard not being able to complete.
([Commits](https://github.com/foosel/OctoPrint/compare/1.3.5rc3...1.3.5rc4))
## 1.3.5rc3 (2017-08-25)
### Bug fixes

View file

@ -7,7 +7,6 @@ thanks to everyone who contributed!
## Patreon Patrons
* 3D Moniak
* Aaron Lieberman
* Aleph Objects, Inc.
* Andrew Moorby
* Arnljot Arntsen
@ -38,7 +37,6 @@ thanks to everyone who contributed!
* Kaile Riser
* Kale Stedman
* Kazuhiro Ogura
* Lamin Kivelä
* Makespace Madrid
* Marcus Ackermann
* Mark Qvist
@ -57,7 +55,6 @@ thanks to everyone who contributed!
* Roger Strolz
* Roy Cortes
* Samer Najia
* SeeMeCNC
* Simon Hallam
* Stefan Krister
* Stephane Schittly
@ -67,4 +64,4 @@ thanks to everyone who contributed!
* Timeshell.ca
* Trent Shumay
and 1130 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!
and 1121 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel)!

View file

@ -23,7 +23,7 @@ INSTALL_REQUIRES = [
# to some voodoo needed to get large streamed uploads and downloads
# to work that is probably not completely straightforward and therefore
# something for post-1.3.0-stable release
"sockjs-tornado>=1.0.2,<1.1",
"sockjs-tornado>=1.0.3,<1.1",
"PyYAML>=3.10,<3.11",
"Flask-Login>=0.2.2,<0.3",
"Flask-Principal>=0.3.5,<0.4",

View file

@ -0,0 +1,7 @@
#!/usr/bin/env python2
# coding=utf-8
from __future__ import absolute_import, division, print_function
if __name__ == "__main__":
import octoprint
octoprint.main()

View file

@ -135,9 +135,10 @@ from .plugins import plugin_commands
from .dev import dev_commands
from .client import client_commands
from .config import config_commands
from .analysis import analysis_commands
@click.group(name="octoprint", invoke_without_command=True, cls=click.CommandCollection,
sources=[server_commands, plugin_commands, dev_commands, client_commands, config_commands])
sources=[server_commands, plugin_commands, dev_commands, client_commands, config_commands, analysis_commands])
@standard_options()
@legacy_options
@click.version_option(version=octoprint.__version__, allow_from_autoenv=False)

View file

@ -0,0 +1,73 @@
# coding=utf-8
from __future__ import absolute_import, division, print_function
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License"
import click
#~~ "octoprint util" commands
@click.group()
def analysis_commands():
pass
@analysis_commands.group(name="analysis")
def util():
"""Analysis tools."""
pass
@util.command(name="gcode")
@click.option("--throttle", "throttle", type=float, default=None)
@click.option("--throttle-lines", "throttle_lines", type=int, default=None)
@click.option("--speed-x", "speedx", type=float, default=6000)
@click.option("--speed-y", "speedy", type=float, default=6000)
@click.option("--speed-z", "speedz", type=float, default=300)
@click.option("--offset", "offset", type=(float, float), multiple=True)
@click.option("--max-t", "maxt", type=int, default=10)
@click.option("--g90-extruder", "g90_extruder", is_flag=True)
@click.option("--progress", "progress", is_flag=True)
@click.argument("path", type=click.Path())
def gcode_command(path, speedx, speedy, speedz, offset, maxt, throttle, throttle_lines, g90_extruder, progress):
"""Runs a GCODE file analysis."""
import time
import yaml
from octoprint.util.gcodeInterpreter import gcode
throttle_callback = None
if throttle:
def throttle_callback(filePos, readBytes):
if filePos % throttle_lines == 0:
# only apply throttle every $throttle_lines lines
time.sleep(throttle)
offsets = offset
if offsets is None:
offsets = []
elif isinstance(offset, tuple):
offsets = list(offsets)
offsets = [(0, 0)] + offsets
if len(offsets) < maxt:
offsets += [(0, 0)] * (maxt - len(offsets))
start_time = time.time()
progress_callback = None
if progress:
def progress_callback(percentage):
click.echo("PROGRESS:{}".format(percentage))
interpreter = gcode(progress_callback=progress_callback)
interpreter.load(path,
speedx=speedx,
speedy=speedy,
offsets=offsets,
throttle=throttle_callback,
max_extruders=maxt,
g90_extruder=g90_extruder)
click.echo("DONE:{}s".format(time.time() - start_time))
click.echo("RESULTS:")
click.echo(yaml.safe_dump(interpreter.get_result(), default_flow_style=False, indent=" ", allow_unicode=True))

View file

@ -324,8 +324,8 @@ class GcodeAnalysisQueue(AbstractAnalysisQueue):
speedy = self._current.printer_profile["axes"]["y"]["speed"]
offsets = self._current.printer_profile["extruder"]["offsets"]
interpreter = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "util", "gcodeInterpreter.py"))
command = [sys.executable, interpreter, "--speed-x={}".format(speedx), "--speed-y={}".format(speedy),
command = [sys.executable, "-m", "octoprint", "analysis", "gcode",
"--speed-x={}".format(speedx), "--speed-y={}".format(speedy),
"--max-t={}".format(max_extruders), "--throttle={}".format(throttle),
"--throttle-lines={}".format(throttle_lines)]
for offset in offsets[1:]:

View file

@ -44,7 +44,11 @@ class CoreWizardPlugin(octoprint.plugin.AssetPlugin,
if not name:
continue
config = dict(type="wizard", name=name, template="corewizard_{}_wizard.jinja2".format(key), div="wizard_plugin_corewizard_{}".format(key))
config = dict(type="wizard",
name=name,
template="corewizard_{}_wizard.jinja2".format(key),
div="wizard_plugin_corewizard_{}".format(key),
suffix="_{}".format(key))
if key in additional:
additional_result = additional[key]()
if additional_result:

View file

@ -455,9 +455,12 @@ class OctoPrintFlaskRequest(flask.Request):
We need this because cookies are not port-specific and we don't want to overwrite our
session and other cookies from one OctoPrint instance on our machine with those of another
one who happens to listen on the same address albeit a different port.
one who happens to listen on the same address albeit a different port or script root.
"""
return "_P" + self.server_port
result = "_P" + self.server_port
if self.script_root:
return result + "_R" + self.script_root.replace("/", "|")
return result
class OctoPrintFlaskResponse(flask.Response):

View file

@ -461,13 +461,26 @@ def _process_templates():
)
# sorting orders
def wizard_key_extractor(d, k):
if d[1].get("_key", None) == "plugin_corewizard_acl":
# Ultra special case - we MUST always have the ACL wizard first since otherwise any steps that follow and
# that require to access APIs to function will run into errors since those APIs won't work before ACL
# has been configured. See also #2140
return u"0:{}".format(to_unicode(d[0]))
elif d[1].get("mandatory", False):
# Other mandatory steps come before the optional ones
return u"1:{}".format(to_unicode(d[0]))
else:
# Finally everything else
return u"2:{}".format(to_unicode(d[0]))
template_sorting = dict(
navbar=dict(add="prepend", key=None),
sidebar=dict(add="append", key="name"),
tab=dict(add="append", key="name"),
settings=dict(add="custom_append", key="name", custom_add_entries=lambda missing: dict(section_plugins=(gettext("Plugins"), None)), custom_add_order=lambda missing: ["section_plugins"] + missing),
usersettings=dict(add="append", key="name"),
wizard=dict(add="append", key="name", key_extractor=lambda d, k: u"0:{}".format(to_unicode(d[0])) if "mandatory" in d[1] and d[1]["mandatory"] else u"1:{}".format(to_unicode(d[0]))),
wizard=dict(add="append", key="name", key_extractor=wizard_key_extractor),
about=dict(add="append", key="name"),
generic=dict(add="append", key=None)
)

File diff suppressed because it is too large Load diff

View file

@ -512,85 +512,3 @@ def getCodeFloat(line, code):
except:
return None
if __name__ == "__main__":
import click
import time
import yaml
import sys
@click.command()
@click.option("--throttle", "throttle", type=float, default=None)
@click.option("--throttle-lines", "throttle_lines", type=int, default=None)
@click.option("--speed-x", "speedx", type=float, default=6000)
@click.option("--speed-y", "speedy", type=float, default=6000)
@click.option("--speed-z", "speedz", type=float, default=300)
@click.option("--offset", "offset", type=(float, float), multiple=True)
@click.option("--max-t", "maxt", type=int, default=10)
@click.option("--g90-extruder", "g90_extruder", is_flag=True)
@click.option("--progress", "progress", is_flag=True)
@click.argument("path", type=click.Path())
def main(path, speedx, speedy, speedz, offset, maxt, throttle, throttle_lines, g90_extruder, progress):
throttle_callback = None
if throttle:
def throttle_callback(filePos, readBytes):
if filePos % throttle_lines == 0:
# only apply throttle every $throttle_lines lines
time.sleep(throttle)
offsets = offset
if offsets is None:
offsets = []
elif isinstance(offset, tuple):
offsets = list(offsets)
offsets = [(0, 0)] + offsets
if len(offsets) < maxt:
offsets += [(0, 0)] * (maxt - len(offsets))
start_time = time.time()
progress_callback = None
if progress:
def progress_callback(percentage):
print("PROGRESS:{}".format(percentage))
interpreter = gcode(progress_callback=progress_callback)
interpreter.load(path,
speedx=speedx,
speedy=speedy,
offsets=offsets,
throttle=throttle_callback,
max_extruders=maxt,
g90_extruder=g90_extruder)
print("DONE:{}s".format(time.time() - start_time))
print("RESULTS:")
print(yaml.safe_dump(interpreter.get_result(), default_flow_style=False, indent=" ", allow_unicode=True))
# os args are gained differently on win32
try:
from click.utils import get_os_args
args = get_os_args()
except ImportError:
# for whatever reason we are running an older Click version?
args = sys.argv[1:]
if len(args) >= len(sys.argv):
# Now some ugly preprocessing of our arguments starts. We have a somewhat difficult situation on our hands
# here if we are running under Windows and want to be able to handle utf-8 command line parameters (think
# plugin parameters such as names or something, e.g. for the "dev plugin:new" command) while at the same
# time also supporting sys.argv rewriting for debuggers etc (e.g. PyCharm).
#
# So what we try to do here is solve this... Generally speaking, sys.argv and whatever Windows returns
# for its CommandLineToArgvW win32 function should have the same length. If it doesn't however and
# sys.argv is shorter than the win32 specific command line arguments, obviously stuff was cut off from
# sys.argv which also needs to be cut off of the win32 command line arguments.
#
# So this is what we do here.
# -1 because first entry is the script that was called
sys_args_length = len(sys.argv) - 1
# cut off stuff from the beginning
args = args[-1 * sys_args_length:] if sys_args_length else []
main(args=args, prog_name="octoprint-gcode-analysis")

View file

@ -530,6 +530,13 @@ class OctoPrintFlaskRequestTest(unittest.TestCase):
def test_cookie_suffix(self):
request = OctoPrintFlaskRequest(standard_environ)
self.assertEquals("_P5000", request.cookie_suffix)
def test_cookie_suffix_with_root(self):
script_root_environ = dict(standard_environ)
script_root_environ["SCRIPT_NAME"] = "/path/to/octoprint"
request = OctoPrintFlaskRequest(script_root_environ)
self.assertEquals("_P5000_R|path|to|octoprint", request.cookie_suffix)
def test_cookies(self):
environ = dict(standard_environ)
@ -561,8 +568,10 @@ class OctoPrintFlaskResponseTest(unittest.TestCase):
def test_cookie_set_and_delete(self, path, scriptroot):
environ = dict(standard_environ)
expected_suffix = "_P5000"
if scriptroot is not None:
environ.update(dict(SCRIPT_NAME=scriptroot))
expected_suffix += "_R" + scriptroot.replace("/", "|")
request = OctoPrintFlaskRequest(environ)
@ -586,7 +595,7 @@ class OctoPrintFlaskResponseTest(unittest.TestCase):
response.set_cookie("some_key", "some_value", **kwargs)
# set_cookie should have key and path values adjusted
set_cookie_mock.assert_called_once_with(response, "some_key_P5000", "some_value", path=expected_path_set)
set_cookie_mock.assert_called_once_with(response, "some_key" + expected_suffix, "some_value", path=expected_path_set)
# test delete_cookie
with mock.patch("flask.Response.set_cookie") as set_cookie_mock:

File diff suppressed because it is too large Load diff

View file

@ -6,16 +6,16 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: OctoPrint 1.3.5.dev136+g10e834f.dirty\n"
"Project-Id-Version: OctoPrint 1.3.5rc4.dev6+g25c56a54\n"
"Report-Msgid-Bugs-To: i18n@octoprint.org\n"
"POT-Creation-Date: 2017-07-26 12:30+0200\n"
"POT-Creation-Date: 2017-10-04 13:18+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.3.4\n"
"Generated-By: Babel 2.5.1\n"
#: src/octoprint/plugins/announcements/__init__.py:126
#: src/octoprint/plugins/announcements/templates/announcements.jinja2:4
@ -105,31 +105,31 @@ msgstr ""
msgid "Refresh Announcements"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:95
#: src/octoprint/plugins/corewizard/__init__.py:108
#: src/octoprint/plugins/corewizard/templates/corewizard_acl_wizard.jinja2:1
#: src/octoprint/server/views.py:559
#: src/octoprint/server/views.py:573
msgid "Access Control"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:143
#: src/octoprint/server/views.py:553
#: src/octoprint/plugins/corewizard/__init__.py:156
#: src/octoprint/server/views.py:567
msgid "Webcam & Timelapse"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:161
#: src/octoprint/plugins/corewizard/__init__.py:174
#: src/octoprint/plugins/corewizard/templates/corewizard_servercommands_wizard.jinja2:1
msgid "Server Commands"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:175
#: src/octoprint/plugins/corewizard/__init__.py:188
msgid "Online connectivity check"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:192
#: src/octoprint/plugins/corewizard/__init__.py:205
msgid "Default Printer Profile"
msgstr ""
#: src/octoprint/plugins/corewizard/__init__.py:218
#: src/octoprint/plugins/corewizard/__init__.py:231
msgid ""
"Without this plugin OctoPrint will no longer be able to perform setup "
"steps that might be required after an update."
@ -1325,7 +1325,7 @@ msgid "Software Update"
msgstr ""
#: src/octoprint/plugins/softwareupdate/__init__.py:964
#: src/octoprint/server/views.py:557
#: src/octoprint/server/views.py:571
#: src/octoprint/static/js/app/viewmodels/appearance.js:13
#: src/octoprint/static/js/app/viewmodels/appearance.js:18
#: src/octoprint/static/js/app/viewmodels/appearance.js:20
@ -1674,113 +1674,113 @@ msgstr ""
msgid "OctoPrint version tracking"
msgstr ""
#: src/octoprint/server/views.py:467
#: src/octoprint/server/views.py:481
msgid "Plugins"
msgstr ""
#: src/octoprint/server/views.py:524
#: src/octoprint/server/views.py:538
msgid "Connection"
msgstr ""
#: src/octoprint/server/views.py:525
#: src/octoprint/server/views.py:539
#: src/octoprint/templates/sidebar/state.jinja2:1
msgid "State"
msgstr ""
#: src/octoprint/server/views.py:526
#: src/octoprint/server/views.py:540
msgid "Files"
msgstr ""
#: src/octoprint/server/views.py:532
#: src/octoprint/server/views.py:546
msgid "Temperature"
msgstr ""
#: src/octoprint/server/views.py:533
#: src/octoprint/server/views.py:547
msgid "Control"
msgstr ""
#: src/octoprint/server/views.py:534
#: src/octoprint/server/views.py:548
msgid "GCode Viewer"
msgstr ""
#: src/octoprint/server/views.py:535
#: src/octoprint/server/views.py:549
msgid "Terminal"
msgstr ""
#: src/octoprint/server/views.py:536
#: src/octoprint/server/views.py:550
#: src/octoprint/templates/sidebar/state.jinja2:4
msgid "Timelapse"
msgstr ""
#: src/octoprint/server/views.py:542
#: src/octoprint/server/views.py:556
msgid "Printer"
msgstr ""
#: src/octoprint/server/views.py:544
#: src/octoprint/server/views.py:558
msgid "Serial Connection"
msgstr ""
#: src/octoprint/server/views.py:545
#: src/octoprint/server/views.py:559
#: src/octoprint/templates/dialogs/settings/printerprofiles.jinja2:1
msgid "Printer Profiles"
msgstr ""
#: src/octoprint/server/views.py:546
#: src/octoprint/server/views.py:560
msgid "Temperatures"
msgstr ""
#: src/octoprint/server/views.py:547
#: src/octoprint/server/views.py:561
msgid "Terminal Filters"
msgstr ""
#: src/octoprint/server/views.py:548
#: src/octoprint/server/views.py:562
msgid "GCODE Scripts"
msgstr ""
#: src/octoprint/server/views.py:550 src/octoprint/server/views.py:552
#: src/octoprint/server/views.py:564 src/octoprint/server/views.py:566
msgid "Features"
msgstr ""
#: src/octoprint/server/views.py:554
#: src/octoprint/server/views.py:568
msgid "GCODE Visualizer"
msgstr ""
#: src/octoprint/server/views.py:555
#: src/octoprint/server/views.py:569
msgid "API"
msgstr ""
#: src/octoprint/server/views.py:560
#: src/octoprint/server/views.py:574
#: src/octoprint/templates/dialogs/settings/folders.jinja2:2
#: src/octoprint/templates/sidebar/files_header.jinja2:10
msgid "Folders"
msgstr ""
#: src/octoprint/server/views.py:561
#: src/octoprint/server/views.py:575
msgid "Appearance"
msgstr ""
#: src/octoprint/server/views.py:562
#: src/octoprint/server/views.py:576
#: src/octoprint/templates/dialogs/settings/logs.jinja2:2
msgid "Logs"
msgstr ""
#: src/octoprint/server/views.py:563
#: src/octoprint/server/views.py:577
msgid "Server"
msgstr ""
#: src/octoprint/server/views.py:569
#: src/octoprint/server/views.py:583
msgid "Access"
msgstr ""
#: src/octoprint/server/views.py:570
#: src/octoprint/server/views.py:584
msgid "Interface"
msgstr ""
#: src/octoprint/server/views.py:586
#: src/octoprint/server/views.py:600
msgid "Start"
msgstr ""
#: src/octoprint/server/views.py:587
#: src/octoprint/server/views.py:601
#: src/octoprint/templates/dialogs/wizard.jinja2:57
msgid "Finish"
msgstr ""
@ -2028,14 +2028,14 @@ msgstr ""
#: src/octoprint/static/js/app/viewmodels/control.js:72
#: src/octoprint/static/js/app/viewmodels/files.js:604
#: src/octoprint/static/js/app/viewmodels/gcode.js:508
#: src/octoprint/static/js/app/viewmodels/gcode.js:530
#: src/octoprint/static/js/app/viewmodels/printerstate.js:234
#: src/octoprint/static/js/app/viewmodels/temperature.js:115
#: src/octoprint/static/js/app/viewmodels/temperature.js:126
msgid "Tool"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/control.js:78
#: src/octoprint/static/js/app/viewmodels/temperature.js:126
msgid "Hotend"
msgstr ""
@ -2059,19 +2059,19 @@ msgid ""
msgstr ""
#: src/octoprint/static/js/app/viewmodels/files.js:593
#: src/octoprint/static/js/app/viewmodels/gcode.js:467
#: src/octoprint/static/js/app/viewmodels/gcode.js:489
msgid "Model size"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/files.js:599
#: src/octoprint/static/js/app/viewmodels/files.js:604
#: src/octoprint/static/js/app/viewmodels/gcode.js:505
#: src/octoprint/static/js/app/viewmodels/gcode.js:508
#: src/octoprint/static/js/app/viewmodels/gcode.js:527
#: src/octoprint/static/js/app/viewmodels/gcode.js:530
msgid "Filament"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/files.js:608
#: src/octoprint/static/js/app/viewmodels/gcode.js:512
#: src/octoprint/static/js/app/viewmodels/gcode.js:534
msgid "Estimated print time"
msgstr ""
@ -2182,40 +2182,40 @@ msgstr ""
msgid "Analyzed"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:468
#: src/octoprint/static/js/app/viewmodels/gcode.js:490
msgid "Estimated total print time"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:469
#: src/octoprint/static/js/app/viewmodels/gcode.js:491
msgid "Estimated layer height"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:469
#: src/octoprint/static/js/app/viewmodels/gcode.js:491
#: src/octoprint/templates/tabs/timelapse.jinja2:46
msgid "mm"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:470
#: src/octoprint/static/js/app/viewmodels/gcode.js:492
msgid "Layer count"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:470
#: src/octoprint/static/js/app/viewmodels/gcode.js:492
msgid "printed"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:470
#: src/octoprint/static/js/app/viewmodels/gcode.js:492
msgid "visited"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:500
#: src/octoprint/static/js/app/viewmodels/gcode.js:522
msgid "Layer number"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:501
#: src/octoprint/static/js/app/viewmodels/gcode.js:523
msgid "Layer height"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/gcode.js:502
#: src/octoprint/static/js/app/viewmodels/gcode.js:524
msgid "GCODE commands"
msgstr ""
@ -2570,21 +2570,21 @@ msgstr ""
msgid "Bed"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/temperature.js:317
#: src/octoprint/static/js/app/viewmodels/temperature.js:318
#: src/octoprint/templates/tabs/temperature.jinja2:11
msgid "Actual"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/temperature.js:322
#: src/octoprint/static/js/app/viewmodels/temperature.js:323
#: src/octoprint/templates/tabs/temperature.jinja2:12
msgid "Target"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/temperature.js:354
#: src/octoprint/static/js/app/viewmodels/temperature.js:355
msgid "just now"
msgstr ""
#: src/octoprint/static/js/app/viewmodels/temperature.js:356
#: src/octoprint/static/js/app/viewmodels/temperature.js:357
msgid "min"
msgstr ""