diff --git a/kaplancloudapp/models.py b/kaplancloudapp/models.py index d5159e5..80aa881 100644 --- a/kaplancloudapp/models.py +++ b/kaplancloudapp/models.py @@ -456,7 +456,7 @@ def get_absolute_url(self): def save(self, *args, **kwargs): super().save(*args, **kwargs) if self.status == 1: - NewProjectReportThread(self).run() + NewProjectReportThread(self).start() class Segment(models.Model): diff --git a/kaplancloudapp/static/project.js b/kaplancloudapp/static/project.js index 1ad19ae..ca73b79 100644 --- a/kaplancloudapp/static/project.js +++ b/kaplancloudapp/static/project.js @@ -1,3 +1,10 @@ +const REPORT_STATUS_LABELS = { + 0: 'Blank', + 1: 'Ready for Processing', + 2: 'Processing', + 3: 'Complete', +}; + window.onload = function() { const assignLinguistForm = document.getElementById('assign-linguist-form').children[0]; const checkboxMain = document.getElementById('checkbox-main'); @@ -5,6 +12,14 @@ window.onload = function() { let filesList = []; + document.querySelectorAll('#reports-body tr').forEach(row => { + const status = parseInt(row.dataset.status, 10); + if (status < 3) { + const uuid = row.id.replace(/^report-/, ''); + checkReport(uuid); + } + }); + checkboxMain.onclick = function() { [...document.getElementsByClassName('checkbox')].forEach((item, i) => { item.checked = checkboxMain.checked; @@ -139,6 +154,7 @@ function analyzeFiles(fileUuids) ) .then(response => response.json()) .then(data => { + addReportRow(data['uuid']); checkReport(data['uuid']); }) .catch(error => { @@ -146,6 +162,39 @@ function analyzeFiles(fileUuids) }) } +function addReportRow(reportUuid) +{ + const tbody = document.getElementById('reports-body'); + const row = document.createElement('tr'); + row.id = 'report-' + reportUuid; + row.dataset.status = '1'; + row.className = 'hover:bg-base-200/30 transition-colors'; + const href = '/report/' + reportUuid; + row.innerHTML = ` + Just now + ${REPORT_STATUS_LABELS[1]} + + + + + + `; + tbody.prepend(row); +} + +function setReportStatus(reportUuid, status) +{ + const row = document.getElementById('report-' + reportUuid); + if (!row) return; + row.dataset.status = String(status); + const badge = row.querySelector('.report-status'); + if (badge && REPORT_STATUS_LABELS[status] !== undefined) { + badge.textContent = REPORT_STATUS_LABELS[status]; + } +} + function checkReport(reportUuid) { var url = new URL(window.location.origin + '/report/' + reportUuid); @@ -156,14 +205,11 @@ function checkReport(reportUuid) .then(response => response.json()) .then(data => { - if (data['status'] == 1 || data['status'] == 2) + setReportStatus(reportUuid, data['status']); + if (data['status'] < 3) { setTimeout(checkReport, 5000, reportUuid); } - else - { - document.getElementById('report-toast').classList.add('show') - } } ) } diff --git a/kaplancloudapp/templates/project.html b/kaplancloudapp/templates/project.html index ed20e5b..547aefe 100644 --- a/kaplancloudapp/templates/project.html +++ b/kaplancloudapp/templates/project.html @@ -6,8 +6,6 @@ .modal-overlay { display: none; position: fixed; inset: 0; z-index: 50; align-items: center; justify-content: center; background: rgb(0 0 0 / 0.5); } .modal-overlay.show { display: flex; } #context-menu { display: none; } - #report-toast { display: none; } - #report-toast.show { display: flex; } {% endblock %} @@ -121,17 +119,36 @@

Reference

{# ── Reports section ── #}

Reports

- {% if reports %} - - {% else %} -

No reports yet.

- {% endif %} +
+ + + + + + + + + + {% for report in reports %} + + + + + + {% endfor %} + +
CreatedStatus
+ {{ report.created_at }} + + {{ report.get_status_display }} + + + + +
+
@@ -199,13 +216,5 @@

Import Package

{% endif %} -{# ── Report toast ── #} -
- -

Your report is ready. Please refresh this page to see it listed.

-
- {% csrf_token %} {% endblock %} diff --git a/kaplancloudapp/templates/report.html b/kaplancloudapp/templates/report.html index db57ec3..afd2ab6 100644 --- a/kaplancloudapp/templates/report.html +++ b/kaplancloudapp/templates/report.html @@ -2,11 +2,13 @@ {% block title %}Report | {{ project.name }} | Kaplan Cloud{% endblock %} {% block navbar_center %} - + {% endblock %} {% block div %} diff --git a/kaplancloudapp/tests.py b/kaplancloudapp/tests.py index 4e6dc45..55ede07 100644 --- a/kaplancloudapp/tests.py +++ b/kaplancloudapp/tests.py @@ -442,14 +442,14 @@ def test_ordering_newest_first(self): @patch("kaplancloudapp.models.NewProjectReportThread") def test_save_with_status_1_triggers_thread(self, mock_thread): - mock_thread.return_value.run = MagicMock() + mock_thread.return_value.start = MagicMock() report = ProjectReport.objects.create( project=self.project, content={"s": "processing"} ) report.status = 1 report.save() mock_thread.assert_called_once() - mock_thread.return_value.run.assert_called_once() + mock_thread.return_value.start.assert_called_once() # =========================================================================== diff --git a/kaplancloudapp/thread_classes.py b/kaplancloudapp/thread_classes.py index 33fd841..0c1e554 100644 --- a/kaplancloudapp/thread_classes.py +++ b/kaplancloudapp/thread_classes.py @@ -5,6 +5,7 @@ import regex from django.apps import apps +from django.db import connection from kaplan import open_bilingualfile from kaplan.kdb import KDB from kaplan.kxliff import KXLIFF @@ -257,32 +258,20 @@ def __init__(self, projectreport_instance, **kwargs): super(NewProjectReportThread, self).__init__(**kwargs) def run(self): - instance = self.projectreport_instance - - for project_file in instance.project_files.all(): - if project_file.status == 1: - project_file.status = 2 - project_file.save() - - SegmentModel = apps.get_model("kaplancloudapp", "Segment") - - entries = [] - - project_report = {} - project_total = { - "Repetitions": 0, - "100": 0, # TODO - "95": 0, - "85": 0, - "75": 0, - "50": 0, - "New": 0, - "Total": 0, - } - - sm = difflib.SequenceMatcher() - for project_file in instance.project_files.all(): - file_report = { + try: + instance = self.projectreport_instance + + for project_file in instance.project_files.all(): + if project_file.status == 1: + project_file.status = 2 + project_file.save() + + SegmentModel = apps.get_model("kaplancloudapp", "Segment") + + entries = [] + + project_report = {} + project_total = { "Repetitions": 0, "100": 0, # TODO "95": 0, @@ -293,66 +282,83 @@ def run(self): "Total": 0, } - for segment in SegmentModel.objects.filter(file=project_file): - source_segment = etree.fromstring( - "" + segment.source + "" - ) - source_entry, _ = KDB.segment_to_entry(source_segment) - word_count = len(source_entry.split()) - char_count = len(source_entry) + sm = difflib.SequenceMatcher() + for project_file in instance.project_files.all(): + file_report = { + "Repetitions": 0, + "100": 0, # TODO + "95": 0, + "85": 0, + "75": 0, + "50": 0, + "New": 0, + "Total": 0, + } + + for segment in SegmentModel.objects.filter(file=project_file): + source_segment = etree.fromstring( + "" + segment.source + "" + ) + source_entry, _ = KDB.segment_to_entry(source_segment) + word_count = len(source_entry.split()) + char_count = len(source_entry) - if source_entry in entries: - file_report["Repetitions"] += word_count - # elif entry in project_tm_entries TODO - else: - sm.set_seq2(source_entry) - - highest_match = 0.0 - for entry in filter( - lambda x: len(x) >= char_count / 2 and len(x) <= char_count * 2, - entries, - ): - sm.set_seq1(entry) - highest_match = max(sm.ratio(), highest_match) - if highest_match >= 0.95: - break - - if highest_match >= 0.95: - file_report["95"] += word_count - elif highest_match >= 0.85: - file_report["85"] += word_count - elif highest_match >= 0.75: - file_report["75"] += word_count - elif highest_match >= 0.5: - file_report["50"] += word_count + if source_entry in entries: + file_report["Repetitions"] += word_count + # elif entry in project_tm_entries TODO else: - file_report["New"] += word_count + sm.set_seq2(source_entry) + + highest_match = 0.0 + for entry in filter( + lambda x: ( + len(x) >= char_count / 2 and len(x) <= char_count * 2 + ), + entries, + ): + sm.set_seq1(entry) + highest_match = max(sm.ratio(), highest_match) + if highest_match >= 0.95: + break - entries.append(source_entry) + if highest_match >= 0.95: + file_report["95"] += word_count + elif highest_match >= 0.85: + file_report["85"] += word_count + elif highest_match >= 0.75: + file_report["75"] += word_count + elif highest_match >= 0.5: + file_report["50"] += word_count + else: + file_report["New"] += word_count + + entries.append(source_entry) - file_report["Total"] += word_count + file_report["Total"] += word_count - project_total["Repetitions"] += file_report["Repetitions"] - project_total["100"] += file_report["100"] - project_total["95"] += file_report["95"] - project_total["85"] += file_report["85"] - project_total["75"] += file_report["75"] - project_total["50"] += file_report["50"] - project_total["New"] += file_report["New"] - project_total["Total"] += file_report["Total"] + project_total["Repetitions"] += file_report["Repetitions"] + project_total["100"] += file_report["100"] + project_total["95"] += file_report["95"] + project_total["85"] += file_report["85"] + project_total["75"] += file_report["75"] + project_total["50"] += file_report["50"] + project_total["New"] += file_report["New"] + project_total["Total"] += file_report["Total"] - project_report[project_file.name] = file_report + project_report[project_file.name] = file_report - project_report["Total"] = project_total + project_report["Total"] = project_total - instance.content = project_report - instance.status = 3 - instance.save() + instance.content = project_report + instance.status = 3 + instance.save() - for project_file in instance.project_files.all(): - if project_file.status == 2: - project_file.status = 3 - project_file.save() + for project_file in instance.project_files.all(): + if project_file.status == 2: + project_file.status = 3 + project_file.save() + finally: + connection.close() class TMImportThread(threading.Thread): diff --git a/kaplancloudapp/views.py b/kaplancloudapp/views.py index c2b7dbc..4e451f9 100644 --- a/kaplancloudapp/views.py +++ b/kaplancloudapp/views.py @@ -402,7 +402,7 @@ def project(request, uuid): "form": form, "form1": form1, "project": project, - "reports": ProjectReport.objects.filter(project=project).filter(status=3), + "reports": ProjectReport.objects.filter(project=project), }, )