diff --git a/app/contributions/forms.py b/app/contributions/forms.py index 8eb44842..04030fd0 100644 --- a/app/contributions/forms.py +++ b/app/contributions/forms.py @@ -12,6 +12,7 @@ from wtforms import ( from wtforms.validators import InputRequired, Length from app.services import SERVICES + class CreateContributionBaseForm(FlaskForm): title = StringField( 'Title', @@ -46,31 +47,8 @@ class CreateContributionBaseForm(FlaskForm): ) submit = SubmitField() -class EditForm(CreateContributionBaseForm): - def prefill(self, model_file): - ''' Pre-fill the form with data of an exististing corpus file ''' - self.title.data = model_file.title - self.description.data = model_file.description - self.publisher.data = model_file.publisher - self.publishing_year.data = model_file.publishing_year - self.publisher_url.data = model_file.publisher_url - self.publishing_url.data = model_file.publishing_url - self.version.data = model_file.version - self.shared.data = model_file.shared -class EditTesseractOCRModelForm(EditForm): - pass - -class EditSpaCyNLPPipelineModelForm(EditForm): - pipeline_name = StringField( - 'Pipeline name', - validators=[InputRequired(), Length(max=64)] - ) - def prefill(self, model_file): - super().prefill(model_file) - self.pipeline_name.data = model_file.pipeline_name - -class TesseractOCRModelContributionForm(CreateContributionBaseForm): +class CreateTesseractOCRPipelineModelForm(CreateContributionBaseForm): tesseract_model_file = FileField( 'File', validators=[FileRequired()] @@ -78,6 +56,7 @@ class TesseractOCRModelContributionForm(CreateContributionBaseForm): compatible_service_versions = SelectMultipleField( 'Compatible service versions' ) + def validate_tesseract_model_file(self, field): current_app.logger.warning(field.data.filename) if not field.data.filename.lower().endswith('.traineddata'): @@ -92,7 +71,8 @@ class TesseractOCRModelContributionForm(CreateContributionBaseForm): ] self.compatible_service_versions.default = '' -class SpacyNLPModelContributionForm(CreateContributionBaseForm): + +class CreateSpaCyNLPPipelineModelForm(CreateContributionBaseForm): spacy_model_file = FileField( 'File', validators=[FileRequired()] @@ -104,16 +84,45 @@ class SpacyNLPModelContributionForm(CreateContributionBaseForm): 'Pipeline name', validators=[InputRequired(), Length(max=64)] ) + def validate_spacy_model_file(self, field): current_app.logger.warning(field.data.filename) if not field.data.filename.lower().endswith('.tar.gz'): raise ValidationError('.tar.gz files only!') def __init__(self, *args, **kwargs): - service_manifest = SERVICES['spacy-nlp-pipeline'] 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 EditContributionBaseForm(CreateContributionBaseForm): + def prefill(self, model_file): + ''' Pre-fill the form with data of an exististing corpus file ''' + self.title.data = model_file.title + self.description.data = model_file.description + self.publisher.data = model_file.publisher + self.publishing_year.data = model_file.publishing_year + self.publisher_url.data = model_file.publisher_url + self.publishing_url.data = model_file.publishing_url + self.version.data = model_file.version + self.shared.data = model_file.shared + + +class EditTesseractOCRPipelineModelForm(EditContributionBaseForm): + pass + + +class EditSpaCyNLPPipelineModelForm(EditContributionBaseForm): + pipeline_name = StringField( + 'Pipeline name', + validators=[InputRequired(), Length(max=64)] + ) + + def prefill(self, model_file): + super().prefill(model_file) + self.pipeline_name.data = model_file.pipeline_name diff --git a/app/contributions/routes.py b/app/contributions/routes.py index 33355b2d..121fc101 100644 --- a/app/contributions/routes.py +++ b/app/contributions/routes.py @@ -2,10 +2,19 @@ from flask import abort, current_app, flash, Markup, render_template, url_for from flask_login import login_required, current_user from threading import Thread from app import db -from app.decorators import admin_required, permission_required -from app.models import Permission, SpaCyNLPPipelineModel, TesseractOCRPipelineModel +from app.decorators import permission_required +from app.models import ( + Permission, + SpaCyNLPPipelineModel, + TesseractOCRPipelineModel +) from . import bp -from .forms import TesseractOCRModelContributionForm, EditSpaCyNLPPipelineModelForm, EditTesseractOCRModelForm, SpacyNLPModelContributionForm +from .forms import ( + CreateSpaCyNLPPipelineModelForm, + CreateTesseractOCRPipelineModelForm, + EditSpaCyNLPPipelineModelForm, + EditTesseractOCRPipelineModelForm +) @bp.before_request @@ -16,30 +25,17 @@ def before_request(): @bp.route('/') -@login_required -@admin_required def contributions(): - tesseract_ocr_user_models = [ - x for x in current_user.tesseract_ocr_pipeline_models - ] - spacy_nlp_user_models = [ - x for x in current_user.spacy_nlp_pipeline_models - ] return render_template( - 'contributions/contribution_overview.html.j2', - tesseract_ocr_user_models=tesseract_ocr_user_models, - spacy_nlp_user_models=spacy_nlp_user_models, - userId = current_user.hashid, - title='Contribution Overview' + 'contributions/contributions.html.j2', + title='Contributions' ) -@bp.route('/edit-tesseract-model/', methods=['GET', 'POST']) -@login_required + +@bp.route('/tesseract_ocr_pipeline_models/', methods=['GET', 'POST']) def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): - tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404( - tesseract_ocr_pipeline_model_id - ) - form = EditTesseractOCRModelForm(prefix='tesseract-ocr-model-edit-form') + tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) + form = EditTesseractOCRPipelineModelForm(prefix='edit-tesseract-ocr-pipeline-model-form') if form.validate_on_submit(): if tesseract_ocr_pipeline_model.title != form.title.data: tesseract_ocr_pipeline_model.title = form.title.data @@ -58,47 +54,50 @@ def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): if tesseract_ocr_pipeline_model.shared != form.shared.data: tesseract_ocr_pipeline_model.shared = form.shared.data db.session.commit() - message = Markup(f'Model "{tesseract_ocr_pipeline_model.title}" updated') - flash(message, category='corpus') - return {}, 201, {'Location': url_for('contributions.contributions')} + tesseract_ocr_pipeline_model_url = url_for( + '.tesseract_ocr_pipeline_model', + tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id + ) + message = Markup(f'Tesseract OCR Pipeline model "{tesseract_ocr_pipeline_model.title}" updated') + flash(message) + return {}, 201, {'Location': tesseract_ocr_pipeline_model_url} form.prefill(tesseract_ocr_pipeline_model) return render_template( 'contributions/tesseract_ocr_pipeline_model.html.j2', - tesseract_ocr_pipeline_model=tesseract_ocr_pipeline_model, form=form, - title='Edit your Tesseract OCR model' + tesseract_ocr_pipeline_model=tesseract_ocr_pipeline_model, + title='Edit Tesseract OCR Pipeline Model' ) -@bp.route('/edit-tesseract-model/', methods=['DELETE']) -@login_required + +@bp.route('/tesseract_ocr_pipeline_models/', methods=['DELETE']) def delete_tesseract_model(tesseract_ocr_pipeline_model_id): - def _delete_tesseract_model(app, tesseract_ocr_pipeline_model_id): + def _delete_tesseract_ocr_pipeline_model(app, tesseract_ocr_pipeline_model_id): with app.app_context(): - model = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) - model.delete() + tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get(tesseract_ocr_pipeline_model_id) + tesseract_ocr_pipeline_model.delete() db.session.commit() - - model = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) - if not (model.user == current_user or current_user.is_administrator()): + + tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404(tesseract_ocr_pipeline_model_id) + if not (tesseract_ocr_pipeline_model.user == current_user or current_user.is_administrator()): abort(403) thread = Thread( - target=_delete_tesseract_model, + target=_delete_tesseract_ocr_pipeline_model, args=(current_app._get_current_object(), tesseract_ocr_pipeline_model_id) ) thread.start() return {}, 202 -@bp.route('/add-tesseract-ocr-pipeline-model', methods=['GET', 'POST']) -def add_tesseract_ocr_pipeline_model(): - form = TesseractOCRModelContributionForm( - prefix='contribute-tesseract-ocr-pipeline-model-form' - ) + +@bp.route('/tesseract_ocr_pipeline_models/create', methods=['GET', 'POST']) +def create_tesseract_ocr_pipeline_model(): + form = CreateTesseractOCRPipelineModelForm(prefix='create-tesseract-ocr-pipeline-model-form') if form.is_submitted(): if not form.validate(): response = {'errors': form.errors} return response, 400 try: - tesseract_ocr_model = TesseractOCRPipelineModel.create( + tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.create( form.tesseract_model_file.data, compatible_service_versions=form.compatible_service_versions.data, description=form.description.data, @@ -114,27 +113,24 @@ def add_tesseract_ocr_pipeline_model(): except OSError: abort(500) db.session.commit() - message = Markup(f'Model "{tesseract_ocr_model.title}" created') + tesseract_ocr_pipeline_model_url = url_for( + '.tesseract_ocr_pipeline_model', + tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id + ) + message = Markup(f'Tesseract OCR Pipeline model "{tesseract_ocr_pipeline_model.title}" created') flash(message) - return {}, 201, {'Location': url_for('contributions.contributions')} - tesseract_ocr_pipeline_models = [ - x for x in TesseractOCRPipelineModel.query.all() - ] - + return {}, 201, {'Location': tesseract_ocr_pipeline_model_url} return render_template( - 'contributions/contribute_tesseract_ocr_models.html.j2', + 'contributions/create_tesseract_ocr_pipeline_model.html.j2', form=form, - tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models, - title='Tesseract OCR Model Contribution' + title='Create Tesseract OCR Pipeline Model' ) -@bp.route('/edit-spacy-model//', methods=['GET', 'POST']) -@login_required + +@bp.route('/spacy-nlp-pipeline-models/', methods=['GET', 'POST']) def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id): - spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404( - spacy_nlp_pipeline_model_id - ) - form = EditSpaCyNLPPipelineModelForm(prefix='spacy-nlp-model-edit-form') + spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) + form = EditSpaCyNLPPipelineModelForm(prefix='edit-spacy-nlp-pipeline-model-form') if form.validate_on_submit(): if spacy_nlp_pipeline_model.title != form.title.data: spacy_nlp_pipeline_model.title = form.title.data @@ -154,30 +150,33 @@ def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id): spacy_nlp_pipeline_model.version = form.version.data if spacy_nlp_pipeline_model.shared != form.shared.data: spacy_nlp_pipeline_model.shared = form.shared.data + current_app.logger.warning(db.session.dirty) db.session.commit() - message = Markup(f'Model "{spacy_nlp_pipeline_model.title}" updated') - flash(message, category='corpus') - return {}, 201, {'Location': url_for('contributions.contributions')} - print(spacy_nlp_pipeline_model.to_json()) + spacy_nlp_pipeline_model_url = url_for( + '.spacy_nlp_pipeline_model', + spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id + ) + message = Markup(f'SpaCy NLP Pipeline model "{spacy_nlp_pipeline_model.title}" updated') + flash(message) + return {}, 201, {'Location': url_for('.contributions')} form.prefill(spacy_nlp_pipeline_model) return render_template( 'contributions/spacy_nlp_pipeline_model.html.j2', - spacy_nlp_pipeline_model=spacy_nlp_pipeline_model, form=form, - title='Edit your spaCy NLP model' + spacy_nlp_pipeline_model=spacy_nlp_pipeline_model, + title=f'{spacy_nlp_pipeline_model.title} [{spacy_nlp_pipeline_model.version}]' ) -@bp.route('/edit-spacy-model/', methods=['DELETE']) -@login_required +@bp.route('/spacy-nlp-pipeline-models/', methods=['DELETE']) def delete_spacy_model(spacy_nlp_pipeline_model_id): def _delete_spacy_model(app, spacy_nlp_pipeline_model_id): with app.app_context(): - model = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) - model.delete() + spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id) + spacy_nlp_pipeline_model.delete() db.session.commit() - model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) - if not (model.user == current_user or current_user.is_administrator()): + spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id) + if not (spacy_nlp_pipeline_model.user == current_user or current_user.is_administrator()): abort(403) thread = Thread( target=_delete_spacy_model, @@ -186,15 +185,16 @@ def delete_spacy_model(spacy_nlp_pipeline_model_id): thread.start() return {}, 202 -@bp.route('/add-spacy-nlp-pipeline-model', methods=['GET', 'POST']) -def add_spacy_nlp_pipeline_model(): - form = SpacyNLPModelContributionForm(prefix='contribute-spacy-nlp-pipeline-model-form') + +@bp.route('/spacy-nlp-pipeline-models/create', methods=['GET', 'POST']) +def create_spacy_nlp_pipeline_model(): + form = CreateSpaCyNLPPipelineModelForm(prefix='create-spacy-nlp-pipeline-model-form') if form.is_submitted(): if not form.validate(): response = {'errors': form.errors} return response, 400 try: - spacy_nlp_model = SpaCyNLPPipelineModel.create( + spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.create( form.spacy_model_file.data, compatible_service_versions=form.compatible_service_versions.data, description=form.description.data, @@ -211,15 +211,15 @@ def add_spacy_nlp_pipeline_model(): except OSError: abort(500) db.session.commit() - message = Markup(f'Model "{spacy_nlp_model.title}" created') + spacy_nlp_pipeline_model_url = url_for( + '.spacy_nlp_pipeline_model', + spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id + ) + message = Markup(f'SpaCy NLP Pipeline model "{spacy_nlp_pipeline_model.title}" created') flash(message) - return {}, 201, {'Location': url_for('contributions.contributions')} - spacy_nlp_pipeline_models = [ - x for x in SpaCyNLPPipelineModel.query.all() - ] + return {}, 201, {'Location': spacy_nlp_pipeline_model_url} return render_template( - 'contributions/contribute_spacy_nlp_models.html.j2', + 'contributions/create_spacy_nlp_pipeline_model.html.j2', form=form, - spacy_nlp_pipeline_models=spacy_nlp_pipeline_models, - title='spaCy NLP Model Contribution' + title='Create SpaCy NLP Pipeline Model' ) diff --git a/app/models.py b/app/models.py index 93a23461..3bf7f8a7 100644 --- a/app/models.py +++ b/app/models.py @@ -625,6 +625,7 @@ class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model): 'publishing_year': self.publishing_year, 'shared': self.shared, 'title': self.title, + 'version': self.version, **self.file_mixin_to_json() } if backrefs: @@ -735,6 +736,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): 'pipeline_name': self.pipeline_name, 'shared': self.shared, 'title': self.title, + 'version': self.version, **self.file_mixin_to_json() } if backrefs: diff --git a/app/services/services.yml b/app/services/services.yml index c9d61e08..9d99d688 100644 --- a/app/services/services.yml +++ b/app/services/services.yml @@ -1,6 +1,6 @@ # TODO: This could also be done via GitLab/GitHub APIs file-setup-pipeline: - name: 'File setup pipeline' + name: 'File Setup Pipeline' publisher: 'Bielefeld University - CRC 1288 - INF' latest_version: '0.1.0' versions: @@ -38,7 +38,7 @@ transkribus-htr-pipeline: publishing_year: 2022 url: 'https://gitlab.ub.uni-bielefeld.de/sfb1288inf/transkribus-htr-pipeline/-/releases/v0.1.1' spacy-nlp-pipeline: - name: 'spaCy NLP Pipeline' + name: 'SpaCy NLP Pipeline' publisher: 'Bielefeld University - CRC 1288 - INF' latest_version: '0.1.0' versions: diff --git a/app/static/js/RessourceLists/RessourceList.js b/app/static/js/RessourceLists/RessourceList.js index 824db3d1..a2242054 100644 --- a/app/static/js/RessourceLists/RessourceList.js +++ b/app/static/js/RessourceLists/RessourceList.js @@ -10,6 +10,8 @@ class RessourceList { JobList.autoInit(); JobInputList.autoInit(); JobResultList.autoInit(); + SpacyNLPPipelineModelList.autoInit(); + TesseractOCRPipelineModelList.autoInit(); QueryResultList.autoInit(); UserList.autoInit(); } diff --git a/app/static/js/RessourceLists/SpacyNLPModelList.js b/app/static/js/RessourceLists/SpacyNLPModelList.js deleted file mode 100644 index 0e20191b..00000000 --- a/app/static/js/RessourceLists/SpacyNLPModelList.js +++ /dev/null @@ -1,76 +0,0 @@ -class SpacyNLPModelList { - constructor () { - - this.elements = { - spacyNLPModelList: document.querySelector('#spacy-nlp-model-list'), - deleteButtons: document.querySelectorAll('.delete-spacy-model-button'), - editButtons: document.querySelectorAll('.edit-spacy-model-button'), - - } - } - - init () { - let userId = this.elements.spacyNLPModelList.dataset.userId; - - for (let deleteButton of this.elements.deleteButtons) { - deleteButton.addEventListener('click', () => {this.deleteModel(deleteButton, userId);}); - } - - for (let editButton of this.elements.editButtons) { - editButton.addEventListener('click', () => {this.editModel(editButton);}); - } - } - - deleteModel(deleteButton, userId) { - return new Promise((resolve, reject) => { - let modelId = deleteButton.dataset.modelId; - let model = app.data.users[userId].spacy_nlp_pipeline_models[modelId]; - let modalElement = Utils.elementFromString( - ` - - ` - ); - document.querySelector('#modals').appendChild(modalElement); - let modal = M.Modal.init( - modalElement, - { - dismissible: false, - onCloseEnd: () => { - modal.destroy(); - modalElement.remove(); - } - } - ); - let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); - confirmElement.addEventListener('click', (event) => { - let modelTitle = model.title; - fetch(`/contributions/edit-spacy-model/${modelId}`, {method: 'DELETE'}) - .then( - (response) => { - app.flash(`Model "${modelTitle}" marked for deletion`, 'corpus'); - resolve(response); - }, - (response) => { - if (response.status === 403) {app.flash('Forbidden', 'error');} - if (response.status === 404) {app.flash('Not Found', 'error');} - reject(response); - } - ); - }); - modal.open(); - }); - } - - editModel(editButton) { - window.location.href = `/contributions/edit-spacy-model/${editButton.dataset.modelId}`; - } -} diff --git a/app/static/js/RessourceLists/SpacyNLPPipelineModelList.js b/app/static/js/RessourceLists/SpacyNLPPipelineModelList.js new file mode 100644 index 00000000..fcc68a0d --- /dev/null +++ b/app/static/js/RessourceLists/SpacyNLPPipelineModelList.js @@ -0,0 +1,99 @@ +class SpacyNLPPipelineModelList extends RessourceList { + static autoInit() { + for (let spaCyNLPPipelineModelListElement of document.querySelectorAll('.spacy-nlp-pipeline-model-list:not(.no-autoinit)')) { + new SpacyNLPPipelineModelList(spaCyNLPPipelineModelListElement); + } + } + + static options = { + initialHtmlGenerator: (id) => { + return ` +
+ search + + +
+ + + + + + + + + + +
TitleDescriptionBiblio
+
    + `.trim(); + }, + item: ` + + + + (), , + + delete + send + + + `.trim(), + ressourceMapper: (spaCyNLPPipelineModel) => { + return { + 'id': spaCyNLPPipelineModel.id, + 'creation-date': spaCyNLPPipelineModel.creation_date, + 'description': spaCyNLPPipelineModel.description, + 'publisher': spaCyNLPPipelineModel.publisher, + 'publisher-url': spaCyNLPPipelineModel.publisher_url, + 'publishing-url': spaCyNLPPipelineModel.publishing_url, + 'publishing-url-2': spaCyNLPPipelineModel.publishing_url, + 'publishing-year': spaCyNLPPipelineModel.publishing_year, + 'title': spaCyNLPPipelineModel.title, + 'title-2': spaCyNLPPipelineModel.title, + 'version': spaCyNLPPipelineModel.version + }; + }, + sortArgs: ['creation-date', {order: 'desc'}], + valueNames: [ + {data: ['id']}, + {data: ['creation-date']}, + {name: 'publisher-url', attr: 'href'}, + {name: 'publishing-url', attr: 'href'}, + 'description', + 'publisher', + 'publishing-url-2', + 'publishing-year', + 'title', + 'title-2', + 'version' + ] + }; + + constructor(listElement, options = {}) { + super(listElement, {...SpacyNLPPipelineModelList.options, ...options}); + } + + init (user) { + this._init(user.spacy_nlp_pipeline_models); + } + + onClick(event) { + let actionButtonElement = event.target.closest('.action-button'); + let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; + let spaCyNLPPipelineModelElement = event.target.closest('tr'); + let spaCyNLPPipelineModelId = spaCyNLPPipelineModelElement.dataset.id; + switch (action) { + case 'delete-request': { + Utils.deleteSpaCyNLPPipelineModelRequest(this.userId, spaCyNLPPipelineModelId); + break; + } + case 'view': { + window.location.href = `/contributions/spacy-nlp-pipeline-models/${spaCyNLPPipelineModelId}`; + break; + } + default: { + break; + } + } + } +} diff --git a/app/static/js/RessourceLists/TesseractOCRModelList.js b/app/static/js/RessourceLists/TesseractOCRModelList.js deleted file mode 100644 index 782f5d7e..00000000 --- a/app/static/js/RessourceLists/TesseractOCRModelList.js +++ /dev/null @@ -1,76 +0,0 @@ -class TesseractOCRModelList { - constructor () { - - this.elements = { - tesseractOCRModelList: document.querySelector('#tesseract-ocr-model-list'), - deleteButtons: document.querySelectorAll('.delete-button'), - editButtons: document.querySelectorAll('.edit-button'), - - } - } - - init () { - let userId = this.elements.tesseractOCRModelList.dataset.userId; - - for (let deleteButton of this.elements.deleteButtons) { - deleteButton.addEventListener('click', () => {this.deleteModel(deleteButton, userId);}); - } - - for (let editButton of this.elements.editButtons) { - editButton.addEventListener('click', () => {this.editModel(editButton);}); - } - } - - deleteModel(deleteButton, userId) { - return new Promise((resolve, reject) => { - let modelId = deleteButton.dataset.modelId; - let model = app.data.users[userId].tesseract_ocr_pipeline_models[modelId]; - let modalElement = Utils.elementFromString( - ` - - ` - ); - document.querySelector('#modals').appendChild(modalElement); - let modal = M.Modal.init( - modalElement, - { - dismissible: false, - onCloseEnd: () => { - modal.destroy(); - modalElement.remove(); - } - } - ); - let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); - confirmElement.addEventListener('click', (event) => { - let modelTitle = model.title; - fetch(`/contributions/edit-tesseract-model/${modelId}`, {method: 'DELETE'}) - .then( - (response) => { - app.flash(`Model "${modelTitle}" marked for deletion`, 'corpus'); - resolve(response); - }, - (response) => { - if (response.status === 403) {app.flash('Forbidden', 'error');} - if (response.status === 404) {app.flash('Not Found', 'error');} - reject(response); - } - ); - }); - modal.open(); - }); - } - - editModel(editButton) { - window.location.href = `/contributions/edit-tesseract-model/${editButton.dataset.modelId}`; - } -} diff --git a/app/static/js/RessourceLists/TesseractOCRPipelineModelList.js b/app/static/js/RessourceLists/TesseractOCRPipelineModelList.js new file mode 100644 index 00000000..36dea105 --- /dev/null +++ b/app/static/js/RessourceLists/TesseractOCRPipelineModelList.js @@ -0,0 +1,99 @@ +class TesseractOCRPipelineModelList extends RessourceList { + static autoInit() { + for (let tesseractOCRPipelineModelListElement of document.querySelectorAll('.tesseract-ocr-pipeline-model-list:not(.no-autoinit)')) { + new TesseractOCRPipelineModelList(tesseractOCRPipelineModelListElement); + } + } + + static options = { + initialHtmlGenerator: (id) => { + return ` +
    + search + + +
    + + + + + + + + + + +
    TitleDescriptionBiblio
    +
      + `.trim(); + }, + item: ` + + + + (), , + + delete + send + + + `.trim(), + ressourceMapper: (tesseractOCRPipelineModel) => { + return { + 'id': tesseractOCRPipelineModel.id, + 'creation-date': tesseractOCRPipelineModel.creation_date, + 'description': tesseractOCRPipelineModel.description, + 'publisher': tesseractOCRPipelineModel.publisher, + 'publisher-url': tesseractOCRPipelineModel.publisher_url, + 'publishing-url': tesseractOCRPipelineModel.publishing_url, + 'publishing-url-2': tesseractOCRPipelineModel.publishing_url, + 'publishing-year': tesseractOCRPipelineModel.publishing_year, + 'title': tesseractOCRPipelineModel.title, + 'title-2': tesseractOCRPipelineModel.title, + 'version': tesseractOCRPipelineModel.version + }; + }, + sortArgs: ['creation-date', {order: 'desc'}], + valueNames: [ + {data: ['id']}, + {data: ['creation-date']}, + {name: 'publisher-url', attr: 'href'}, + {name: 'publishing-url', attr: 'href'}, + 'description', + 'publisher', + 'publishing-url-2', + 'publishing-year', + 'title', + 'title-2', + 'version' + ] + }; + + constructor(listElement, options = {}) { + super(listElement, {...TesseractOCRPipelineModelList.options, ...options}); + } + + init (user) { + this._init(user.tesseract_ocr_pipeline_models); + } + + onClick(event) { + let actionButtonElement = event.target.closest('.action-button'); + let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; + let tesseractOCRPipelineModelElement = event.target.closest('tr'); + let tesseractOCRPipelineModelId = tesseractOCRPipelineModelElement.dataset.id; + switch (action) { + case 'delete-request': { + Utils.deleteTesseractOCRPipelineModelRequest(this.userId, tesseractOCRPipelineModelId); + break; + } + case 'view': { + window.location.href = `/contributions/tesseract-ocr-pipeline-models/${tesseractOCRPipelineModelId}`; + break; + } + default: { + break; + } + } + } +} diff --git a/app/static/js/Utils.js b/app/static/js/Utils.js index 2e7cbd4c..e6076e43 100644 --- a/app/static/js/Utils.js +++ b/app/static/js/Utils.js @@ -84,8 +84,8 @@ class Utils { `