From 30ae36d91ed8a91bb9d01322b4188e9c88463e4e Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 26 May 2021 10:55:53 -0400 Subject: [PATCH 01/13] Desktop mode, share button hiding --- app/static/app/js/MapView.jsx | 7 +++++-- app/static/app/js/ModelView.jsx | 8 +++++--- app/static/app/js/components/Map.jsx | 8 +++++--- app/views/app.py | 6 ++++-- app/views/public.py | 7 +++++-- package.json | 2 +- webodm/settings.py | 5 +++++ 7 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/static/app/js/MapView.jsx b/app/static/app/js/MapView.jsx index 77bcfbab..e17eaa75 100644 --- a/app/static/app/js/MapView.jsx +++ b/app/static/app/js/MapView.jsx @@ -10,14 +10,16 @@ class MapView extends React.Component { mapItems: [], selectedMapType: 'orthophoto', title: "", - public: false + public: false, + shareButtons: true }; static propTypes = { mapItems: PropTypes.array.isRequired, // list of dictionaries where each dict is a {mapType: 'orthophoto', url: }, selectedMapType: PropTypes.oneOf(['orthophoto', 'plant', 'dsm', 'dtm']), title: PropTypes.string, - public: PropTypes.bool + public: PropTypes.bool, + shareButtons: PropTypes.bool }; constructor(props){ @@ -106,6 +108,7 @@ class MapView extends React.Component { showBackground={true} mapType={this.state.selectedMapType} public={this.props.public} + shareButtons={this.props.shareButtons} /> ); diff --git a/app/static/app/js/ModelView.jsx b/app/static/app/js/ModelView.jsx index f19a3880..709135e8 100644 --- a/app/static/app/js/ModelView.jsx +++ b/app/static/app/js/ModelView.jsx @@ -75,12 +75,14 @@ class CamerasMenu extends React.Component{ class ModelView extends React.Component { static defaultProps = { task: null, - public: false + public: false, + shareButtons: true }; static propTypes = { task: PropTypes.object.isRequired, // The object should contain two keys: {id: , project: } - public: PropTypes.bool // Is the view being displayed via a shared link? + public: PropTypes.bool, // Is the view being displayed via a shared link? + shareButtons: PropTypes.bool }; constructor(props){ @@ -499,7 +501,7 @@ class ModelView extends React.Component { direction="up" showLabel={false} buttonClass="btn-secondary" /> - {(!this.props.public) ? + {(this.props.shareButtons && !this.props.public) ? { this.shareButton = ref; }} task={this.props.task} diff --git a/app/static/app/js/components/Map.jsx b/app/static/app/js/components/Map.jsx index 6201b5d6..c1d7bdd6 100644 --- a/app/static/app/js/components/Map.jsx +++ b/app/static/app/js/components/Map.jsx @@ -32,14 +32,16 @@ class Map extends React.Component { static defaultProps = { showBackground: false, mapType: "orthophoto", - public: false + public: false, + shareButtons: true }; static propTypes = { showBackground: PropTypes.bool, tiles: PropTypes.array.isRequired, mapType: PropTypes.oneOf(['orthophoto', 'plant', 'dsm', 'dtm']), - public: PropTypes.bool + public: PropTypes.bool, + shareButtons: PropTypes.bool }; constructor(props) { @@ -536,7 +538,7 @@ _('Example:'),
{this.state.pluginActionButtons.map((button, i) =>
{button}
)} - {(!this.props.public && this.state.singleTask !== null) ? + {(this.props.shareButtons && !this.props.public && this.state.singleTask !== null) ? { this.shareButton = ref; }} task={this.state.singleTask} diff --git a/app/views/app.py b/app/views/app.py index e7bd3ec8..f9aeff69 100644 --- a/app/views/app.py +++ b/app/views/app.py @@ -71,7 +71,8 @@ def map(request, project_pk=None, task_pk=None): 'params': { 'map-items': json.dumps(mapItems), 'title': title, - 'public': 'false' + 'public': 'false', + 'share-buttons': 'false' if settings.DESKTOP_MODE else 'true' }.items() }) @@ -95,7 +96,8 @@ def model_display(request, project_pk=None, task_pk=None): 'title': title, 'params': { 'task': json.dumps(task.get_model_display_params()), - 'public': 'false' + 'public': 'false', + 'share-buttons': 'false' if settings.DESKTOP_MODE else 'true' }.items() }) diff --git a/app/views/public.py b/app/views/public.py index f0df5531..37ec67aa 100644 --- a/app/views/public.py +++ b/app/views/public.py @@ -8,6 +8,7 @@ from django.shortcuts import render from app.api.tasks import TaskSerializer from app.models import Task from django.views.decorators.csrf import ensure_csrf_cookie +from webodm import settings def get_public_task(task_pk): """ @@ -27,7 +28,8 @@ def handle_map(request, template, task_pk=None, hide_title=False): 'params': { 'map-items': json.dumps([task.get_map_items()]), 'title': task.name if not hide_title else '', - 'public': 'true' + 'public': 'true', + 'share-buttons': 'false' if settings.DESKTOP_MODE else 'true' }.items() }) @@ -45,7 +47,8 @@ def handle_model_display(request, template, task_pk=None): 'title': task.name, 'params': { 'task': json.dumps(task.get_model_display_params()), - 'public': 'true' + 'public': 'true', + 'share-buttons': 'false' if settings.DESKTOP_MODE else 'true' }.items() }) diff --git a/package.json b/package.json index bbca5926..fe1b0cc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WebODM", - "version": "1.8.3", + "version": "1.8.4", "description": "User-friendly, extendable application and API for processing aerial imagery.", "main": "index.js", "scripts": { diff --git a/webodm/settings.py b/webodm/settings.py index 23b6577c..4dfa0494 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -68,6 +68,11 @@ SINGLE_USER_MODE = False # URL to redirect to if there are no processing nodes when visiting the dashboard PROCESSING_NODES_ONBOARDING = None +# Enable desktop mode. In desktop mode some styling changes +# are applied to make the application look nicer on desktop +# as well as disabling certain features (e.g. sharing) +DESKTOP_MODE = False + # Default CSS to add to theme DEFAULT_THEME_CSS = '' From b05cceaa047c146a19b3061b05f2dd5039a9fff2 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 26 May 2021 12:18:33 -0400 Subject: [PATCH 02/13] no need to create symlink to pip --- Dockerfile | 1 - app/static/app/css/main.scss | 4 ++++ app/templates/app/base.html | 19 +++++++++++++++++++ app/templatetags/settings.py | 4 ++++ webodm/settings.py | 2 +- 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 228d8b19..a8d71c31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,6 @@ RUN apt-get -qq update && apt-get -qq install -y nodejs # Install Python3, GDAL, nginx, letsencrypt, psql RUN apt-get -qq update && apt-get -qq install -y --no-install-recommends python3 python3-pip python3-setuptools python3-wheel git g++ python3-dev python2.7-dev libpq-dev binutils libproj-dev gdal-bin python3-gdal nginx certbot grass-core gettext-base cron postgresql-client-12 gettext RUN update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1 && update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2 -RUN ln -s /usr/bin/pip3 /usr/bin/pip && pip install -U pip # Install pip reqs ADD requirements.txt /webodm/ diff --git a/app/static/app/css/main.scss b/app/static/app/css/main.scss index 8c171e55..657090ca 100644 --- a/app/static/app/css/main.scss +++ b/app/static/app/css/main.scss @@ -84,6 +84,10 @@ html, body, section.main, .content, #wrapper, #page-wrapper{ } } + .sidebar-nav.navbar-collapse{ + width: 100%; + } + .navbar-top-links li a.dropdown-toggle{ height: 50px; } diff --git a/app/templates/app/base.html b/app/templates/app/base.html index 97286216..3371d673 100644 --- a/app/templates/app/base.html +++ b/app/templates/app/base.html @@ -55,6 +55,18 @@ {% endcompress %} + {% is_desktop_mode as desktop_mode %} + {% if desktop_mode %} + + + {% endif %} + @@ -97,11 +109,18 @@ $(function(){ $('#side-menu').metisMenu(); $(window).bind("load resize", function() { + {% if desktop_mode %} + var topOffset = 0; + {% else %} var topOffset = 50; + {% endif %} + var width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width; if (width < 768) { $('div.navbar-collapse').addClass('collapse'); + {% if not desktop_mode %} topOffset = 100; // 2-row-menu + {% endif %} } else { $('div.navbar-collapse').removeClass('collapse'); } diff --git a/app/templatetags/settings.py b/app/templatetags/settings.py index c640860d..7bda2e18 100644 --- a/app/templatetags/settings.py +++ b/app/templatetags/settings.py @@ -11,6 +11,10 @@ logger = logging.getLogger('app.logger') def is_single_user_mode(): return settings.SINGLE_USER_MODE +@register.simple_tag +def is_desktop_mode(): + return settings.DESKTOP_MODE + @register.simple_tag def is_dev_mode(): return settings.DEV diff --git a/webodm/settings.py b/webodm/settings.py index 4dfa0494..5c8ad93c 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -71,7 +71,7 @@ PROCESSING_NODES_ONBOARDING = None # Enable desktop mode. In desktop mode some styling changes # are applied to make the application look nicer on desktop # as well as disabling certain features (e.g. sharing) -DESKTOP_MODE = False +DESKTOP_MODE = True # Default CSS to add to theme DEFAULT_THEME_CSS = '' From a19cc6260a0e6d9ea58b6702ebfa8863ce50c54a Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 26 May 2021 12:19:37 -0400 Subject: [PATCH 03/13] Desktop mode false by default --- webodm/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webodm/settings.py b/webodm/settings.py index 5c8ad93c..4dfa0494 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -71,7 +71,7 @@ PROCESSING_NODES_ONBOARDING = None # Enable desktop mode. In desktop mode some styling changes # are applied to make the application look nicer on desktop # as well as disabling certain features (e.g. sharing) -DESKTOP_MODE = True +DESKTOP_MODE = False # Default CSS to add to theme DEFAULT_THEME_CSS = '' From d286c72a2493606f439089f8ad4e3659bb500765 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 26 May 2021 16:01:52 -0400 Subject: [PATCH 04/13] Started refactoring some scripts to be python based --- Dockerfile | 4 +- app/boot.py | 7 +- app/management/commands/rebuildplugins.py | 25 +++ app/management/commands/translate.py | 43 +++++ app/scripts/__init__.py | 0 app/scripts/extract_odm_strings.py | 128 +++++++-------- .../extract_plugin_manifest_strings.py | 56 ++++--- app/scripts/extract_potree_strings.py | 52 +++--- app/scripts/plugin_cleanup.sh | 8 - .../app/js/translations/odm_autogenerated.js | 150 +++++++++--------- start.sh | 2 +- 11 files changed, 275 insertions(+), 200 deletions(-) create mode 100644 app/management/commands/rebuildplugins.py create mode 100644 app/management/commands/translate.py create mode 100644 app/scripts/__init__.py delete mode 100755 app/scripts/plugin_cleanup.sh diff --git a/Dockerfile b/Dockerfile index a8d71c31..fcd21b35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,8 +39,8 @@ WORKDIR /webodm RUN npm install --quiet -g webpack@4.16.5 && npm install --quiet -g webpack-cli@4.2.0 && npm install --quiet && webpack --mode production RUN echo "UTC" > /etc/timezone RUN python manage.py collectstatic --noinput -RUN bash app/scripts/plugin_cleanup.sh && echo "from app.plugins import build_plugins;build_plugins()" | python manage.py shell -RUN bash translate.sh build safe +RUN python manage.py rebuildplugins +RUN python manage.py translate build --safe # Cleanup RUN apt-get remove -y g++ python3-dev libpq-dev && apt-get autoremove -y diff --git a/app/boot.py b/app/boot.py index 197afdfc..b3b15bf2 100644 --- a/app/boot.py +++ b/app/boot.py @@ -1,4 +1,5 @@ import os +import sys import kombu from django.contrib.auth.models import Permission @@ -82,8 +83,10 @@ def boot(): s.app_logo.save(os.path.basename(settings.APP_DEFAULT_LOGO), File(open(settings.APP_DEFAULT_LOGO, 'rb'))) logger.info("Created settings") - - init_plugins() + + # Invoked via manage.py + if len(sys.argv[1:2]) > 0 and not settings.TESTING: + init_plugins() if not settings.TESTING: try: diff --git a/app/management/commands/rebuildplugins.py b/app/management/commands/rebuildplugins.py new file mode 100644 index 00000000..973a938f --- /dev/null +++ b/app/management/commands/rebuildplugins.py @@ -0,0 +1,25 @@ +import os +import shutil +import glob +from django.core.management.base import BaseCommand +from app.plugins import build_plugins + +def cleanup(): + # Delete all node_modules and build directories within plugins' public/ folders + root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..")) + for d in glob.glob(os.path.join(root, "plugins", "**", "public", "node_modules")): + shutil.rmtree(d) + print("R\t" + d) + for d in glob.glob(os.path.join(root, "plugins", "**", "public", "build")): + shutil.rmtree(d) + print("R\t" + d) + + print("Cleanup done!") + +class Command(BaseCommand): + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + + def handle(self, **options): + cleanup() + build_plugins() \ No newline at end of file diff --git a/app/management/commands/translate.py b/app/management/commands/translate.py new file mode 100644 index 00000000..45c306b8 --- /dev/null +++ b/app/management/commands/translate.py @@ -0,0 +1,43 @@ +import os +from django.core.management.base import BaseCommand +from django.core.management import call_command + +from app.scripts.extract_odm_strings import extract_odm_strings +from app.scripts.extract_plugin_manifest_strings import extract_plugin_manifest_strings +from app.scripts.extract_potree_strings import extract_potree_strings + +root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..")) + +class Command(BaseCommand): + def add_arguments(self, parser): + parser.add_argument("action", type=str, choices=['extract', 'build']) + parser.add_argument("--safe", type=bool, required=False, help="Skip invalid languages") + super(Command, self).add_arguments(parser) + + def handle(self, **options): + with open(os.path.join(root, "LOCALES")) as f: + locales = f.read().strip().split(" ") + + if options.get('action') == 'extract': + print("Extracting .po files from Django/React") + locale_params = ["--locale=%s" % l for l in locales] + + locale_dir = os.path.join(root, "locale") + if not os.path.exists(locale_dir): + os.mkdir(locale_dir) + + extract_potree_strings( + os.path.join(root, "app", "static", "app", "js", "vendor", "potree", "build", "potree", "resources", "lang", "en", "translation.json"), + os.path.join(root, "app", "static", "app", "js", "translations", "potree_autogenerated.js") + ) + extract_odm_strings( + "https://raw.githubusercontent.com/OpenDroneMap/ODM/master/opendm/config.py", + os.path.join(root, "app", "static", "app", "js", "translations", "odm_autogenerated.js") + ) + extract_plugin_manifest_strings( + os.path.join(root, "plugins"), + os.path.join(root, "app", "translations", "plugin_manifest_autogenerated.py") + ) + + call_command('makemessages', '--keep-pot', *locale_params, '--ignore=build', '--ignore=app/templates/app/registration/*') + call_command('makemessages_djangojs', '--keep-pot', *locale_params, '-d=djangojs', '--extension=jsx', '--extension=js', '--ignore=build', '--ignore=app/static/app/js/vendor', '--ignore=app/static/app/bundles', '--ignore=node_modules', '--language=Python') \ No newline at end of file diff --git a/app/scripts/__init__.py b/app/scripts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/scripts/extract_odm_strings.py b/app/scripts/extract_odm_strings.py index e07dabaa..88546be6 100644 --- a/app/scripts/extract_odm_strings.py +++ b/app/scripts/extract_odm_strings.py @@ -3,52 +3,6 @@ import argparse, os, urllib.request, ast, sys from io import StringIO -parser = argparse.ArgumentParser(description='Extract ODM strings.') -parser.add_argument('input', type=str, - help='URL to ODM\'s config.py') -parser.add_argument('output', type=str, - help='Where to write resulting translation file') -args = parser.parse_args() - -url = args.input -outfile = args.output - -strings = [] -print("Fetching %s ..." % url) -res = urllib.request.urlopen(url) -config_file = res.read().decode('utf-8') -# config_file = open("test.py").read() - -options = {} -class ArgumentParserStub(argparse.ArgumentParser): - def add_argument(self, *args, **kwargs): - argparse.ArgumentParser.add_argument(self, *args, **kwargs) - options[args[0]] = {} - for name, value in kwargs.items(): - options[args[0]][str(name)] = str(value) - - def add_mutually_exclusive_group(self): - return ArgumentParserStub() - -# Voodoo! :) -# ( parse AST, extract "def config()" function, set module to only -# contain that function, execute module in current scope, -# run config function) -root = ast.parse(config_file) -new_body = [] -for stmt in root.body: - # Assignments - if hasattr(stmt, 'targets'): - new_body.append(stmt) - - # Functions - elif hasattr(stmt, 'name'): - new_body.append(stmt) - -root.body = new_body -exec(compile(root, filename="", mode="exec")) - - # Misc variables needed to get config to run __version__ = '?' class context: @@ -63,22 +17,72 @@ class log: def ODM_ERROR(s): pass -config(["--project-path", "/bogus", "name"], parser=ArgumentParserStub()) -for opt in options: - h = options[opt].get('help') - if h: - h = h.replace("\n", "") - strings.append(h) +def extract_odm_strings(url, outfile): + strings = [] + print("Fetching %s ..." % url) + res = urllib.request.urlopen(url) + config_file = res.read().decode('utf-8') + # config_file = open("test.py").read() -strings = list(set(strings)) -print("Found %s ODM strings" % len(strings)) -if len(strings) > 0: - with open(outfile, "w") as f: - f.write("// Auto-generated with extract_odm_strings.py, do not edit!\n\n") + options = {} + class ArgumentParserStub(argparse.ArgumentParser): + def add_argument(self, *args, **kwargs): + argparse.ArgumentParser.add_argument(self, *args, **kwargs) + options[args[0]] = {} + for name, value in kwargs.items(): + options[args[0]][str(name)] = str(value) + + def add_mutually_exclusive_group(self): + return ArgumentParserStub() - for s in strings: - f.write("_(\"%s\");\n" % s.replace("\"", "\\\"")) + # Voodoo! :) + # ( parse AST, extract "def config()" function, set module to only + # contain that function, execute module in current scope, + # run config function) + root = ast.parse(config_file) + new_body = [] + for stmt in root.body: + # Assignments + if hasattr(stmt, 'targets'): + new_body.append(stmt) - print("Wrote %s" % outfile) -else: - print("No strings found") \ No newline at end of file + # Functions + elif hasattr(stmt, 'name'): + new_body.append(stmt) + + root.body = new_body + exec(compile(root, filename="", mode="exec"), globals()) + + + + config(["--project-path", "/bogus", "name"], parser=ArgumentParserStub()) + for opt in options: + h = options[opt].get('help') + if h: + h = h.replace("\n", "") + strings.append(h) + + strings = list(set(strings)) + print("Found %s ODM strings" % len(strings)) + if len(strings) > 0: + with open(outfile, "w") as f: + f.write("// Auto-generated with extract_odm_strings.py, do not edit!\n\n") + + for s in strings: + f.write("_(\"%s\");\n" % s.replace("\"", "\\\"")) + + print("Wrote %s" % outfile) + else: + print("No strings found") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Extract ODM strings.') + parser.add_argument('input', type=str, + help='URL to ODM\'s config.py') + parser.add_argument('output', type=str, + help='Where to write resulting translation file') + args = parser.parse_args() + + url = args.input + outfile = args.output \ No newline at end of file diff --git a/app/scripts/extract_plugin_manifest_strings.py b/app/scripts/extract_plugin_manifest_strings.py index 7504b792..9f545a00 100644 --- a/app/scripts/extract_plugin_manifest_strings.py +++ b/app/scripts/extract_plugin_manifest_strings.py @@ -1,33 +1,37 @@ #!/usr/bin/python3 -import argparse, json, os, glob +import json, os, glob -parser = argparse.ArgumentParser(description='Extract plugin manifest strings.') -parser.add_argument('input', type=str, - help='Path to plugins directory') -parser.add_argument('output', type=str, - help='Where to write resulting translation file') -args = parser.parse_args() +def extract_plugin_manifest_strings(plugins_dir, output): + strings = [] + manifests = glob.glob(os.path.join(plugins_dir, "*", "manifest.json"), recursive=True) + print("Found %s manifests" % len(manifests)) -strings = [] -manifests = glob.glob(os.path.join(args.input, "*", "manifest.json"), recursive=True) -print("Found %s manifests" % len(manifests)) + for m in manifests: + with open(m) as f: + j = json.loads(f.read()) + if j.get("description"): + strings.append(j.get("description")) -for m in manifests: - with open(m) as f: - j = json.loads(f.read()) - if j.get("description"): - strings.append(j.get("description")) + print("Found %s manifest strings" % len(strings)) + if len(strings) > 0: + with open(output, "w") as f: + f.write("// Auto-generated with extract_plugin_manifest_strings.py, do not edit!\n\n") + f.write("from django.utils.translation import gettext as _\n") + + for s in strings: + f.write("_(\"%s\")\n" % s.replace("\"", "\\\"")) -print("Found %s manifest strings" % len(strings)) -if len(strings) > 0: - with open(args.output, "w") as f: - f.write("// Auto-generated with extract_plugin_manifest_strings.py, do not edit!\n\n") - f.write("from django.utils.translation import gettext as _\n") - - for s in strings: - f.write("_(\"%s\")\n" % s.replace("\"", "\\\"")) + print("Wrote %s" % output) + else: + print("No strings found") - print("Wrote %s" % args.output) -else: - print("No strings found") \ No newline at end of file +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Extract plugin manifest strings.') + parser.add_argument('input', type=str, + help='Path to plugins directory') + parser.add_argument('output', type=str, + help='Where to write resulting translation file') + args = parser.parse_args() + extract_plugin_manifest_strings(args.input, args.output) \ No newline at end of file diff --git a/app/scripts/extract_potree_strings.py b/app/scripts/extract_potree_strings.py index ac0b5660..320e4aa6 100644 --- a/app/scripts/extract_potree_strings.py +++ b/app/scripts/extract_potree_strings.py @@ -1,31 +1,35 @@ #!/usr/bin/python3 -import argparse, json, os +import json, os -parser = argparse.ArgumentParser(description='Extract Potree strings.') -parser.add_argument('input', type=str, - help='Path to Potree\'s english translation.json') -parser.add_argument('output', type=str, - help='Where to write resulting translation file') -args = parser.parse_args() +def extract_potree_strings(translation_json, output): + strings = [] + with open(translation_json) as f: + j = json.loads(f.read()) + for section in j: + s = j[section] + for k in s: + english_str = s[k] + strings.append(english_str) -strings = [] -with open(args.input) as f: - j = json.loads(f.read()) - for section in j: - s = j[section] - for k in s: - english_str = s[k] - strings.append(english_str) + print("Found %s Potree strings" % len(strings)) + if len(strings) > 0: + with open(output, "w") as f: + f.write("// Auto-generated with extract_potree_strings.py, do not edit!\n\n") -print("Found %s Potree strings" % len(strings)) -if len(strings) > 0: - with open(args.output, "w") as f: - f.write("// Auto-generated with extract_potree_strings.py, do not edit!\n\n") + for s in strings: + f.write("_(\"%s\");\n" % s.replace("\"", "\\\"")) - for s in strings: - f.write("_(\"%s\");\n" % s.replace("\"", "\\\"")) + print("Wrote %s" % output) + else: + print("No strings found") - print("Wrote %s" % args.output) -else: - print("No strings found") \ No newline at end of file +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Extract Potree strings.') + parser.add_argument('input', type=str, + help='Path to Potree\'s english translation.json') + parser.add_argument('output', type=str, + help='Where to write resulting translation file') + args = parser.parse_args() + extract_potree_strings(args.input, args.output) \ No newline at end of file diff --git a/app/scripts/plugin_cleanup.sh b/app/scripts/plugin_cleanup.sh deleted file mode 100755 index 56f17e4f..00000000 --- a/app/scripts/plugin_cleanup.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Delete all node_modules and build directories within plugins' public/ folders - -__dirname=$(cd $(dirname "$0"); pwd -P) -cd "${__dirname}/../../" - -find plugins/ -type d \( -name build -o -name node_modules \) -path 'plugins/*/public/*' -exec rm -frv '{}' \; -echo "Done!" \ No newline at end of file diff --git a/app/static/app/js/translations/odm_autogenerated.js b/app/static/app/js/translations/odm_autogenerated.js index 50789543..27ac9e90 100644 --- a/app/static/app/js/translations/odm_autogenerated.js +++ b/app/static/app/js/translations/odm_autogenerated.js @@ -1,81 +1,81 @@ // Auto-generated with extract_odm_strings.py, do not edit! -_("Keep faces in the mesh that are not seen in any camera. Default: %(default)s"); -_("Name of dataset (i.e subfolder name within project folder). Default: %(default)s"); -_("Filters the point cloud by removing points that deviate more than N standard deviations from the local mean. Set to 0 to disable filtering. Default: %(default)s"); -_("Legacy option (use --feature-quality instead). Resizes images by the largest side for feature extraction purposes only. Set to -1 to disable. This does not affect the final orthophoto resolution quality and will not resize the original images. Default: %(default)s"); -_("Radius of the overlap between submodels. After grouping images into clusters, images that are closer than this radius to a cluster are added to the cluster. This is done to ensure that neighboring submodels overlap. Default: %(default)s"); -_("Path to the image groups file that controls how images should be split into groups. The file needs to use the following format: image_name group_nameDefault: %(default)s"); -_("Matcher algorithm, Fast Library for Approximate Nearest Neighbors or Bag of Words. FLANN is slower, but more stable. BOW is faster, but can sometimes miss valid matches. Can be one of: %(choices)s. Default: %(default)s"); -_("URL to a ClusterODM instance for distributing a split-merge workflow on multiple nodes in parallel. Default: %(default)s"); -_("Rerun processing from this stage. Can be one of: %(choices)s. Default: %(default)s"); -_("Turn off camera parameter optimization during bundle adjustment. This can be sometimes useful for improving results that exhibit doming/bowling or when images are taken with a rolling shutter camera. Default: %(default)s"); -_("Generates a benchmark file with runtime info. Default: %(default)s"); -_("Number of steps used to fill areas with gaps. Set to 0 to disable gap filling. Starting with a radius equal to the output resolution, N different DEMs are generated with progressively bigger radius using the inverse distance weighted (IDW) algorithm and merged together. Remaining gaps are then merged using nearest neighbor interpolation. Default: %(default)s"); -_("Rerun this stage only and stop. Can be one of: %(choices)s. Default: %(default)s"); -_("Reduce the memory usage needed for depthmap fusion by splitting large scenes into tiles. Turn this on if your machine doesn't have much RAM and/or you've set --pc-quality to high or ultra. Experimental. Default: %(default)s"); -_("Minimum number of features to extract per image. More features can be useful for finding more matches between images, potentially allowing the reconstruction of areas with little overlap or insufficient features. More features also slow down processing. Default: %(default)s"); -_("Average number of images per submodel. When splitting a large dataset into smaller submodels, images are grouped into clusters. This value regulates the number of images that each cluster should have on average. Default: %(default)s"); -_("Path to the file containing the ground control points used for georeferencing. The file needs to use the following format: EPSG: or <+proj definition>geo_x geo_y geo_z im_x im_y image_name [gcp_name] [extra1] [extra2]Default: %(default)s"); -_("Computes an euclidean raster map for each DEM. The map reports the distance from each cell to the nearest NODATA value (before any hole filling takes place). This can be useful to isolate the areas that have been filled. Default: %(default)s"); -_("Export the georeferenced point cloud in Entwine Point Tile (EPT) format. Default: %(default)s"); -_("Turn on gamma tone mapping or none for no tone mapping. Can be one of %(choices)s. Default: %(default)s "); -_("Export the georeferenced point cloud in LAS format. Default: %(default)s"); -_("DSM/DTM resolution in cm / pixel. Note that this value is capped by a ground sampling distance (GSD) estimate. To remove the cap, check --ignore-gsd also. Default: %(default)s"); -_("Legacy option (use --pc-quality instead). Controls the density of the point cloud by setting the resolution of the depthmap images. Higher values take longer to compute but produce denser point clouds. Default: %(default)s"); -_("Run local bundle adjustment for every image added to the reconstruction and a global adjustment every 100 images. Speeds up reconstruction for very large datasets. Default: %(default)s"); -_("Simple Morphological Filter elevation threshold parameter (meters). Default: %(default)s"); -_("Skip the blending of colors near seams. Default: %(default)s"); -_("Use the camera parameters computed from another dataset instead of calculating them. Can be specified either as path to a cameras.json file or as a JSON string representing the contents of a cameras.json file. Default: %(default)s"); -_("Generate static tiles for orthophotos and DEMs that are suitable for viewers like Leaflet or OpenLayers. Default: %(default)s"); -_("Choose the algorithm for extracting keypoints and computing descriptors. Can be one of: %(choices)s. Default: %(default)s"); -_("Use this tag to build a DSM (Digital Surface Model, ground + objects) using a progressive morphological filter. Check the --dem* parameters for finer tuning. Default: %(default)s"); -_("Simple Morphological Filter slope parameter (rise over run). Default: %(default)s"); -_("show this help message and exit"); -_("Skip generation of PDF report. This can save time if you don't need a report. Default: %(default)s"); -_("Print additional messages to the console. Default: %(default)s"); -_("Export the georeferenced point cloud in CSV format. Default: %(default)s"); -_("Filters the point cloud by keeping only a single point around a radius N (in meters). This can be useful to limit the output resolution of the point cloud and remove duplicate points. Set to 0 to disable sampling. Default: %(default)s"); -_("Set a value in meters for the GPS Dilution of Precision (DOP) information for all images. If your images are tagged with high precision GPS information (RTK), this value will be automatically set accordingly. You can use this option to manually set it in case the reconstruction fails. Lowering this option can sometimes help control bowling-effects over large areas. Default: %(default)s"); -_("Print debug messages. Default: %(default)s"); -_("Distance threshold in meters to find pre-matching images based on GPS exif data. Set both matcher-neighbors and this to 0 to skip pre-matching. Default: %(default)s"); -_("When texturing the 3D mesh, for each triangle, choose to prioritize images with sharp features (gmi) or those that cover the largest area (area). Default: %(default)s"); -_("Use this tag if you have a GCP File but want to use the EXIF information for georeferencing instead. Default: %(default)s"); -_("Decimate the points before generating the DEM. 1 is no decimation (full quality). 100 decimates ~99%% of the points. Useful for speeding up generation of DEM results in very large datasets. Default: %(default)s"); -_("Perform ground rectification on the point cloud. This means that wrongly classified ground points will be re-classified and gaps will be filled. Useful for generating DTMs. Default: %(default)s"); -_("Set feature extraction quality. Higher quality generates better features, but requires more memory and takes longer. Can be one of: %(choices)s. Default: %(default)s"); -_("The maximum vertex count of the output mesh. Default: %(default)s"); -_("Set the radiometric calibration to perform on images. When processing multispectral and thermal images you should set this option to obtain reflectance/temperature values (otherwise you will get digital number values). [camera] applies black level, vignetting, row gradient gain/exposure compensation (if appropriate EXIF tags are found) and computes absolute temperature values. [camera+sun] is experimental, applies all the corrections of [camera], plus compensates for spectral radiance registered via a downwelling light sensor (DLS) taking in consideration the angle of the sun. Can be one of: %(choices)s. Default: %(default)s"); -_("Set point cloud quality. Higher quality generates better, denser point clouds, but requires more memory and takes longer. Each step up in quality increases processing time roughly by a factor of 4x.Can be one of: %(choices)s. Default: %(default)s"); -_("Simple Morphological Filter window radius parameter (meters). Default: %(default)s"); -_("Set this parameter if you want to generate a Google Earth (KMZ) rendering of the orthophoto. Default: %(default)s"); -_("Delete heavy intermediate files to optimize disk space usage. This affects the ability to restart the pipeline from an intermediate stage, but allows datasets to be processed on machines that don't have sufficient disk space available. Default: %(default)s"); -_("Skip normalization of colors across all images. Useful when processing radiometric data. Default: %(default)s"); -_("Set this parameter if you want to generate a PNG rendering of the orthophoto. Default: %(default)s"); -_("When processing multispectral datasets, you can specify the name of the primary band that will be used for reconstruction. It's recommended to choose a band which has sharp details and is in focus. Default: %(default)s"); -_("Orthophoto resolution in cm / pixel. Note that this value is capped by a ground sampling distance (GSD) estimate. To remove the cap, check --ignore-gsd also. Default: %(default)s"); -_("Permanently delete all previous results and rerun the processing pipeline."); -_("Set this parameter if you want a striped GeoTIFF. Default: %(default)s"); -_("Set a camera projection type. Manually setting a value can help improve geometric undistortion. By default the application tries to determine a lens type from the images metadata. Can be one of: %(choices)s. Default: %(default)s"); _("Path to the project folder. Your project folder should contain subfolders for each dataset. Each dataset should have an \"images\" folder."); -_("Generates a polygon around the cropping area that cuts the orthophoto around the edges of features. This polygon can be useful for stitching seamless mosaics with multiple overlapping orthophotos. Default: %(default)s"); -_("Displays version number and exits. "); -_("Choose what to merge in the merge step in a split dataset. By default all available outputs are merged. Options: %(choices)s. Default: %(default)s"); -_("Skip generation of a full 3D model. This can save time if you only need 2D results such as orthophotos and DEMs. Default: %(default)s"); -_("Classify the point cloud outputs using a Simple Morphological Filter. You can control the behavior of this option by tweaking the --dem-* parameters. Default: %(default)s"); -_("End processing at this stage. Can be one of: %(choices)s. Default: %(default)s"); -_("Simple Morphological Filter elevation scalar parameter. Default: %(default)s"); -_("Type of photometric outlier removal method. Can be one of: %(choices)s. Default: %(default)s"); -_("Use images' GPS exif data for reconstruction, even if there are GCPs present.This flag is useful if you have high precision GPS measurements. If there are no GCPs, this flag does nothing. Default: %(default)s"); -_("Number of nearest images to pre-match based on GPS exif data. Set to 0 to skip pre-matching. Neighbors works together with Distance parameter, set both to 0 to not use pre-matching. Default: %(default)s"); -_("Use a full 3D mesh to compute the orthophoto instead of a 2.5D mesh. This option is a bit faster and provides similar results in planar areas. Default: %(default)s"); -_("Path to the image geolocation file containing the camera center coordinates used for georeferencing. Note that omega/phi/kappa are currently not supported (you can set them to 0). The file needs to use the following format: EPSG: or <+proj definition>image_name geo_x geo_y geo_z [omega (degrees)] [phi (degrees)] [kappa (degrees)] [horz accuracy (meters)] [vert accuracy (meters)]Default: %(default)s"); -_("Use this tag to build a DTM (Digital Terrain Model, ground only) using a simple morphological filter. Check the --dem* and --smrf* parameters for finer tuning. Default: %(default)s"); -_("Build orthophoto overviews for faster display in programs such as QGIS. Default: %(default)s"); _("Automatically crop image outputs by creating a smooth buffer around the dataset boundaries, shrinked by N meters. Use 0 to disable cropping. Default: %(default)s"); -_("When processing multispectral datasets, ODM will automatically align the images for each band. If the images have been postprocessed and are already aligned, use this option. Default: %(default)s"); -_("Set the compression to use for orthophotos. Can be one of: %(choices)s. Default: %(default)s"); +_("Set feature extraction quality. Higher quality generates better features, but requires more memory and takes longer. Can be one of: %(choices)s. Default: %(default)s"); +_("End processing at this stage. Can be one of: %(choices)s. Default: %(default)s"); +_("When texturing the 3D mesh, for each triangle, choose to prioritize images with sharp features (gmi) or those that cover the largest area (area). Default: %(default)s"); +_("Delete heavy intermediate files to optimize disk space usage. This affects the ability to restart the pipeline from an intermediate stage, but allows datasets to be processed on machines that don't have sufficient disk space available. Default: %(default)s"); +_("Simple Morphological Filter elevation threshold parameter (meters). Default: %(default)s"); +_("Use the camera parameters computed from another dataset instead of calculating them. Can be specified either as path to a cameras.json file or as a JSON string representing the contents of a cameras.json file. Default: %(default)s"); +_("Type of photometric outlier removal method. Can be one of: %(choices)s. Default: %(default)s"); +_("Name of dataset (i.e subfolder name within project folder). Default: %(default)s"); +_("Orthophoto resolution in cm / pixel. Note that this value is capped by a ground sampling distance (GSD) estimate. To remove the cap, check --ignore-gsd also. Default: %(default)s"); +_("Build orthophoto overviews for faster display in programs such as QGIS. Default: %(default)s"); +_("Displays version number and exits. "); +_("Use this tag to build a DSM (Digital Surface Model, ground + objects) using a progressive morphological filter. Check the --dem* parameters for finer tuning. Default: %(default)s"); +_("Export the georeferenced point cloud in CSV format. Default: %(default)s"); +_("Reduce the memory usage needed for depthmap fusion by splitting large scenes into tiles. Turn this on if your machine doesn't have much RAM and/or you've set --pc-quality to high or ultra. Experimental. Default: %(default)s"); +_("Permanently delete all previous results and rerun the processing pipeline."); +_("Export the georeferenced point cloud in Entwine Point Tile (EPT) format. Default: %(default)s"); +_("Use this tag if you have a GCP File but want to use the EXIF information for georeferencing instead. Default: %(default)s"); +_("Turn off camera parameter optimization during bundle adjustment. This can be sometimes useful for improving results that exhibit doming/bowling or when images are taken with a rolling shutter camera. Default: %(default)s"); +_("Generates a polygon around the cropping area that cuts the orthophoto around the edges of features. This polygon can be useful for stitching seamless mosaics with multiple overlapping orthophotos. Default: %(default)s"); +_("Print debug messages. Default: %(default)s"); +_("Set point cloud quality. Higher quality generates better, denser point clouds, but requires more memory and takes longer. Each step up in quality increases processing time roughly by a factor of 4x.Can be one of: %(choices)s. Default: %(default)s"); +_("Number of nearest images to pre-match based on GPS exif data. Set to 0 to skip pre-matching. Neighbors works together with Distance parameter, set both to 0 to not use pre-matching. Default: %(default)s"); +_("Set a camera projection type. Manually setting a value can help improve geometric undistortion. By default the application tries to determine a lens type from the images metadata. Can be one of: %(choices)s. Default: %(default)s"); +_("Skip generation of PDF report. This can save time if you don't need a report. Default: %(default)s"); _("Octree depth used in the mesh reconstruction, increase to get more vertices, recommended values are 8-12. Default: %(default)s"); -_("Skips dense reconstruction and 3D model generation. It generates an orthophoto directly from the sparse reconstruction. If you just need an orthophoto and do not need a full 3D model, turn on this option. Default: %(default)s"); -_("Ignore Ground Sampling Distance (GSD). GSD caps the maximum resolution of image outputs and resizes images when necessary, resulting in faster processing and lower memory usage. Since GSD is an estimate, sometimes ignoring it can result in slightly better image output quality. Default: %(default)s"); +_("Rerun processing from this stage. Can be one of: %(choices)s. Default: %(default)s"); +_("Turn on gamma tone mapping or none for no tone mapping. Can be one of %(choices)s. Default: %(default)s "); +_("Decimate the points before generating the DEM. 1 is no decimation (full quality). 100 decimates ~99%% of the points. Useful for speeding up generation of DEM results in very large datasets. Default: %(default)s"); +_("Path to the image groups file that controls how images should be split into groups. The file needs to use the following format: image_name group_nameDefault: %(default)s"); +_("Skip normalization of colors across all images. Useful when processing radiometric data. Default: %(default)s"); +_("Filters the point cloud by removing points that deviate more than N standard deviations from the local mean. Set to 0 to disable filtering. Default: %(default)s"); +_("Set a value in meters for the GPS Dilution of Precision (DOP) information for all images. If your images are tagged with high precision GPS information (RTK), this value will be automatically set accordingly. You can use this option to manually set it in case the reconstruction fails. Lowering this option can sometimes help control bowling-effects over large areas. Default: %(default)s"); +_("Skip the blending of colors near seams. Default: %(default)s"); +_("The maximum vertex count of the output mesh. Default: %(default)s"); +_("Set this parameter if you want to generate a PNG rendering of the orthophoto. Default: %(default)s"); +_("Set this parameter if you want a striped GeoTIFF. Default: %(default)s"); +_("Generates a benchmark file with runtime info. Default: %(default)s"); +_("Run local bundle adjustment for every image added to the reconstruction and a global adjustment every 100 images. Speeds up reconstruction for very large datasets. Default: %(default)s"); +_("Computes an euclidean raster map for each DEM. The map reports the distance from each cell to the nearest NODATA value (before any hole filling takes place). This can be useful to isolate the areas that have been filled. Default: %(default)s"); _("The maximum number of processes to use in various processes. Peak memory requirement is ~1GB per thread and 2 megapixel image resolution. Default: %(default)s"); +_("show this help message and exit"); +_("Rerun this stage only and stop. Can be one of: %(choices)s. Default: %(default)s"); +_("Simple Morphological Filter window radius parameter (meters). Default: %(default)s"); +_("Keep faces in the mesh that are not seen in any camera. Default: %(default)s"); +_("Minimum number of features to extract per image. More features can be useful for finding more matches between images, potentially allowing the reconstruction of areas with little overlap or insufficient features. More features also slow down processing. Default: %(default)s"); +_("Use a full 3D mesh to compute the orthophoto instead of a 2.5D mesh. This option is a bit faster and provides similar results in planar areas. Default: %(default)s"); +_("Skip generation of a full 3D model. This can save time if you only need 2D results such as orthophotos and DEMs. Default: %(default)s"); +_("Number of steps used to fill areas with gaps. Set to 0 to disable gap filling. Starting with a radius equal to the output resolution, N different DEMs are generated with progressively bigger radius using the inverse distance weighted (IDW) algorithm and merged together. Remaining gaps are then merged using nearest neighbor interpolation. Default: %(default)s"); +_("Set this parameter if you want to generate a Google Earth (KMZ) rendering of the orthophoto. Default: %(default)s"); +_("Print additional messages to the console. Default: %(default)s"); +_("Classify the point cloud outputs using a Simple Morphological Filter. You can control the behavior of this option by tweaking the --dem-* parameters. Default: %(default)s"); +_("Ignore Ground Sampling Distance (GSD). GSD caps the maximum resolution of image outputs and resizes images when necessary, resulting in faster processing and lower memory usage. Since GSD is an estimate, sometimes ignoring it can result in slightly better image output quality. Default: %(default)s"); +_("Simple Morphological Filter elevation scalar parameter. Default: %(default)s"); +_("Set the compression to use for orthophotos. Can be one of: %(choices)s. Default: %(default)s"); +_("Distance threshold in meters to find pre-matching images based on GPS exif data. Set both matcher-neighbors and this to 0 to skip pre-matching. Default: %(default)s"); +_("Set the radiometric calibration to perform on images. When processing multispectral and thermal images you should set this option to obtain reflectance/temperature values (otherwise you will get digital number values). [camera] applies black level, vignetting, row gradient gain/exposure compensation (if appropriate EXIF tags are found) and computes absolute temperature values. [camera+sun] is experimental, applies all the corrections of [camera], plus compensates for spectral radiance registered via a downwelling light sensor (DLS) taking in consideration the angle of the sun. Can be one of: %(choices)s. Default: %(default)s"); +_("Radius of the overlap between submodels. After grouping images into clusters, images that are closer than this radius to a cluster are added to the cluster. This is done to ensure that neighboring submodels overlap. Default: %(default)s"); +_("URL to a ClusterODM instance for distributing a split-merge workflow on multiple nodes in parallel. Default: %(default)s"); +_("Use images' GPS exif data for reconstruction, even if there are GCPs present.This flag is useful if you have high precision GPS measurements. If there are no GCPs, this flag does nothing. Default: %(default)s"); +_("When processing multispectral datasets, ODM will automatically align the images for each band. If the images have been postprocessed and are already aligned, use this option. Default: %(default)s"); +_("Use this tag to build a DTM (Digital Terrain Model, ground only) using a simple morphological filter. Check the --dem* and --smrf* parameters for finer tuning. Default: %(default)s"); +_("Legacy option (use --pc-quality instead). Controls the density of the point cloud by setting the resolution of the depthmap images. Higher values take longer to compute but produce denser point clouds. Default: %(default)s"); +_("Generate static tiles for orthophotos and DEMs that are suitable for viewers like Leaflet or OpenLayers. Default: %(default)s"); +_("Skips dense reconstruction and 3D model generation. It generates an orthophoto directly from the sparse reconstruction. If you just need an orthophoto and do not need a full 3D model, turn on this option. Default: %(default)s"); +_("Legacy option (use --feature-quality instead). Resizes images by the largest side for feature extraction purposes only. Set to -1 to disable. This does not affect the final orthophoto resolution quality and will not resize the original images. Default: %(default)s"); +_("Simple Morphological Filter slope parameter (rise over run). Default: %(default)s"); +_("When processing multispectral datasets, you can specify the name of the primary band that will be used for reconstruction. It's recommended to choose a band which has sharp details and is in focus. Default: %(default)s"); +_("DSM/DTM resolution in cm / pixel. Note that this value is capped by a ground sampling distance (GSD) estimate. To remove the cap, check --ignore-gsd also. Default: %(default)s"); +_("Choose the algorithm for extracting keypoints and computing descriptors. Can be one of: %(choices)s. Default: %(default)s"); +_("Average number of images per submodel. When splitting a large dataset into smaller submodels, images are grouped into clusters. This value regulates the number of images that each cluster should have on average. Default: %(default)s"); +_("Matcher algorithm, Fast Library for Approximate Nearest Neighbors or Bag of Words. FLANN is slower, but more stable. BOW is faster, but can sometimes miss valid matches. Can be one of: %(choices)s. Default: %(default)s"); +_("Filters the point cloud by keeping only a single point around a radius N (in meters). This can be useful to limit the output resolution of the point cloud and remove duplicate points. Set to 0 to disable sampling. Default: %(default)s"); +_("Path to the image geolocation file containing the camera center coordinates used for georeferencing. Note that omega/phi/kappa are currently not supported (you can set them to 0). The file needs to use the following format: EPSG: or <+proj definition>image_name geo_x geo_y geo_z [omega (degrees)] [phi (degrees)] [kappa (degrees)] [horz accuracy (meters)] [vert accuracy (meters)]Default: %(default)s"); +_("Choose what to merge in the merge step in a split dataset. By default all available outputs are merged. Options: %(choices)s. Default: %(default)s"); +_("Perform ground rectification on the point cloud. This means that wrongly classified ground points will be re-classified and gaps will be filled. Useful for generating DTMs. Default: %(default)s"); +_("Path to the file containing the ground control points used for georeferencing. The file needs to use the following format: EPSG: or <+proj definition>geo_x geo_y geo_z im_x im_y image_name [gcp_name] [extra1] [extra2]Default: %(default)s"); +_("Export the georeferenced point cloud in LAS format. Default: %(default)s"); diff --git a/start.sh b/start.sh index 83dbc788..baec75ea 100755 --- a/start.sh +++ b/start.sh @@ -51,7 +51,7 @@ if [ "$1" = "--setup-devenv" ] || [ "$2" = "--setup-devenv" ]; then pip install -r requirements.txt echo Build translations... - ./translate.sh build safe + python manage.py translate build --safe echo Setup webpack watch... webpack --watch & From 92966f1d294b589876c8f5a5f0e53d2660551c67 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Thu, 27 May 2021 09:55:27 -0400 Subject: [PATCH 05/13] Finish translate command, fix build --- app/boot.py | 4 +--- app/management/commands/rebuildplugins.py | 2 ++ app/management/commands/translate.py | 15 +++++++++++++-- app/plugins/grass_engine.py | 2 -- app/views/dev.py | 6 ++---- webodm/settings.py | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/app/boot.py b/app/boot.py index b3b15bf2..fc915116 100644 --- a/app/boot.py +++ b/app/boot.py @@ -84,9 +84,7 @@ def boot(): logger.info("Created settings") - # Invoked via manage.py - if len(sys.argv[1:2]) > 0 and not settings.TESTING: - init_plugins() + init_plugins() if not settings.TESTING: try: diff --git a/app/management/commands/rebuildplugins.py b/app/management/commands/rebuildplugins.py index 973a938f..cba17f31 100644 --- a/app/management/commands/rebuildplugins.py +++ b/app/management/commands/rebuildplugins.py @@ -17,6 +17,8 @@ def cleanup(): print("Cleanup done!") class Command(BaseCommand): + requires_system_checks = [] + def add_arguments(self, parser): super(Command, self).add_arguments(parser) diff --git a/app/management/commands/translate.py b/app/management/commands/translate.py index 45c306b8..67e47a3c 100644 --- a/app/management/commands/translate.py +++ b/app/management/commands/translate.py @@ -9,9 +9,11 @@ from app.scripts.extract_potree_strings import extract_potree_strings root = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "..")) class Command(BaseCommand): + requires_system_checks = [] + def add_arguments(self, parser): parser.add_argument("action", type=str, choices=['extract', 'build']) - parser.add_argument("--safe", type=bool, required=False, help="Skip invalid languages") + parser.add_argument("--safe", action='store_true', required=False, help="Skip invalid languages") super(Command, self).add_arguments(parser) def handle(self, **options): @@ -40,4 +42,13 @@ class Command(BaseCommand): ) call_command('makemessages', '--keep-pot', *locale_params, '--ignore=build', '--ignore=app/templates/app/registration/*') - call_command('makemessages_djangojs', '--keep-pot', *locale_params, '-d=djangojs', '--extension=jsx', '--extension=js', '--ignore=build', '--ignore=app/static/app/js/vendor', '--ignore=app/static/app/bundles', '--ignore=node_modules', '--language=Python') \ No newline at end of file + call_command('makemessages_djangojs', '--keep-pot', *locale_params, '-d=djangojs', '--extension=jsx', '--extension=js', '--ignore=build', '--ignore=app/static/app/js/vendor', '--ignore=app/static/app/bundles', '--ignore=node_modules', '--language=Python') + + elif options.get('action') == 'build': + if options.get('safe'): + for l in locales: + print("Building %s .po files into .mo" % l) + call_command('compilemessages', '--locale=%s' % l) + else: + print("Building .po files into .mo") + call_command('compilemessages') \ No newline at end of file diff --git a/app/plugins/grass_engine.py b/app/plugins/grass_engine.py index 4b86b394..cb3c7ff9 100644 --- a/app/plugins/grass_engine.py +++ b/app/plugins/grass_engine.py @@ -26,8 +26,6 @@ class GrassEngine: if self.grass_binary is None: logger.warning("Could not find a GRASS 7 executable. GRASS scripts will not work.") - else: - logger.info("Initializing GRASS engine using {}".format(self.grass_binary)) def create_context(self, serialized_context = {}): if self.grass_binary is None: raise GrassEngineException("GRASS engine is unavailable") diff --git a/app/views/dev.py b/app/views/dev.py index c08eb558..daa5cd0d 100644 --- a/app/views/dev.py +++ b/app/views/dev.py @@ -68,10 +68,8 @@ def dev_tools(request, action): logger.info("Moving %s to %s..." % (locale_path, webodm_locale_dir)) copymerge(locale_path, webodm_locale_dir) - logger.info("Running translate.sh extract && translate.sh build safe") - translate_script = os.path.join(settings.BASE_DIR, 'translate.sh') - - subprocess.call(['bash', '-c', '%s extract && %s build safe' % (translate_script, translate_script)], cwd=settings.BASE_DIR) + logger.info("Running python manage.py translate extract && python manage.py translate build --safe") + subprocess.call(['bash', '-c', 'python manage.py translate extract && %s python manage.py translate build --safe'], cwd=settings.BASE_DIR) return JsonResponse({'message': _("Translation files reloaded!"), 'reload': True}) except Exception as e: diff --git a/webodm/settings.py b/webodm/settings.py index 4dfa0494..0cd4a5b3 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -154,7 +154,7 @@ DATABASES = { 'NAME': os.environ.get('WO_DATABASE_NAME', 'webodm_dev'), 'USER': os.environ.get('WO_DATABASE_USER', 'postgres'), 'PASSWORD': os.environ.get('WO_DATABASE_PASSWORD', 'postgres'), - 'HOST': os.environ.get('WO_DATABASE_HOST', 'db'), + 'HOST': os.environ.get('WO_DATABASE_HOST', 'dbxxx'), 'PORT': os.environ.get('WO_DATABASE_PORT', '5432'), } } From 2401627f9583214c7487769e551bc8547b88f648 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Thu, 27 May 2021 10:06:36 -0400 Subject: [PATCH 06/13] Invoke python for pip install --- app/plugins/plugin_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/plugins/plugin_base.py b/app/plugins/plugin_base.py index 7b21c62c..b95f8088 100644 --- a/app/plugins/plugin_base.py +++ b/app/plugins/plugin_base.py @@ -41,7 +41,7 @@ class PluginBase(ABC): if not os.path.exists(self.get_python_packages_path()): os.makedirs(self.get_python_packages_path(), exist_ok=True) - p = subprocess.Popen(['pip', 'install', '-U', '-r', 'requirements.txt', + p = subprocess.Popen(['python', '-m', 'pip', 'install', '-U', '-r', 'requirements.txt', '--target', self.get_python_packages_path()], cwd=self.get_path()) p.wait() From ae1eaf4cf55ae26c13407561b0b8778f0fdd2c30 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Thu, 27 May 2021 11:35:36 -0400 Subject: [PATCH 07/13] Add top line in desktop mode --- app/templates/app/base.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/templates/app/base.html b/app/templates/app/base.html index 3371d673..1c7b16f2 100644 --- a/app/templates/app/base.html +++ b/app/templates/app/base.html @@ -72,6 +72,10 @@ +{% if desktop_mode %} +
+{% endif %} + {% block body %}