From a2a0aabb62c8cf402160bc5c3e6fcedc39b80314 Mon Sep 17 00:00:00 2001 From: Oleksii Kriuchykhin Date: Wed, 14 Apr 2021 14:40:13 +0200 Subject: [PATCH] Implement pooling for Report document creation status [SCI-5557] --- app/assets/.eslintrc.json | 3 +- ..._datatable.js.erb => reports_datatable.js} | 85 +++++++++++++------ app/controllers/reports_controller.rb | 25 +++++- app/datatables/report_datatable.rb | 3 +- config/routes.rb | 1 + 5 files changed, 86 insertions(+), 31 deletions(-) rename app/assets/javascripts/reports/{reports_datatable.js.erb => reports_datatable.js} (72%) diff --git a/app/assets/.eslintrc.json b/app/assets/.eslintrc.json index 83dd8d18e..c1a6e5cea 100644 --- a/app/assets/.eslintrc.json +++ b/app/assets/.eslintrc.json @@ -27,6 +27,7 @@ { "beforeLineComment": false } - ] + ], + "max-len": ["error", { "code": 120 }] } } diff --git a/app/assets/javascripts/reports/reports_datatable.js.erb b/app/assets/javascripts/reports/reports_datatable.js similarity index 72% rename from app/assets/javascripts/reports/reports_datatable.js.erb rename to app/assets/javascripts/reports/reports_datatable.js index e804a9a0a..0f11cf5a8 100644 --- a/app/assets/javascripts/reports/reports_datatable.js.erb +++ b/app/assets/javascripts/reports/reports_datatable.js @@ -1,9 +1,10 @@ -/* global I18n DataTableHelpers */ +/* global I18n DataTableHelpers animateSpinner */ -(function(global) { +(function() { 'use strict'; - var DATATABLE; + const RETRY_COUNT = 25; + const START_POLLING_INTERVAL = 10000; var CHECKED_REPORTS = []; function tableDrowCallback() { @@ -14,13 +15,13 @@ function appendSearchResults(data) { var items = []; - if(data.hasOwnProperty('projects')){ + if (data.hasOwnProperty('projects')) { $.each(data.projects, function(index, el) { items.push( { - 'value': el.path, - 'text': el.name, - 'disabled': false + value: el.path, + text: el.name, + disabled: false } ) }); @@ -30,7 +31,7 @@ function initToggleAllCheckboxes() { $('input[name="select_all"]').change(function() { - if($(this).is(':checked')) { + if ($(this).is(':checked')) { $("[data-action='toggle']").prop('checked', true); $('.report-row').addClass('selected'); addAllItems(); @@ -45,7 +46,7 @@ function addAllItems() { $.each($("[data-action='toggle']"), function(i, el) { - CHECKED_REPORTS.push($(el).attr('data-report-id')); + CHECKED_REPORTS.push($(el).data('report-id')); }) } @@ -108,23 +109,28 @@ return ''; } - function appendEditPathToRow(row, data) { + function addAttributesToRow(row, data) { $(row).addClass('report-row') - .attr('data-edit-path', data['edit']) - .attr('data-id', data['0']); + .attr('data-edit-path', data.edit) + .attr('data-status-path', data.status) + .attr('data-retry-count', 0) + .attr('data-id', data['0']); + if (data['3'].processing || data['4'].processing) { + $(row).addClass('processing'); + } } function checkboxToggleCallback() { $("[data-action='toggle']").change(function() { - var id = $(this).attr('data-report-id'); - if($(this).is(':checked')) { + var id = $(this).data('report-id'); + if ($(this).is(':checked')) { $(this).closest('.report-row').addClass('selected'); CHECKED_REPORTS.push(id); } else { - var index = CHECKED_REPORTS.indexOf(id); + let index = CHECKED_REPORTS.indexOf(id); $(this).closest('.report-row').removeClass('selected'); - if(index != -1) { - CHECKED_REPORTS.splice(index, 1); + if (index !== -1) { + CHECKED_REPORTS.splice(index, 1); } } updateButtons(); @@ -167,11 +173,31 @@ } } + function checkProcessingStatus(reportId) { + let $row = $('#reports-table').find(`tr[data-id="${reportId}"]`); + + if ($row.length === 0) return; + + $.getJSON($row.data('status-path'), (statusData) => { + $row.find('.docx').parent().html(renderDocxFile(statusData.docx)); + $row.find('.pdf').parent().html(renderPdfFile(statusData.pdf)); + + if (statusData.docx.processing || statusData.pdf.processing) { + if ($row.data('retry-count') >= RETRY_COUNT) return; + + $row.data('retry-count', $row.data('retry-count') + 1); + setTimeout(() => { checkProcessingStatus(reportId); }, START_POLLING_INTERVAL * $row.data('retry-count')); + } else { + $row.removeClass('processing'); + } + }); + } + // INIT function initDatatable() { - var $table = $('#reports-table') - DATATABLE = $table.dataTable({ + var $table = $('#reports-table'); + $table.dataTable({ dom: "Rt<'pagination-row hidden'<'pagination-info'li><'pagination-actions'p>>", order: [[2, 'desc']], sScrollX: '100%', @@ -207,10 +233,13 @@ sSearch: I18n.t('general.filter') }, fnDrawCallback: tableDrowCallback, - createdRow: appendEditPathToRow, + createdRow: addAttributesToRow, fnInitComplete: function() { DataTableHelpers.initLengthApearance($table.closest('.dataTables_wrapper')); $('.pagination-row').removeClass('hidden'); + $('.report-row.processing').each(function() { + setTimeout(() => { checkProcessingStatus($(this).data('id')); }, START_POLLING_INTERVAL); + }); } }); } @@ -220,23 +249,23 @@ e.preventDefault(); animateSpinner(); if (CHECKED_REPORTS.length === 1) { - var id = CHECKED_REPORTS[0]; - var row = $(".report-row[data-id='" + id + "']"); - var url = row.attr('data-edit-path'); + let id = CHECKED_REPORTS[0]; + let row = $(".report-row[data-id='" + id + "']"); + let url = row.attr('data-edit-path'); $(location).attr('href', url); } }); } function initDeleteReports() { - $('#delete-reports-btn').click(function(e) { + $('#delete-reports-btn').click(function() { if (CHECKED_REPORTS.length > 0) { - $('#report-ids').attr("value", "[" + CHECKED_REPORTS + "]"); - $('#delete-reports-modal').modal("show"); + $('#report-ids').attr('value', '[' + CHECKED_REPORTS + ']'); + $('#delete-reports-modal').modal('show'); } }); - $("#confirm-delete-reports-btn").click(function(e) { + $('#confirm-delete-reports-btn').click(function() { animateLoading(); }); } @@ -244,4 +273,4 @@ initDatatable(); initEditReport(); initDeleteReports(); -})(window); +}()); diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 6f578ddc9..5aca5606e 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -22,7 +22,7 @@ class ReportsController < ApplicationController result_contents ).freeze - before_action :load_vars, only: %i(edit update document_preview generate) + before_action :load_vars, only: %i(edit update document_preview generate status) before_action :load_vars_nested, only: BEFORE_ACTION_METHODS before_action :load_visible_projects, only: %i(new edit) before_action :load_available_repositories, @@ -166,6 +166,28 @@ class ReportsController < ApplicationController redirect_to reports_path end + def status + docx = @report.docx_file.attached? ? document_preview_report_path(@report, report_type: :docx) : nil + pdf = @report.pdf_file.attached? ? document_preview_report_path(@report, report_type: :pdf) : nil + + respond_to do |format| + format.json do + render json: { + docx: { + processing: @report.docx_file_processing, + preview_url: docx, + error: false + }, + pdf: { + processing: @report.pdf_file_processing, + preview_url: pdf, + error: false + } + } + end + end + end + # Generation action def generate respond_to do |format| @@ -458,6 +480,7 @@ class ReportsController < ApplicationController def load_vars @report = current_team.reports.find_by(id: params[:id]) render_404 unless @report + render_403 unless can_read_project?(@report.project) end def load_vars_nested diff --git a/app/datatables/report_datatable.rb b/app/datatables/report_datatable.rb index 298872520..1316658db 100644 --- a/app/datatables/report_datatable.rb +++ b/app/datatables/report_datatable.rb @@ -60,7 +60,8 @@ class ReportDatatable < CustomDatatable '6' => sanitize_input(record.modified_by), '7' => I18n.l(record.created_at, format: :full), '8' => I18n.l(record.updated_at, format: :full), - 'edit' => edit_project_report_path(record.project_id, record.id) + 'edit' => edit_project_report_path(record.project_id, record.id), + 'status' => status_project_report_path(record.project_id, record.id) } end end diff --git a/config/routes.rb b/config/routes.rb index 7b51f8aa5..b6f90a1ed 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -251,6 +251,7 @@ Rails.application.routes.draw do only: %i(edit update create) do member do post 'generate', to: 'reports#generate', format: %w(pdf json) + get 'status', to: 'reports#status', format: %w(json) end collection do