diff --git a/app/__init__.py b/app/__init__.py index dcb58e47b9943b4efcc77f9bc8f5ba060f9b0d78..59d6d5c99e88ded2b4644b44708bed1f4f59b74f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,6 +4,7 @@ from docker import DockerClient from flask import Flask from flask_apscheduler import APScheduler from flask_assets import Environment +from flask_breadcrumbs import Breadcrumbs, default_breadcrumb_root from flask_login import LoginManager from flask_mail import Mail from flask_marshmallow import Marshmallow @@ -16,6 +17,7 @@ from flask_hashids import Hashids apifairy = APIFairy() assets = Environment() +breadcrumbs = Breadcrumbs() db = SQLAlchemy() docker_client = DockerClient() hashids = Hashids() @@ -44,6 +46,7 @@ def create_app(config: Config = Config) -> Flask: apifairy.init_app(app) assets.init_app(app) + breadcrumbs.init_app(app) db.init_app(app) hashids.init_app(app) login.init_app(app) @@ -64,9 +67,11 @@ def create_app(config: Config = Config) -> Flask: app.register_blueprint(api_blueprint, url_prefix='/api') from .auth import bp as auth_blueprint + default_breadcrumb_root(auth_blueprint, '.') app.register_blueprint(auth_blueprint, url_prefix='/auth') from .contributions import bp as contributions_blueprint + default_breadcrumb_root(contributions_blueprint, '.contributions') app.register_blueprint(contributions_blueprint, url_prefix='/contributions') from .corpora import bp as corpora_blueprint @@ -76,9 +81,11 @@ def create_app(config: Config = Config) -> Flask: app.register_blueprint(jobs_blueprint, url_prefix='/jobs') from .main import bp as main_blueprint + default_breadcrumb_root(main_blueprint, '.') app.register_blueprint(main_blueprint, url_prefix='/') from .services import bp as services_blueprint + default_breadcrumb_root(services_blueprint, '.services') app.register_blueprint(services_blueprint, url_prefix='/services') from .settings import bp as settings_blueprint diff --git a/app/auth/routes.py b/app/auth/routes.py index 5655d0dcf59fddf1482cd7d5bcd978758d1d2cb8..6e11a14090da3aa20ab20119750ba26f5e97bee8 100644 --- a/app/auth/routes.py +++ b/app/auth/routes.py @@ -1,11 +1,5 @@ -from flask import ( - abort, - flash, - redirect, - render_template, - request, - url_for -) +from flask import abort, flash, redirect, render_template, request, url_for +from flask_breadcrumbs import register_breadcrumb from flask_login import current_user, login_user, login_required, logout_user from app import db from app.email import create_message, send @@ -36,6 +30,7 @@ def before_request(): @bp.route('/register', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.register', 'Register') def register(): if current_user.is_authenticated: return redirect(url_for('main.dashboard')) @@ -71,6 +66,7 @@ def register(): @bp.route('/login', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.login', 'Login') def login(): if current_user.is_authenticated: return redirect(url_for('main.dashboard')) @@ -97,6 +93,7 @@ def logout(): @bp.route('/unconfirmed') +@register_breadcrumb(bp, '.unconfirmed', 'Unconfirmed') @login_required def unconfirmed(): if current_user.confirmed: @@ -136,6 +133,7 @@ def confirm(token): @bp.route('/reset_password', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.reset_password_request', 'Password Reset') def reset_password_request(): if current_user.is_authenticated: return redirect(url_for('main.dashboard')) @@ -165,6 +163,7 @@ def reset_password_request(): @bp.route('/reset_password/<token>', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.reset_password', 'Password Reset') def reset_password(token): if current_user.is_authenticated: return redirect(url_for('main.dashboard')) diff --git a/app/contributions/__init__.py b/app/contributions/__init__.py index 5175c0ce7d5c6b907a1cd0fe1a6f3df140f580b4..7749a27804487e49afd8017b21ebdae07601c85d 100644 --- a/app/contributions/__init__.py +++ b/app/contributions/__init__.py @@ -2,16 +2,4 @@ from flask import Blueprint bp = Blueprint('contributions', __name__) -from . import routes - -from .spacy_nlp_pipeline_models import bp as spacy_nlp_pipeline_models_bp -bp.register_blueprint( - spacy_nlp_pipeline_models_bp, - url_prefix='/spacy-nlp-pipeline-models' -) - -from .tesseract_ocr_pipeline_models import bp as tesseract_ocr_pipeline_models_bp -bp.register_blueprint( - tesseract_ocr_pipeline_models_bp, - url_prefix='/tesseract-ocr-pipeline-models' -) +from . import json_routes, routes diff --git a/app/contributions/forms.py b/app/contributions/forms.py index acec307f00b4e409ff962cc7e0021973a442f2fe..1ef4fdc79611ef7944c970621e6791a36813b43d 100644 --- a/app/contributions/forms.py +++ b/app/contributions/forms.py @@ -1,11 +1,14 @@ from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileRequired from wtforms import ( StringField, SubmitField, SelectMultipleField, - IntegerField + IntegerField, + ValidationError ) from wtforms.validators import InputRequired, Length +from app.services import SERVICES class ContributionBaseForm(FlaskForm): @@ -45,3 +48,79 @@ class ContributionBaseForm(FlaskForm): class EditContributionBaseForm(ContributionBaseForm): pass + + +############################################################################## +# /spacy-nlp-pipeline-models # +############################################################################## +class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm): + spacy_model_file = FileField( + 'File', + validators=[FileRequired()] + ) + pipeline_name = StringField( + 'Pipeline name', + validators=[InputRequired(), Length(max=64)] + ) + + def validate_spacy_model_file(self, field): + if not field.data.filename.lower().endswith('.tar.gz'): + raise ValidationError('.tar.gz files only!') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + service_manifest = SERVICES['spacy-nlp-pipeline'] + self.compatible_service_versions.choices = [('', 'Choose your option')] + self.compatible_service_versions.choices += [ + (x, x) for x in service_manifest['versions'].keys() + ] + self.compatible_service_versions.default = '' + + +class EditSpaCyNLPPipelineModelForm(EditContributionBaseForm): + pipeline_name = StringField( + 'Pipeline name', + validators=[InputRequired(), Length(max=64)] + ) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + service_manifest = SERVICES['spacy-nlp-pipeline'] + self.compatible_service_versions.choices = [('', 'Choose your option')] + self.compatible_service_versions.choices += [ + (x, x) for x in service_manifest['versions'].keys() + ] + self.compatible_service_versions.default = '' + + +############################################################################## +# /tesseract-ocr-pipeline-models # +############################################################################## +class CreateTesseractOCRPipelineModelForm(ContributionBaseForm): + tesseract_model_file = FileField( + 'File', + validators=[FileRequired()] + ) + + def validate_tesseract_model_file(self, field): + if not field.data.filename.lower().endswith('.traineddata'): + raise ValidationError('traineddata files only!') + + def __init__(self, *args, **kwargs): + service_manifest = SERVICES['tesseract-ocr-pipeline'] + super().__init__(*args, **kwargs) + self.compatible_service_versions.choices = [('', 'Choose your option')] + self.compatible_service_versions.choices += [ + (x, x) for x in service_manifest['versions'].keys() + ] + self.compatible_service_versions.default = '' + + +class EditTesseractOCRPipelineModelForm(EditContributionBaseForm): + def __init__(self, *args, **kwargs): + service_manifest = SERVICES['tesseract-ocr-pipeline'] + super().__init__(*args, **kwargs) + self.compatible_service_versions.choices = [('', 'Choose your option')] + self.compatible_service_versions.choices += [ + (x, x) for x in service_manifest['versions'].keys() + ] + self.compatible_service_versions.default = '' diff --git a/app/contributions/json_routes.py b/app/contributions/json_routes.py new file mode 100644 index 0000000000000000000000000000000000000000..c44a4c9ccb38f7ccbef335526efe80948d741a53 --- /dev/null +++ b/app/contributions/json_routes.py @@ -0,0 +1,107 @@ +from flask import abort, current_app, request +from flask_login import login_required, current_user +from threading import Thread +from app import db +from app.decorators import content_negotiation, permission_required +from app.models import SpaCyNLPPipelineModel, TesseractOCRPipelineModel +from . import bp + + +############################################################################## +# /spacy-nlp-pipeline-models # +############################################################################## +@bp.route('/spacy-nlp-pipeline-models<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE']) +@login_required +@content_negotiation(produces='application/json') +def delete_spacy_model(spacy_nlp_pipeline_model_id): + def _delete_spacy_model(app, spacy_nlp_pipeline_model_id): + with app.app_context(): + snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) + snpm.delete() + db.session.commit() + + snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) + if not (snpm.user == current_user or current_user.is_administrator()): + abort(403) + thread = Thread( + target=_delete_spacy_model, + args=(current_app._get_current_object(), snpm.id) + ) + thread.start() + resonse_data = { + 'message': \ + f'SpaCy NLP Pipeline Model "{snpm.title}" marked for deletion' + } + return resonse_data, 202 + + +@bp.route('/spacy-nlp-pipeline-models<hashid:spacy_nlp_pipeline_model_id>/is_public', methods=['PUT']) +@login_required +@permission_required('CONTRIBUTE') +@content_negotiation(consumes='application/json', produces='application/json') +def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id): + is_public = request.json + if not isinstance(is_public, bool): + abort(400) + snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) + if not (snpm.user == current_user or current_user.is_administrator()): + abort(403) + snpm.is_public = is_public + db.session.commit() + response_data = { + 'message': ( + f'SpaCy NLP Pipeline Model "{snpm.title}"' + f' is now {"public" if is_public else "private"}' + ) + } + return response_data, 200 + + +############################################################################## +# /tesseract-ocr-pipeline-models # +############################################################################## +@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE']) +@login_required +@content_negotiation(produces='application/json') +def delete_tesseract_model(tesseract_ocr_pipeline_model_id): + def _delete_tesseract_ocr_pipeline_model(app, tesseract_ocr_pipeline_model_id): + with app.app_context(): + topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) + topm.delete() + db.session.commit() + + topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) + if not (topm.user == current_user or current_user.is_administrator()): + abort(403) + thread = Thread( + target=_delete_tesseract_ocr_pipeline_model, + args=(current_app._get_current_object(), topm.id) + ) + thread.start() + response_data = { + 'message': \ + f'Tesseract OCR Pipeline Model "{topm.title}" marked for deletion' + } + return response_data, 202 + + +@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>/is_public', methods=['PUT']) +@login_required +@permission_required('CONTRIBUTE') +@content_negotiation(consumes='application/json', produces='application/json') +def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_id): + is_public = request.json + if not isinstance(is_public, bool): + abort(400) + topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) + if not (topm.user == current_user or current_user.is_administrator()): + abort(403) + topm.is_public = is_public + db.session.commit() + response_data = { + 'message': ( + f'Tesseract OCR Pipeline Model "{topm.title}"' + f' is now {"public" if is_public else "private"}' + ) + } + return response_data, 200 diff --git a/app/contributions/routes.py b/app/contributions/routes.py index 6d8b9cc3ab62b318b9c9a61fe4442e2698c9ec87..6da7dc120bbb1923e64e9ad092fec4abd4b442c8 100644 --- a/app/contributions/routes.py +++ b/app/contributions/routes.py @@ -1,12 +1,189 @@ -from flask import render_template -from flask_login import login_required +from flask import abort, flash, redirect, render_template, request, url_for +from flask_breadcrumbs import register_breadcrumb +from flask_login import current_user, login_required +from app import db +from app.models import SpaCyNLPPipelineModel, TesseractOCRPipelineModel from . import bp +from .forms import ( + CreateSpaCyNLPPipelineModelForm, + EditSpaCyNLPPipelineModelForm, + CreateTesseractOCRPipelineModelForm, + EditTesseractOCRPipelineModelForm +) -@bp.route('/') +@bp.route('') +@register_breadcrumb(bp, '.', 'Contributions') @login_required def contributions(): return render_template( 'contributions/contributions.html.j2', title='Contributions' ) + + +############################################################################## +# /spacy-nlp-pipeline-models # +############################################################################## +@bp.route('/spacy-nlp-pipeline-models') +@register_breadcrumb(bp, '.spacy_nlp_pipeline_models', 'SpaCy NLP Pipeline Models') +@login_required +def spacy_nlp_pipeline_models(): + return render_template( + 'contributions/spacy_nlp_pipeline_models.html.j2', + title='SpaCy NLP Pipeline Models' + ) + + +@bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.create', 'Create') +@login_required +def create_spacy_nlp_pipeline_model(): + form_prefix = 'create-spacy-nlp-pipeline-model-form' + form = CreateSpaCyNLPPipelineModelForm(prefix=form_prefix) + if form.is_submitted(): + if not form.validate(): + return {'errors': form.errors}, 400 + try: + snpm = SpaCyNLPPipelineModel.create( + form.spacy_model_file.data, + compatible_service_versions=form.compatible_service_versions.data, + description=form.description.data, + pipeline_name=form.pipeline_name.data, + publisher=form.publisher.data, + publisher_url=form.publisher_url.data, + publishing_url=form.publishing_url.data, + publishing_year=form.publishing_year.data, + is_public=False, + title=form.title.data, + version=form.version.data, + user=current_user + ) + except OSError: + abort(500) + db.session.commit() + flash(f'SpaCy NLP Pipeline model "{snpm.title}" created') + return {}, 201, {'Location': url_for('.spacy_nlp_pipeline_models')} + return render_template( + 'contributions/create_spacy_nlp_pipeline_model.html.j2', + form=form, + title='Create SpaCy NLP Pipeline Model' + ) + + +def spacy_nlp_pipeline_model_dlc(*args, **kwargs): + snpm_id = request.view_args['spacy_nlp_pipeline_model_id'] + snpm = SpaCyNLPPipelineModel.query.get(snpm_id) + return [ + { + 'text': f'{snpm.title} {snpm.version}', + 'url': url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=snpm_id) + } + ] + + +@bp.route('/spacy-nlp-pipeline-models/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.spacy_nlp_pipeline_models.entity', '', dynamic_list_constructor=spacy_nlp_pipeline_model_dlc) +@login_required +def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id): + snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) + form_prefix = 'edit-spacy-nlp-pipeline-model-form' + form = EditSpaCyNLPPipelineModelForm( + data=snpm.to_json_serializeable(), + prefix=form_prefix + ) + if form.validate_on_submit(): + form.populate_obj(snpm) + if db.session.is_modified(snpm): + flash(f'SpaCy NLP Pipeline model "{snpm.title}" updated') + db.session.commit() + return redirect(url_for('.spacy_nlp_pipeline_models')) + return render_template( + 'contributions/spacy_nlp_pipeline_model.html.j2', + form=form, + spacy_nlp_pipeline_model=snpm, + title=f'{snpm.title} {snpm.version}' + ) + + +############################################################################## +# /tesseract-ocr-pipeline-models # +############################################################################## +@bp.route('/tesseract-ocr-pipeline-models') +@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models', 'Tesseract OCR Pipeline Models') +@login_required +def tesseract_ocr_pipeline_models(): + return render_template( + 'contributions/tesseract_ocr_pipeline_models.html.j2', + title='Tesseract OCR Pipeline Models' + ) + + +@bp.route('/tesseract-ocr-pipeline-models/create', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.create', 'Create') +@login_required +def create_tesseract_ocr_pipeline_model(): + form_prefix = 'create-tesseract-ocr-pipeline-model-form' + form = CreateTesseractOCRPipelineModelForm(prefix=form_prefix) + if form.is_submitted(): + if not form.validate(): + return {'errors': form.errors}, 400 + try: + topm = TesseractOCRPipelineModel.create( + form.tesseract_model_file.data, + compatible_service_versions=form.compatible_service_versions.data, + description=form.description.data, + publisher=form.publisher.data, + publisher_url=form.publisher_url.data, + publishing_url=form.publishing_url.data, + publishing_year=form.publishing_year.data, + is_public=False, + title=form.title.data, + version=form.version.data, + user=current_user + ) + except OSError: + abort(500) + db.session.commit() + flash(f'Tesseract OCR Pipeline model "{topm.title}" created') + return {}, 201, {'Location': url_for('.tesseract_ocr_pipeline_models')} + return render_template( + 'contributions/create_tesseract_ocr_pipeline_model.html.j2', + form=form, + title='Create Tesseract OCR Pipeline Model' + ) + + +def tesseract_ocr_pipeline_model_dlc(*args, **kwargs): + topm_id = request.view_args['tesseract_ocr_pipeline_model_id'] + topm = TesseractOCRPipelineModel.query.get(topm_id) + return [ + { + 'text': f'{topm.title} {topm.version}', + 'url': url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=topm_id) + } + ] + + +@bp.route('/tesseract-ocr-pipeline-models/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.tesseract_ocr_pipeline_models.entity', '', dynamic_list_constructor=tesseract_ocr_pipeline_model_dlc) +@login_required +def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): + topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) + form_prefix = 'edit-tesseract-ocr-pipeline-model-form' + form = EditTesseractOCRPipelineModelForm( + data=topm.to_json_serializeable(), + prefix=form_prefix + ) + if form.validate_on_submit(): + form.populate_obj(topm) + if db.session.is_modified(topm): + flash(f'Tesseract OCR Pipeline model "{topm.title}" updated') + db.session.commit() + return redirect(url_for('.tesseract_ocr_pipeline_models')) + return render_template( + 'contributions/tesseract_ocr_pipeline_model.html.j2', + form=form, + tesseract_ocr_pipeline_model=topm, + title=f'{topm.title} {topm.version}' + ) diff --git a/app/contributions/spacy_nlp_pipeline_models/__init__.py b/app/contributions/spacy_nlp_pipeline_models/__init__.py deleted file mode 100644 index 8ff119d01549a5b68ff40b0372669d6b07cd24fb..0000000000000000000000000000000000000000 --- a/app/contributions/spacy_nlp_pipeline_models/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from flask import Blueprint - - -template_base_dir = 'contributions/spacy_nlp_pipeline_models' - - -bp = Blueprint('spacy_nlp_pipeline_models', __name__) -from . import routes, json_routes diff --git a/app/contributions/spacy_nlp_pipeline_models/forms.py b/app/contributions/spacy_nlp_pipeline_models/forms.py deleted file mode 100644 index 2670c1d1c0ba126c1eabf911b09475eda53c3799..0000000000000000000000000000000000000000 --- a/app/contributions/spacy_nlp_pipeline_models/forms.py +++ /dev/null @@ -1,44 +0,0 @@ -from flask_wtf.file import FileField, FileRequired -from wtforms import StringField, ValidationError -from wtforms.validators import InputRequired, Length -from app.services import SERVICES -from ..forms import ContributionBaseForm, EditContributionBaseForm - - -class CreateSpaCyNLPPipelineModelForm(ContributionBaseForm): - spacy_model_file = FileField( - 'File', - validators=[FileRequired()] - ) - pipeline_name = StringField( - 'Pipeline name', - validators=[InputRequired(), Length(max=64)] - ) - - def validate_spacy_model_file(self, field): - if not field.data.filename.lower().endswith('.tar.gz'): - raise ValidationError('.tar.gz files only!') - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - service_manifest = SERVICES['spacy-nlp-pipeline'] - self.compatible_service_versions.choices = [('', 'Choose your option')] - self.compatible_service_versions.choices += [ - (x, x) for x in service_manifest['versions'].keys() - ] - self.compatible_service_versions.default = '' - - -class EditSpaCyNLPPipelineModelForm(EditContributionBaseForm): - pipeline_name = StringField( - 'Pipeline name', - validators=[InputRequired(), Length(max=64)] - ) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - service_manifest = SERVICES['spacy-nlp-pipeline'] - self.compatible_service_versions.choices = [('', 'Choose your option')] - self.compatible_service_versions.choices += [ - (x, x) for x in service_manifest['versions'].keys() - ] - self.compatible_service_versions.default = '' diff --git a/app/contributions/spacy_nlp_pipeline_models/json_routes.py b/app/contributions/spacy_nlp_pipeline_models/json_routes.py deleted file mode 100644 index f7a9a254586abd478d7401fcd19669670cfd1b57..0000000000000000000000000000000000000000 --- a/app/contributions/spacy_nlp_pipeline_models/json_routes.py +++ /dev/null @@ -1,54 +0,0 @@ -from flask import abort, current_app, request -from flask_login import login_required, current_user -from threading import Thread -from app import db -from app.decorators import content_negotiation, permission_required -from app.models import SpaCyNLPPipelineModel -from . import bp - - -@bp.route('/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE']) -@login_required -@content_negotiation(produces='application/json') -def delete_spacy_model(spacy_nlp_pipeline_model_id): - def _delete_spacy_model(app, spacy_nlp_pipeline_model_id): - with app.app_context(): - snpm = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) - snpm.delete() - db.session.commit() - - snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) - if not (snpm.user == current_user or current_user.is_administrator()): - abort(403) - thread = Thread( - target=_delete_spacy_model, - args=(current_app._get_current_object(), snpm.id) - ) - thread.start() - resonse_data = { - 'message': \ - f'SpaCy NLP Pipeline Model "{snpm.title}" marked for deletion' - } - return resonse_data, 202 - - -@bp.route('/<hashid:spacy_nlp_pipeline_model_id>/is_public', methods=['PUT']) -@login_required -@permission_required('CONTRIBUTE') -@content_negotiation(consumes='application/json', produces='application/json') -def update_spacy_nlp_pipeline_model_is_public(spacy_nlp_pipeline_model_id): - is_public = request.json - if not isinstance(is_public, bool): - abort(400) - snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) - if not (snpm.user == current_user or current_user.is_administrator()): - abort(403) - snpm.is_public = is_public - db.session.commit() - response_data = { - 'message': ( - f'SpaCy NLP Pipeline Model "{snpm.title}"' - f' is now {"public" if is_public else "private"}' - ) - } - return response_data, 200 diff --git a/app/contributions/spacy_nlp_pipeline_models/routes.py b/app/contributions/spacy_nlp_pipeline_models/routes.py deleted file mode 100644 index fd972902087e00a156b912323005bf7f9827abc3..0000000000000000000000000000000000000000 --- a/app/contributions/spacy_nlp_pipeline_models/routes.py +++ /dev/null @@ -1,76 +0,0 @@ -from flask import abort, flash, redirect, render_template, url_for -from flask_login import current_user, login_required -from app import db -from app.models import SpaCyNLPPipelineModel -from . import bp, template_base_dir -from .forms import ( - CreateSpaCyNLPPipelineModelForm, - EditSpaCyNLPPipelineModelForm -) - - -@bp.route('') -@login_required -def spacy_nlp_pipeline_models(): - return render_template( - f'{template_base_dir}/spacy_nlp_pipeline_models.html.j2', - title='SpaCy NLP Pipeline Models' - ) - - -@bp.route('/create', methods=['GET', 'POST']) -@login_required -def create_spacy_nlp_pipeline_model(): - form_prefix = 'create-spacy-nlp-pipeline-model-form' - form = CreateSpaCyNLPPipelineModelForm(prefix=form_prefix) - if form.is_submitted(): - if not form.validate(): - return {'errors': form.errors}, 400 - try: - snpm = SpaCyNLPPipelineModel.create( - form.spacy_model_file.data, - compatible_service_versions=form.compatible_service_versions.data, - description=form.description.data, - pipeline_name=form.pipeline_name.data, - publisher=form.publisher.data, - publisher_url=form.publisher_url.data, - publishing_url=form.publishing_url.data, - publishing_year=form.publishing_year.data, - is_public=False, - title=form.title.data, - version=form.version.data, - user=current_user - ) - except OSError: - abort(500) - db.session.commit() - flash(f'SpaCy NLP Pipeline model "{snpm.title}" created') - return {}, 201, {'Location': url_for('.spacy_nlp_pipeline_models')} - return render_template( - f'{template_base_dir}/create_spacy_nlp_pipeline_model.html.j2', - form=form, - title='Create SpaCy NLP Pipeline Model' - ) - - -@bp.route('/<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST']) -@login_required -def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id): - snpm = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) - form_prefix = 'edit-spacy-nlp-pipeline-model-form' - form = EditSpaCyNLPPipelineModelForm( - data=snpm.to_json_serializeable(), - prefix=form_prefix - ) - if form.validate_on_submit(): - form.populate_obj(snpm) - if db.session.is_modified(snpm): - flash(f'SpaCy NLP Pipeline model "{snpm.title}" updated') - db.session.commit() - return redirect(url_for('.spacy_nlp_pipeline_models')) - return render_template( - f'{template_base_dir}/spacy_nlp_pipeline_model.html.j2', - form=form, - spacy_nlp_pipeline_model=snpm, - title=f'{snpm.title} {snpm.version}' - ) diff --git a/app/contributions/tesseract_ocr_pipeline_models/__init__.py b/app/contributions/tesseract_ocr_pipeline_models/__init__.py deleted file mode 100644 index cf44126dd5a34aaefa85099995489ce61db43043..0000000000000000000000000000000000000000 --- a/app/contributions/tesseract_ocr_pipeline_models/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from flask import Blueprint - - -template_base_dir = 'contributions/tesseract_ocr_pipeline_models' - - -bp = Blueprint('tesseract_ocr_pipeline_models', __name__) -from . import routes, json_routes diff --git a/app/contributions/tesseract_ocr_pipeline_models/forms.py b/app/contributions/tesseract_ocr_pipeline_models/forms.py deleted file mode 100644 index 51f0d76c2017029c46691719d3131ee779d5c39c..0000000000000000000000000000000000000000 --- a/app/contributions/tesseract_ocr_pipeline_models/forms.py +++ /dev/null @@ -1,35 +0,0 @@ -from flask_wtf.file import FileField, FileRequired -from wtforms import ValidationError -from app.services import SERVICES -from ..forms import ContributionBaseForm, EditContributionBaseForm - - -class CreateTesseractOCRPipelineModelForm(ContributionBaseForm): - tesseract_model_file = FileField( - 'File', - validators=[FileRequired()] - ) - - def validate_tesseract_model_file(self, field): - if not field.data.filename.lower().endswith('.traineddata'): - raise ValidationError('traineddata files only!') - - def __init__(self, *args, **kwargs): - service_manifest = SERVICES['tesseract-ocr-pipeline'] - super().__init__(*args, **kwargs) - self.compatible_service_versions.choices = [('', 'Choose your option')] - self.compatible_service_versions.choices += [ - (x, x) for x in service_manifest['versions'].keys() - ] - self.compatible_service_versions.default = '' - - -class EditTesseractOCRPipelineModelForm(EditContributionBaseForm): - def __init__(self, *args, **kwargs): - service_manifest = SERVICES['tesseract-ocr-pipeline'] - super().__init__(*args, **kwargs) - self.compatible_service_versions.choices = [('', 'Choose your option')] - self.compatible_service_versions.choices += [ - (x, x) for x in service_manifest['versions'].keys() - ] - self.compatible_service_versions.default = '' diff --git a/app/contributions/tesseract_ocr_pipeline_models/json_routes.py b/app/contributions/tesseract_ocr_pipeline_models/json_routes.py deleted file mode 100644 index 81aa65984ac95a1d9d01772fcdde8593df81f904..0000000000000000000000000000000000000000 --- a/app/contributions/tesseract_ocr_pipeline_models/json_routes.py +++ /dev/null @@ -1,54 +0,0 @@ -from flask import abort, current_app, request -from flask_login import login_required, current_user -from threading import Thread -from app import db -from app.decorators import content_negotiation, permission_required -from app.models import TesseractOCRPipelineModel -from . import bp - - -@bp.route('/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE']) -@login_required -@content_negotiation(produces='application/json') -def delete_tesseract_model(tesseract_ocr_pipeline_model_id): - def _delete_tesseract_ocr_pipeline_model(app, tesseract_ocr_pipeline_model_id): - with app.app_context(): - topm = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) - topm.delete() - db.session.commit() - - topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) - if not (topm.user == current_user or current_user.is_administrator()): - abort(403) - thread = Thread( - target=_delete_tesseract_ocr_pipeline_model, - args=(current_app._get_current_object(), topm.id) - ) - thread.start() - response_data = { - 'message': \ - f'Tesseract OCR Pipeline Model "{topm.title}" marked for deletion' - } - return response_data, 202 - - -@bp.route('/<hashid:tesseract_ocr_pipeline_model_id>/is_public', methods=['PUT']) -@login_required -@permission_required('CONTRIBUTE') -@content_negotiation(consumes='application/json', produces='application/json') -def update_tesseract_ocr_pipeline_model_is_public(tesseract_ocr_pipeline_model_id): - is_public = request.json - if not isinstance(is_public, bool): - abort(400) - topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) - if not (topm.user == current_user or current_user.is_administrator()): - abort(403) - topm.is_public = is_public - db.session.commit() - response_data = { - 'message': ( - f'Tesseract OCR Pipeline Model "{topm.title}"' - f' is now {"public" if is_public else "private"}' - ) - } - return response_data, 200 diff --git a/app/contributions/tesseract_ocr_pipeline_models/routes.py b/app/contributions/tesseract_ocr_pipeline_models/routes.py deleted file mode 100644 index b888cef75865598bf0a850b158e5119872a40851..0000000000000000000000000000000000000000 --- a/app/contributions/tesseract_ocr_pipeline_models/routes.py +++ /dev/null @@ -1,75 +0,0 @@ -from flask import abort, flash, redirect, render_template, url_for -from flask_login import login_required, current_user -from app import db -from app.models import TesseractOCRPipelineModel -from . import bp, template_base_dir -from .forms import ( - CreateTesseractOCRPipelineModelForm, - EditTesseractOCRPipelineModelForm -) - - -@bp.route('') -@login_required -def tesseract_ocr_pipeline_models(): - return render_template( - f'{template_base_dir}/tesseract_ocr_pipeline_models.html.j2', - title='Tesseract OCR Pipeline Models' - ) - - -@bp.route('/create', methods=['GET', 'POST']) -@login_required -def create_tesseract_ocr_pipeline_model(): - form_prefix = 'create-tesseract-ocr-pipeline-model-form' - form = CreateTesseractOCRPipelineModelForm(prefix=form_prefix) - if form.is_submitted(): - if not form.validate(): - return {'errors': form.errors}, 400 - try: - topm = TesseractOCRPipelineModel.create( - form.tesseract_model_file.data, - compatible_service_versions=form.compatible_service_versions.data, - description=form.description.data, - publisher=form.publisher.data, - publisher_url=form.publisher_url.data, - publishing_url=form.publishing_url.data, - publishing_year=form.publishing_year.data, - is_public=False, - title=form.title.data, - version=form.version.data, - user=current_user - ) - except OSError: - abort(500) - db.session.commit() - flash(f'Tesseract OCR Pipeline model "{topm.title}" created') - return {}, 201, {'Location': url_for('.tesseract_ocr_pipeline_models')} - return render_template( - f'{template_base_dir}/create_tesseract_ocr_pipeline_model.html.j2', - form=form, - title='Create Tesseract OCR Pipeline Model' - ) - - -@bp.route('/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST']) -@login_required -def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): - topm = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) - form_prefix = 'edit-tesseract-ocr-pipeline-model-form' - form = EditTesseractOCRPipelineModelForm( - data=topm.to_json_serializeable(), - prefix=form_prefix - ) - if form.validate_on_submit(): - form.populate_obj(topm) - if db.session.is_modified(topm): - flash(f'Tesseract OCR Pipeline model "{topm.title}" updated') - db.session.commit() - return redirect(url_for('.tesseract_ocr_pipeline_models')) - return render_template( - f'{template_base_dir}/tesseract_ocr_pipeline_model.html.j2', - form=form, - tesseract_ocr_pipeline_model=topm, - title=f'{topm.title} {topm.version}' - ) diff --git a/app/corpora/routes.py b/app/corpora/routes.py index 5484fb50af31a6a80984eeffa475aa1e02cc4953..82701cea4e8a418f370375d9b87aa2d956282faa 100644 --- a/app/corpora/routes.py +++ b/app/corpora/routes.py @@ -1,23 +1,18 @@ -from flask import ( - abort, - flash, - Markup, - redirect, - render_template, - url_for -) +from flask import abort, flash, redirect, render_template, url_for from flask_login import current_user, login_required from .decorators import corpus_follower_permission_required from app import db -from app.models import ( - Corpus, - CorpusFollowerAssociation, - CorpusFollowerRole, -) +from app.models import Corpus, CorpusFollowerAssociation, CorpusFollowerRole from . import bp from .forms import CreateCorpusForm +@bp.route('') +@login_required +def corpora(): + return redirect(url_for('main.dashboard', _anchor='corpora')) + + @bp.route('/create', methods=['GET', 'POST']) @login_required def create_corpus(): diff --git a/app/main/routes.py b/app/main/routes.py index 918f7414d2415f510dbf28ca0a92aa63878b6fc7..5399b5e96aeff112a75a3b2f85295917cf417c22 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -1,4 +1,5 @@ from flask import flash, redirect, render_template, url_for +from flask_breadcrumbs import register_breadcrumb from flask_login import current_user, login_required, login_user from app.auth.forms import LoginForm from app.models import Corpus, User @@ -6,6 +7,7 @@ from . import bp @bp.route('', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.', '<i class="material-icons">home</i>') def index(): form = LoginForm(prefix='login-form') if form.validate_on_submit(): @@ -20,37 +22,44 @@ def index(): @bp.route('/faq') +@register_breadcrumb(bp, '.faq', 'Frequently Asked Questions') def faq(): return render_template('main/faq.html.j2', title='Frequently Asked Questions') @bp.route('/dashboard') +@register_breadcrumb(bp, '.dashboard', 'Dashboard') @login_required def dashboard(): return render_template('main/dashboard.html.j2', title='Dashboard') @bp.route('/user_manual') +@register_breadcrumb(bp, '.user_manual', 'User manual') def user_manual(): return render_template('main/user_manual.html.j2', title='User manual') @bp.route('/news') +@register_breadcrumb(bp, '.news', 'News') def news(): return render_template('main/news.html.j2', title='News') @bp.route('/privacy_policy') +@register_breadcrumb(bp, '.privacy_policy', 'Private statement (GDPR)') def privacy_policy(): return render_template('main/privacy_policy.html.j2', title='Privacy statement (GDPR)') @bp.route('/terms_of_use') +@register_breadcrumb(bp, '.terms_of_use', 'Terms of Use') def terms_of_use(): return render_template('main/terms_of_use.html.j2', title='Terms of Use') @bp.route('/social-area') +@register_breadcrumb(bp, '.social_area', 'Social Area') def social_area(): users = [ u.to_json_serializeable(relationships=True, filter_by_privacy_settings=True,) for u diff --git a/app/services/routes.py b/app/services/routes.py index 0fb4b1684deb0cf9ddbbe85262262766e6056e0c..5d5a69a025d5a79913a5d280456af189168e53a6 100644 --- a/app/services/routes.py +++ b/app/services/routes.py @@ -1,4 +1,5 @@ -from flask import abort, current_app, flash, make_response, Markup, render_template, request +from flask import abort, current_app, flash, Markup, redirect, render_template, request, url_for +from flask_breadcrumbs import register_breadcrumb from flask_login import current_user, login_required import requests from app import db, hashids @@ -18,7 +19,15 @@ from .forms import ( ) +@bp.route('/services') +@register_breadcrumb(bp, '.', 'Services') +@login_required +def services(): + return redirect(url_for('main.dashboard')) + + @bp.route('/file-setup-pipeline', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.file_setup_pipeline', 'File Setup') @login_required def file_setup_pipeline(): service = 'file-setup-pipeline' @@ -60,6 +69,7 @@ def file_setup_pipeline(): @bp.route('/tesseract-ocr-pipeline', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.tesseract_ocr_pipeline', 'Tesseract OCR Pipeline') @login_required def tesseract_ocr_pipeline(): service_name = 'tesseract-ocr-pipeline' @@ -109,6 +119,7 @@ def tesseract_ocr_pipeline(): @bp.route('/transkribus-htr-pipeline', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.transkribus_htr_pipeline', 'Transkribus HTR Pipeline') @login_required def transkribus_htr_pipeline(): if not current_app.config.get('NOPAQUE_TRANSKRIBUS_ENABLED'): @@ -168,6 +179,7 @@ def transkribus_htr_pipeline(): @bp.route('/spacy-nlp-pipeline', methods=['GET', 'POST']) +@register_breadcrumb(bp, '.spacy_nlp_pipeline', 'SpaCy NLP Pipeline') @login_required def spacy_nlp_pipeline(): service = 'spacy-nlp-pipeline' @@ -213,9 +225,10 @@ def spacy_nlp_pipeline(): @bp.route('/corpus-analysis') +@register_breadcrumb(bp, '.corpus_analysis', 'Corpus Analysis') @login_required def corpus_analysis(): return render_template( 'services/corpus_analysis.html.j2', - title='Corpus analysis' + title='Corpus Analysis' ) diff --git a/app/templates/_navbar.html.j2 b/app/templates/_navbar.html.j2 index d943c0e4b597a893b628fbcc6a9eeeacb9e0db1f..2790ef1a41d38fa2f710a85fe993cc0b5b907d80 100644 --- a/app/templates/_navbar.html.j2 +++ b/app/templates/_navbar.html.j2 @@ -14,10 +14,12 @@ </div> <div class="nav-content primary-variant-color"> <ul class="tabs tabs-transparent"> - <li class="tab"><a href="{{ url_for('main.index') }}" target="_self"><i class="material-icons">home</i></a></li> - {% if breadcrumbs is defined %} - {{ breadcrumbs }} + {%- for breadcrumb in breadcrumbs -%} + <li class="tab"><a {{ 'class="active"' if loop.last }} href="{{ breadcrumb.url }}" target="_self">{{ breadcrumb.text }}</a></li> + {% if not loop.last %} + <li class="tab disabled"><i class="material-icons">navigate_next</i></li> {% endif %} + {%- endfor -%} </ul> {% if current_user.is_authenticated %} <a class="btn-floating btn-large halfway-fab modal-trigger pink tooltipped waves-effect waves-light" data-tooltip="Roadmap" href="#roadmap-modal"><i class="material-icons">explore</i></a> diff --git a/app/templates/_sidenav.html.j2 b/app/templates/_sidenav.html.j2 index 0027772e260e7743468c9699d92cf071197ff641..fbaeddbe0524b2bd07556ed2698bbd7a2f9af4ff 100644 --- a/app/templates/_sidenav.html.j2 +++ b/app/templates/_sidenav.html.j2 @@ -35,7 +35,7 @@ <li class="service-color service-color-border border-darken" data-service="transkribus-htr-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.transkribus_htr_pipeline') }}"><i class="nopaque-icons service-icons" data-service="transkribus-htr-pipeline"></i>HTR</a></li> {% endif %} <li class="service-color service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.spacy_nlp_pipeline') }}"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>NLP</a></li> - <li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icons" data-service="corpus-analysis"></i>Corpus analysis</a></li> + <li class="service-color service-color-border border-darken" data-service="corpus-analysis" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.corpus_analysis') }}"><i class="nopaque-icons service-icons" data-service="corpus-analysis"></i>Corpus Analysis</a></li> <li><div class="divider"></div></li> <li><a class="subheader">Account</a></li> <li><a href="{{ url_for('settings.settings') }}"><i class="material-icons">settings</i>General Settings</a></li> diff --git a/app/templates/admin/_breadcrumbs.html.j2 b/app/templates/admin/_breadcrumbs.html.j2 deleted file mode 100644 index c4a640466e8478a8741776fadd206f0d13fb655e..0000000000000000000000000000000000000000 --- a/app/templates/admin/_breadcrumbs.html.j2 +++ /dev/null @@ -1,18 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.index') }}" target="_self">Administration</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('.users') %} -<li class="tab"><a class="active" href="{{ url_for('.users') }}" target="_self">Users</a></li> -{% elif request.path == url_for('.user', user_id=user.id) %} -<li class="tab"><a href="{{ url_for('.users') }}" target="_self">Users</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.user', user_id=user.id) }}" target="_self">{{ user.username }}</a></li> -{% elif request.path == url_for('.edit_user', user_id=user.id) %} -<li class="tab"><a href="{{ url_for('.users') }}" target="_self">Users</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.user', user_id=user.id) }}" target="_self">{{ user.username }}</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.edit_user', user_id=user.id) }}" target="_self">Edit</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/admin/edit_user.html.j2 b/app/templates/admin/edit_user.html.j2 index c963b7f73d4de0edebc6984deb3b04f10f18fe24..0ac4f27dd4d260c9c427573cd691efb8430d5937 100644 --- a/app/templates/admin/edit_user.html.j2 +++ b/app/templates/admin/edit_user.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "admin/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block page_content %} diff --git a/app/templates/admin/user.html.j2 b/app/templates/admin/user.html.j2 index b4b0e30322c9dcdaecd98be307085f4b74d56130..aa4899cef7150f3a3c3f474537ec91564dcdd61a 100644 --- a/app/templates/admin/user.html.j2 +++ b/app/templates/admin/user.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "admin/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/admin/users.html.j2 b/app/templates/admin/users.html.j2 index c96024cffdf1d1a9ae8f1ecd1ade599351d40c54..25b27c9512b8435ee361f821f616325eb7293a53 100644 --- a/app/templates/admin/users.html.j2 +++ b/app/templates/admin/users.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "admin/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/auth/_breadcrumbs.html.j2 b/app/templates/auth/_breadcrumbs.html.j2 deleted file mode 100644 index 2f46d9dc206032274281c6c671aa288549101fc5..0000000000000000000000000000000000000000 --- a/app/templates/auth/_breadcrumbs.html.j2 +++ /dev/null @@ -1,14 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('.login') %} -<li class="tab"><a class="active" href="{{ url_for('.login') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.register') %} -<li class="tab"><a class="active" href="{{ url_for('.register') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.reset_password', token=token) %} -<li class="tab"><a class="active" href="{{ url_for('.reset_password', token=token) }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.reset_password_request') %} -<li class="tab"><a class="active" href="{{ url_for('.reset_password_request') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.unconfirmed') %} -<li class="tab"><a class="active" href="{{ url_for('.unconfirmed') }}" target="_self">{{ title }}</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/auth/login.html.j2 b/app/templates/auth/login.html.j2 index 213c0a5f19bc24183951b8c050f3fe2a862b7184..7aa402f6bc30660eb97447489158a7dfe7dc1cea 100644 --- a/app/templates/auth/login.html.j2 +++ b/app/templates/auth/login.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "auth/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} diff --git a/app/templates/auth/register.html.j2 b/app/templates/auth/register.html.j2 index 69a019126dd1eb314bfd628da3741c5cc3667e93..d8e023a779eb4a73cbb2d1c09aed8a1aeb3ba039 100644 --- a/app/templates/auth/register.html.j2 +++ b/app/templates/auth/register.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "auth/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} diff --git a/app/templates/auth/reset_password.html.j2 b/app/templates/auth/reset_password.html.j2 index 06f11059b759db639572621195fefac4b2dc6f63..7df460bbdfb8785c68fb949e997c62511180c100 100644 --- a/app/templates/auth/reset_password.html.j2 +++ b/app/templates/auth/reset_password.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "auth/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block page_content %} diff --git a/app/templates/auth/reset_password_request.html.j2 b/app/templates/auth/reset_password_request.html.j2 index a94d18da91521dbd6b38ec67e04be35b1366dc3c..5bf28111670963d07b223e222abeae7cee0b6b7c 100644 --- a/app/templates/auth/reset_password_request.html.j2 +++ b/app/templates/auth/reset_password_request.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "auth/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block page_content %} diff --git a/app/templates/auth/unconfirmed.html.j2 b/app/templates/auth/unconfirmed.html.j2 index 26384eccbd71a207ee690c6486c87f5b5dca11d5..f927fcfff82527f37ab4d5862c3324f708bea915 100644 --- a/app/templates/auth/unconfirmed.html.j2 +++ b/app/templates/auth/unconfirmed.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "auth/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/contributions/_breadcrumbs.html.j2 b/app/templates/contributions/_breadcrumbs.html.j2 deleted file mode 100644 index ab64dec4794d6df46d5f50e6fbbeb6cc324733ea..0000000000000000000000000000000000000000 --- a/app/templates/contributions/_breadcrumbs.html.j2 +++ /dev/null @@ -1,46 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('.contributions') %} -<li class="tab"><a class="active" href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -{% elif request.path == url_for('.tesseract_ocr_pipeline_models')%} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.tesseract_ocr_pipeline_models') }}" target="_self">Tesseract OCR Pipeline Models</a></li> -{% elif request.path == url_for('.spacy_nlp_pipeline_models')%} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.spacy_nlp_pipeline_models') }}" target="_self">SpaCy NLP Pipeline Models</a></li> -{% elif request.path == url_for('.create_tesseract_ocr_pipeline_model') %} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" target="_self">Tesseract OCR Pipeline Models</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.create_tesseract_ocr_pipeline_model') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.create_spacy_nlp_pipeline_model') %} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.spacy_nlp_pipeline_models') }}" target="_self">SpaCy NLP Pipeline Models</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.create_spacy_nlp_pipeline_model') }}" target="_self">{{ title }}</a></li> -{% elif tesseract_ocr_pipeline_model and request.path == url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id) %} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" target="_self">Tesseract OCR Pipeline Models</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"> - <a class="active" href="{{ url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id) }}" target="_self"> - {{ tesseract_ocr_pipeline_model.title }} {{ tesseract_ocr_pipeline_model.version }} - </a> -</li> -{% elif spacy_nlp_pipeline_model and request.path == url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id) %} -<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.spacy_nlp_pipeline_models') }}" target="_self">SpaCy NLP Pipeline Models</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"> - <a class="active" href="{{ url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id) }}" target="_self"> - {{ spacy_nlp_pipeline_model.title }} {{ spacy_nlp_pipeline_model.version }} - </a> -</li> -{% endif %} -{% endset %} diff --git a/app/templates/contributions/contributions.html.j2 b/app/templates/contributions/contributions.html.j2 index efefcbbb2385915d9d3e8f4de39f3d1debe46027..a09447230ef7549b80d9be2444a8eb12df2a17b6 100644 --- a/app/templates/contributions/contributions.html.j2 +++ b/app/templates/contributions/contributions.html.j2 @@ -10,7 +10,7 @@ <div class="col s4"> <div class="card extension-selector hoverable service-color" data-service="tesseract-ocr-pipeline"> - <a href="{{ url_for('.tesseract_ocr_pipeline_models.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> + <a href="{{ url_for('.tesseract_ocr_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> <div class="card-content"> <span class="card-title" data-service="tesseract-ocr-pipeline"><i class="nopaque-icons service-icons" data-service="tesseract-ocr-pipeline"></i>Tesseract OCR Pipeline Models</span> <p>Here you can see and edit the models that you have created. You can also create new models.</p> @@ -20,7 +20,7 @@ <div class="col s4"> <div class="card extension-selector hoverable service-color" data-service="spacy-nlp-pipeline"> - <a href="{{ url_for('.spacy_nlp_pipeline_models.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> + <a href="{{ url_for('.spacy_nlp_pipeline_models') }}" style="position: absolute; width: 100%; height: 100%;"></a> <div class="card-content"> <span class="card-title"><i class="nopaque-icons service-icons" data-service="spacy-nlp-pipeline"></i>SpaCy NLP Pipeline Models</span> <p>Here you can see and edit the models that you have created. You can also create new models.</p> diff --git a/app/templates/contributions/spacy_nlp_pipeline_models/create_spacy_nlp_pipeline_model.html.j2 b/app/templates/contributions/create_spacy_nlp_pipeline_model.html.j2 similarity index 100% rename from app/templates/contributions/spacy_nlp_pipeline_models/create_spacy_nlp_pipeline_model.html.j2 rename to app/templates/contributions/create_spacy_nlp_pipeline_model.html.j2 diff --git a/app/templates/contributions/tesseract_ocr_pipeline_models/create_tesseract_ocr_pipeline_model.html.j2 b/app/templates/contributions/create_tesseract_ocr_pipeline_model.html.j2 similarity index 100% rename from app/templates/contributions/tesseract_ocr_pipeline_models/create_tesseract_ocr_pipeline_model.html.j2 rename to app/templates/contributions/create_tesseract_ocr_pipeline_model.html.j2 diff --git a/app/templates/contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_model.html.j2 b/app/templates/contributions/spacy_nlp_pipeline_model.html.j2 similarity index 100% rename from app/templates/contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_model.html.j2 rename to app/templates/contributions/spacy_nlp_pipeline_model.html.j2 diff --git a/app/templates/contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_models.html.j2 b/app/templates/contributions/spacy_nlp_pipeline_models.html.j2 similarity index 100% rename from app/templates/contributions/spacy_nlp_pipeline_models/spacy_nlp_pipeline_models.html.j2 rename to app/templates/contributions/spacy_nlp_pipeline_models.html.j2 diff --git a/app/templates/contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_model.html.j2 b/app/templates/contributions/tesseract_ocr_pipeline_model.html.j2 similarity index 100% rename from app/templates/contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_model.html.j2 rename to app/templates/contributions/tesseract_ocr_pipeline_model.html.j2 diff --git a/app/templates/contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_models.html.j2 b/app/templates/contributions/tesseract_ocr_pipeline_models.html.j2 similarity index 100% rename from app/templates/contributions/tesseract_ocr_pipeline_models/tesseract_ocr_pipeline_models.html.j2 rename to app/templates/contributions/tesseract_ocr_pipeline_models.html.j2 diff --git a/app/templates/corpora/_breadcrumbs.html.j2 b/app/templates/corpora/_breadcrumbs.html.j2 deleted file mode 100644 index bdbe0f3449c9a514c920e01055f728aba56d1419..0000000000000000000000000000000000000000 --- a/app/templates/corpora/_breadcrumbs.html.j2 +++ /dev/null @@ -1,28 +0,0 @@ -{# {% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('main.dashboard', _anchor='jobs') }}" target="_self">My corpora</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('.create_corpus') %} -<li class="tab"><a class="active" href="{{ url_for('.create_corpus') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.import_corpus') %} -<li class="tab"><a class="active" href="{{ url_for('.import_corpus') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.corpus', corpus_id=corpus.id) %} -<li class="tab"><a class="active" href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li> -{% elif request.path == url_for('.analyse_corpus', corpus_id=corpus.id) %} -<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.analyse_corpus', corpus_id=corpus.id) }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.create_corpus_file', corpus_id=corpus.id) %} -<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id, _anchor='files') }}" target="_self">Corpus files</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.create_corpus_file', corpus_id=corpus.id) }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.corpus_file', corpus_file_id=corpus_file.id, corpus_id=corpus.id) %} -<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id) }}" target="_self">{{ corpus.title }}</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('.corpus', corpus_id=corpus.id, _anchor='files') }}" target="_self">Corpus files</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.corpus_file', corpus_file_id=corpus_file.id, corpus_id=corpus.id) }}" target="_self">{{ corpus_file.author }}: {{ corpus_file.title }} ({{ corpus_file.publishing_year }})</a></li> -{% endif %} -{% endset %} #} diff --git a/app/templates/corpora/corpus.html.j2 b/app/templates/corpora/corpus.html.j2 index 053dbdc0a775997a7c0b89158d729796dcf28b7f..f17e1e884923b03dabadef535ab255897c68f689 100644 --- a/app/templates/corpora/corpus.html.j2 +++ b/app/templates/corpora/corpus.html.j2 @@ -1,6 +1,5 @@ {% extends "base.html.j2" %} {% import "materialize/wtf.html.j2" as wtf %} -{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/corpora/create_corpus.html.j2 b/app/templates/corpora/create_corpus.html.j2 index ccb4987724ab3d7d8bc7a8c8aa4bf79d3537df0d..5feb72254d7f4d5f2240146b639dda07e2325f75 100644 --- a/app/templates/corpora/create_corpus.html.j2 +++ b/app/templates/corpora/create_corpus.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/corpora/files/corpus_file.html.j2 b/app/templates/corpora/files/corpus_file.html.j2 index 781ea05915613f30b9855f4e2d5755c3ae045e1e..28a762d41a7870c09da5692c1aec935e228450f8 100644 --- a/app/templates/corpora/files/corpus_file.html.j2 +++ b/app/templates/corpora/files/corpus_file.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/corpora/files/create_corpus_file.html.j2 b/app/templates/corpora/files/create_corpus_file.html.j2 index 8cff13a61803d50a68efa89ffa954f10cb44af0e..ff634294274c579f4f517ce2c557f0ed86988902 100644 --- a/app/templates/corpora/files/create_corpus_file.html.j2 +++ b/app/templates/corpora/files/create_corpus_file.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/corpora/import_corpus.html.j2 b/app/templates/corpora/import_corpus.html.j2 index 957668e6817d8b306c02f2760d336e27ac1d7d99..dd0806a75c7e7a04f2bf5d1a53c79e0c24e20212 100644 --- a/app/templates/corpora/import_corpus.html.j2 +++ b/app/templates/corpora/import_corpus.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "corpora/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/jobs/_breadcrumbs.html.j2 b/app/templates/jobs/_breadcrumbs.html.j2 deleted file mode 100644 index e3de43f313d7d460f3196d2889f10136803b0a82..0000000000000000000000000000000000000000 --- a/app/templates/jobs/_breadcrumbs.html.j2 +++ /dev/null @@ -1,8 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('main.dashboard', _anchor='jobs') }}" target="_self">My jobs</a></li> -{% if request.path == url_for('.job', job_id=job.id) %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a class="active" href="{{ url_for('.job', job_id=job.id) }}" target="_self">{{ job.title }}</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/jobs/job.html.j2 b/app/templates/jobs/job.html.j2 index b5055ce61fd84a1ae3dacbd2eedb20773b910503..51f2fc6daddd5c232997512433f8e9f00b6b2beb 100644 --- a/app/templates/jobs/job.html.j2 +++ b/app/templates/jobs/job.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "jobs/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block main_attribs %} class="service-scheme" data-service="{{ job.service }}"{% endblock main_attribs %} diff --git a/app/templates/main/_breadcrumbs.html.j2 b/app/templates/main/_breadcrumbs.html.j2 deleted file mode 100644 index d65978d65b2c92b072b8c445452d38719f4ca0c2..0000000000000000000000000000000000000000 --- a/app/templates/main/_breadcrumbs.html.j2 +++ /dev/null @@ -1,14 +0,0 @@ -{% set breadcrumbs %} -{% if not (request.path == url_for('.index')) %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% endif %} -{% if request.path == url_for('.faq') %} -<li class="tab"><a class="active" href="{{ url_for('.faq') }}" target="_self">Frequently Asked Questions</a></li> -{% elif request.path == url_for('.dashboard') %} -<li class="tab"><a class="active" href="{{ url_for('.dashboard') }}" target="_self">Dashboard</a></li> -{% elif request.path == url_for('.news') %} -<li class="tab"><a class="active" href="{{ url_for('.news') }}" target="_self">News</a></li> -{% elif request.path == url_for('.terms_of_use') %} -<li class="tab"><a class="active" href="{{ url_for('.terms_of_use') }}" target="_self">Terms of use</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2 index 5474db970b33fc11aedb8245a4a9b1149a23dbc4..1598e1396eab87ca038cd96a0bb0cc2101379c44 100644 --- a/app/templates/main/dashboard.html.j2 +++ b/app/templates/main/dashboard.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/faq.html.j2 b/app/templates/main/faq.html.j2 index fb10e3b49c1bf1f80af95d08313b9c6856b8a450..5c1680072e0f5b0b9174f0db2b8d2802ea1b3b90 100644 --- a/app/templates/main/faq.html.j2 +++ b/app/templates/main/faq.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/index.html.j2 b/app/templates/main/index.html.j2 index 74bfa30646af16ad69f1c340c24bd8cce846e0a0..7b80a794b9202a304e80000b1c2d807e99bf8fd9 100644 --- a/app/templates/main/index.html.j2 +++ b/app/templates/main/index.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block page_content %} diff --git a/app/templates/main/news.html.j2 b/app/templates/main/news.html.j2 index b8961b023382bfb3b3373961378e9dffa10bb887..d1111d8b05363691474cd41e2cf2e213a15b5421 100644 --- a/app/templates/main/news.html.j2 +++ b/app/templates/main/news.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/news_new.html.j2 b/app/templates/main/news_new.html.j2 index d3e2f9b68c673f2a24b46346f382cff830e5ef61..d2b339e3ddc87ad497527ed99e5041a22cbd319c 100644 --- a/app/templates/main/news_new.html.j2 +++ b/app/templates/main/news_new.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/privacy_policy.html.j2 b/app/templates/main/privacy_policy.html.j2 index ff22b10ad8b9b0befa524dc3e5b0bfd14d9e63e4..c55ae722916b0ee5cb77b0140ab8915f5ce06a28 100644 --- a/app/templates/main/privacy_policy.html.j2 +++ b/app/templates/main/privacy_policy.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/terms_of_use.html.j2 b/app/templates/main/terms_of_use.html.j2 index baedd0a28530a56d4660c9aae335fbff15eddaf2..d61084d64177fa7e1e9113508766a91c8dd43600 100644 --- a/app/templates/main/terms_of_use.html.j2 +++ b/app/templates/main/terms_of_use.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/main/user_manual.html.j2 b/app/templates/main/user_manual.html.j2 index 0da85809df2ca2487b55756d61b7a69138c8bc23..2ef1da01a3cd79f22f1be64634bc6f643adb7acc 100644 --- a/app/templates/main/user_manual.html.j2 +++ b/app/templates/main/user_manual.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "main/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block page_content %} <div class="container"> diff --git a/app/templates/services/_breadcrumbs.html.j2 b/app/templates/services/_breadcrumbs.html.j2 deleted file mode 100644 index a08beafab6595a87910f44350e8a569205a7a79c..0000000000000000000000000000000000000000 --- a/app/templates/services/_breadcrumbs.html.j2 +++ /dev/null @@ -1,16 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -<li class="tab"><a href="{{ url_for('main.index', _anchor='services') }}" target="_self">Processes & Services</a></li> -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('.corpus_analysis') %} -<li class="tab"><a class="active" href="{{ url_for('.corpus_analysis') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.file_setup_pipeline') %} -<li class="tab"><a class="active" href="{{ url_for('.file_setup_pipeline') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.spacy_nlp_pipeline') %} -<li class="tab"><a class="active" href="{{ url_for('.spacy_nlp_pipeline') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.tesseract_ocr_pipeline') %} -<li class="tab"><a class="active" href="{{ url_for('.tesseract_ocr_pipeline') }}" target="_self">{{ title }}</a></li> -{% elif request.path == url_for('.transkribus_htr_pipeline') %} -<li class="tab"><a class="active" href="{{ url_for('.transkribus_htr_pipeline') }}" target="_self">{{ title }}</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/services/corpus_analysis.html.j2 b/app/templates/services/corpus_analysis.html.j2 index a7e3da8e7a04634df25bb02047168a847e06897f..9ddc9ec3d1fa3e2c3bf2d5152fe8e70ad07a0f28 100644 --- a/app/templates/services/corpus_analysis.html.j2 +++ b/app/templates/services/corpus_analysis.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "services/_breadcrumbs.html.j2" import breadcrumbs with context %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} diff --git a/app/templates/services/file_setup_pipeline.html.j2 b/app/templates/services/file_setup_pipeline.html.j2 index ebc4cfc4cba500de29ff5ced062525244603c9ce..0f046e98b0860e2369d689562acb0f6e6537e21e 100644 --- a/app/templates/services/file_setup_pipeline.html.j2 +++ b/app/templates/services/file_setup_pipeline.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "services/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="file-setup-pipeline"{% endblock main_attribs %} diff --git a/app/templates/services/spacy_nlp_pipeline.html.j2 b/app/templates/services/spacy_nlp_pipeline.html.j2 index 8f466e3dc9431583ecef8e641dd9740d572daa2b..2ebba838724ba9dae11f63ea8e199efdefa94832 100644 --- a/app/templates/services/spacy_nlp_pipeline.html.j2 +++ b/app/templates/services/spacy_nlp_pipeline.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "services/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %} @@ -77,7 +76,7 @@ {{ form.model.label }} <span class="helper-text"> <a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#0064A3;">help_outline</i></a> - <a class="tooltipped" href="{{ url_for('contributions.spacy_nlp_pipeline_models.create_spacy_nlp_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own spaCy NLP models"><i class="material-icons" style="color:#0064A3">new_label</i></a> + <a class="tooltipped" href="{{ url_for('contributions.create_spacy_nlp_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own spaCy NLP models"><i class="material-icons" style="color:#0064A3">new_label</i></a> </span> </div> </div> diff --git a/app/templates/services/tesseract_ocr_pipeline.html.j2 b/app/templates/services/tesseract_ocr_pipeline.html.j2 index 11d65c6439850bfb2f18787de2f911bb56efde3a..9b1d61877be4ce59eba286fb669a31b31d1f16c2 100644 --- a/app/templates/services/tesseract_ocr_pipeline.html.j2 +++ b/app/templates/services/tesseract_ocr_pipeline.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "services/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %} @@ -59,7 +58,7 @@ {{ form.model.label }} <span class="helper-text"> <a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#00A58B;">help_outline</i></a> - <a class="tooltipped" href="{{ url_for('contributions.tesseract_ocr_pipeline_models.create_tesseract_ocr_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own Tesseract OCR models"><i class="material-icons" style="color:#00A58B">new_label</i></a> + <a class="tooltipped" href="{{ url_for('contributions.create_tesseract_ocr_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own Tesseract OCR models"><i class="material-icons" style="color:#00A58B">new_label</i></a> </span> {% for error in form.model.errors %} <span class="helper-text error-color-text">{{ error }}</span> diff --git a/app/templates/services/transkribus_htr_pipeline.html.j2 b/app/templates/services/transkribus_htr_pipeline.html.j2 index f5468ce97ebc065a95f16981d56542101121da53..50eb3b6e1d69960c1fe1f6b38e1252d8308f4d87 100644 --- a/app/templates/services/transkribus_htr_pipeline.html.j2 +++ b/app/templates/services/transkribus_htr_pipeline.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "services/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block main_attribs %} class="service-scheme" data-service="transkribus-htr-pipeline"{% endblock main_attribs %} diff --git a/app/templates/settings/_breadcrumbs.html.j2 b/app/templates/settings/_breadcrumbs.html.j2 deleted file mode 100644 index 3b5077bfd8e7dd07315128eef5e87fcf34b4721b..0000000000000000000000000000000000000000 --- a/app/templates/settings/_breadcrumbs.html.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{% set breadcrumbs %} -<li class="tab disabled"><i class="material-icons">navigate_next</i></li> -{% if request.path == url_for('settings.settings') %} -<li class="tab"><a{%if request.path == url_for('settings.settings') %} class="active"{% endif %} href="{{ url_for('settings.settings') }}" target="_self">Settings</a></li> -{% endif %} -{% endset %} diff --git a/app/templates/settings/settings.html.j2 b/app/templates/settings/settings.html.j2 index e9cfb97bda684a8a654a6d0bbde8bc1a19564ae1..fd830aee644b4c24513af2cb00377f4ebeddf04d 100644 --- a/app/templates/settings/settings.html.j2 +++ b/app/templates/settings/settings.html.j2 @@ -1,5 +1,4 @@ {% extends "base.html.j2" %} -{% from "settings/_breadcrumbs.html.j2" import breadcrumbs with context %} {% import "materialize/wtf.html.j2" as wtf %} {% block page_content %} diff --git a/requirements.txt b/requirements.txt index 838cee8fe7e067fa51462010d6b50f507849c1dc..e621d2ad4947a3df3b27513bd8bde5d72f2bf567 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ eventlet Flask==2.1.3 Flask-APScheduler Flask-Assets +Flask-Breadcrumbs Flask-Hashids==1.0.1 Flask-HTTPAuth Flask-Login