diff --git a/app/controllers/problems_controller.rb b/app/controllers/problems_controller.rb --- a/app/controllers/problems_controller.rb +++ b/app/controllers/problems_controller.rb @@ -148,6 +148,9 @@ @summary = { attempt: user.count, solve: 0 } user.each_value { |v| @summary[:solve] += 1 if v == 1 } + + #for new graph + @chart_dataset = @problem.get_jschart_history.to_json.html_safe end def manage diff --git a/app/controllers/report_controller.rb b/app/controllers/report_controller.rb --- a/app/controllers/report_controller.rb +++ b/app/controllers/report_controller.rb @@ -248,7 +248,7 @@ #@histogram = { data: Array.new(range,0), summary: {} } @summary = {count: 0, solve: 0, attempt: 0} user = Hash.new(0) - Submission.where(problem_id: @problem.id).find_each do |sub| + Submission.where(problem_id: @problem.id).includes(:language).each do |sub| #histogram d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 #@histogram[:data][d.to_i] += 1 if d < range @@ -257,7 +257,8 @@ @summary[:count] += 1 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max - lang = Language.find_by_id(sub.language_id) + #lang = Language.find_by_id(sub.language_id) + lang = sub.language next unless lang next unless sub.points >= @problem.full_score diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -130,27 +130,21 @@ def stat @user = User.find(params[:id]) - @submission = Submission.joins(:problem).where(user_id: params[:id]) + @submission = Submission.joins(:problem).includes(:problem).includes(:language).where(user_id: params[:id]) @submission = @submission.where('problems.available = true') unless current_user.admin? - range = 120 - @histogram = { data: Array.new(range,0), summary: {} } @summary = {count: 0, solve: 0, attempt: 0} problem = Hash.new(0) @submission.find_each do |sub| - #histogram - d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 - @histogram[:data][d.to_i] += 1 if d < range - @summary[:count] += 1 next unless sub.problem problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max end - @histogram[:summary][:max] = [@histogram[:data].max,1].max @summary[:attempt] = problem.count problem.each_value { |v| @summary[:solve] += 1 if v == 1 } + @chart_dataset = @user.get_jschart_user_sub_history.to_json.html_safe end def toggle_activate diff --git a/app/models/user.rb b/app/models/user.rb --- a/app/models/user.rb +++ b/app/models/user.rb @@ -314,6 +314,21 @@ User.update_all(:last_ip => nil) end + def get_jschart_user_sub_history + start = 4.month.ago.beginning_of_day + start_date = start.to_date + count = Submission.where(user: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count + i = 0 + label = [] + value = [] + while (start_date + i < Time.zone.now.to_date) + label << (start_date+i).strftime("%d-%b") + value << (count[start_date+i] || 0) + i+=1 + end + return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']} + end + #create multiple user, one per lines of input def self.create_from_list(lines) error_logins = [] diff --git a/app/views/application/_bar_graph.html.haml b/app/views/application/_bar_graph.html.haml deleted file mode 100644 --- a/app/views/application/_bar_graph.html.haml +++ /dev/null @@ -1,44 +0,0 @@ -- param = {} unless param -- graph_height = param[:graph_height] || 100 -- bar_width = param[:bar_width] || 14 -- graph_width = (bar_width * histogram[:data].count) + 20 -:css - .hist_bar { - width: #{bar_width-1}px; - position: absolute; - background-color: lightblue; - } - .hist_fill { - width: #{bar_width-1}px; - position: absolute; - background-color: #eee; - } - .hist_text { - position: absolute; - font-size:5px; - } - -%div{style: "position: relative; width: #{graph_width}px; height: 125px; background-color:#fff;" } - //draw background - - histogram[:data].each_index do |i| - - height = histogram[:data][i] * graph_height / histogram[:summary][:max] - - top = graph_height - height - - left = graph_width - (i+1)*bar_width - %div.hist_fill{style: "top: 0px; height: #{graph_height - height}px; left: #{left}px;" } - // draw horizontal line - - line = 3 - - line.times do |i| - - top = graph_height - graph_height * (i+0.5)/ line - %div{style: "position:absolute;width: #{graph_width-21}px;height: 1px;left: 20px;top:#{top}px;background-color: #333;"} - %div.hist_text{style: "position:absolute;left: 0px;top:#{top-6}px"} - =((i+0.5) * histogram[:summary][:max] / line).to_i - // draw the actual bar and text - - @histogram[:data].each_index do |i| - - height = histogram[:data][i] * graph_height / histogram[:summary][:max] - - top = graph_height - height - - left = graph_width - (i+1)*bar_width - %div.hist_bar{style: "top: #{top}px; height: #{height}px; left: #{left}px; dae: #{histogram[:data][i]}" } - - if i % 7 == 1 - %div.hist_text{style: "top:#{graph_height + 5}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%-d')} - - if (Time.now.in_time_zone - i.day).day == 15 - %div.hist_text{style: "top:#{graph_height + 15}px;left: #{left}px;"} #{(Time.zone.today - i.day).strftime('%b')} diff --git a/app/views/application/_submission_short.html.haml b/app/views/application/_submission_short.html.haml --- a/app/views/application/_submission_short.html.haml +++ b/app/views/application/_submission_short.html.haml @@ -3,21 +3,21 @@ - else - if local_assigns[:show_id] .row - .col-3.text-secondary - Sub ID: - %strong.col-9= submission.id + .col-3.fw-bold + Sub ID + .col-9.text-secondary-x= submission.id - unless submission.graded_at .row - .col-3.text-secondary= t 'main.submitted_at' - %strong.col-9= format_full_time_ago(submission.submitted_at.localtime) + .col-3.fw-bold= t 'main.submitted_at' + .col-9.text-secondary-x= format_full_time_ago(submission.submitted_at.localtime) - else .row - .col-3.text-secondary= t 'main.graded_at' - %strong.col-9= format_full_time_ago(submission.graded_at.localtime) + .col-3.fw-bold= t 'main.graded_at' + .col-9.text-secondary-x= format_full_time_ago(submission.graded_at.localtime) - if GraderConfiguration['ui.show_score'] .row - .col-3.text-secondary=t 'main.score' - %strong.col-9 + .col-3.fw-bold=t 'main.score' + .col-9.text-secondary-x = (submission.points*100/submission.problem.full_score).to_i %tt.grader-comment = " [#{submission.grader_comment}]" diff --git a/app/views/problems/manage.html.haml b/app/views/problems/manage.html.haml --- a/app/views/problems/manage.html.haml +++ b/app/views/problems/manage.html.haml @@ -2,51 +2,29 @@ = stylesheet_link_tag 'problems' = javascript_include_tag 'local_jquery' -:javascript - $(document).ready( function() { - function shiftclick(start,stop,value) { - $('tr input').each( function(id,input) { - var $input=$(input); - var iid=parseInt($input.attr('id').split('-')[2]); - if(iid>=start&&iid<=stop){ - $input.prop('checked',value) - } - }); - } - - $('tr input').click( function(e) { - if (e.shiftKey) { - stop = parseInt($(this).attr('id').split('-')[2]); - var orig_stop = stop - if (typeof start !== 'undefined') { - if (start > stop) { - var tmp = start; - start = stop; - stop = tmp; - } - shiftclick(start,stop,$(this).is(':checked') ) - } - start = orig_stop - } else { - start = parseInt($(this).attr('id').split('-')[2]); - } - }); - }); %h1 Manage problems %p= link_to '[Back to problem list]', problems_path -= form_tag :action=>'do_manage' do - .panel.panel-primary - .panel-heading += form_with url: do_manage_problems_path do |f| + .card.border-primary.mb-2 + .card-header.text-bg-primary.border-primary Action - .panel-body + .card-body .submit-box What do you want to do to the selected problem? %br/ (You can shift-click to select a range of problems) + .row + .col-md-auto + = f.check_box :change_date_added, class: 'form-check-input' + .col-md-auto + .form-check-label + Change "Date added" to + .col-md-auto + %ul.form-inline %li Change "Date added" to @@ -107,13 +85,45 @@ = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])" :javascript - $('.input-group.date').datetimepicker({ - format: 'DD/MMM/YYYY', - showTodayButton: true, - locale: 'en', - widgetPositioning: {horizontal: 'auto', vertical: 'bottom'}, + + $(document).on('import-map-loaded', function() { + function shiftclick(start,stop,value) { + $('tr input').each( function(id,input) { + var $input=$(input); + var iid=parseInt($input.attr('id').split('-')[2]); + if(iid>=start&&iid<=stop){ + $input.prop('checked',value) + } + }); + } + $('tr input').click( function(e) { + if (e.shiftKey) { + stop = parseInt($(this).attr('id').split('-')[2]); + var orig_stop = stop + if (typeof start !== 'undefined') { + if (start > stop) { + var tmp = start; + start = stop; + stop = tmp; + } + shiftclick(start,stop,$(this).is(':checked') ) + } + start = orig_stop + } else { + start = parseInt($(this).attr('id').split('-')[2]); + } + }); + + $('.input-group.date').datetimepicker({ + format: 'DD/MMM/YYYY', + showTodayButton: true, + locale: 'en', + widgetPositioning: {horizontal: 'auto', vertical: 'bottom'}, + + }); + + $('.datatable').DataTable({ + paging: false + }); }); - $('.datatable').DataTable({ - paging: false - }); diff --git a/app/views/problems/stat.html.haml b/app/views/problems/stat.html.haml --- a/app/views/problems/stat.html.haml +++ b/app/views/problems/stat.html.haml @@ -4,28 +4,34 @@ } %h1 Problem stat: #{@problem.name} -%h2 Overview + +.row.mb-3 + .col-md-8 + .card + .card-body + %h2.card-title Submission History + %canvas#chart{height: '50px'} -.row - .col-md-2 - %strong Name: - .col-md-10 - = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 - = link_to_description_if_any "[#{t 'main.problem_desc'}] ".html_safe, @problem -.row - .col-md-2.strong - %strong Submissions: - .col-md-10 - = @submissions.count -.row - .col-md-2.strong - %strong Solved/Attemped User - .col-md-10 - #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) - - -%h2 Submissions Count -= render partial: 'application/bar_graph', locals: { histogram: @histogram } + .col-md-4 + .card + .card-body + %h2.card-title General Info + .row + .col-sm-6 + Name + .col-sm-6 + = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 + = link_to_description_if_any "[#{t 'main.problem_desc'}] ".html_safe, @problem + .row + .col-sm-6 + Subs + .col-sm-6 + = @submissions.count + .row + .col-sm-6 + Solved/Attempted User + .col-sm-6 + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) %h2 Submissions - if @submissions and @submissions.count > 0 @@ -58,6 +64,27 @@ No submission :javascript - $("#main_table").DataTable({ - paging: false + $(document).on('import-map-loaded',(e) => { + //init datatable + $("#main_table").DataTable({ + paging: false + }); + + //history graph + data = #{@chart_dataset} + config = { + type: 'bar', + data: data, + options: { + plugins: { + legend: { + display: false + }, + }, + } + } + Chart.defaults.font.size = 15 + //Chart.defaults.font.family = 'Sarabun Light' + chart = new Chart($('#chart'),config) }); + diff --git a/app/views/users/stat.html.haml b/app/views/users/stat.html.haml --- a/app/views/users/stat.html.haml +++ b/app/views/users/stat.html.haml @@ -1,42 +1,46 @@ -- content_for :header do - = javascript_include_tag 'local_jquery' - -:javascript - $(function () { - $('#submission_table').tablesorter({widgets: ['zebra']}); - }); :css .fix-width { font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier; } -%h1= @user.full_name +%h1 User stats +%h5.text-secondary= @user.login + +.row.my-3 + .col-md-8 + .card + .card-body + %h2.card-title Sub Info + %canvas#chart{height: '50px'} -Login: #{@user.login}
-Full name: #{@user.full_name}
+ .col-md-4 + .card + .card-body + %h2.card-title General Info + .row + .col-sm-6.fw-bold + Login + .col-sm-6 + = @user.login + .row + .col-sm-6.fw-bold + Full name + .col-sm-6 + = @user.full_name + .row + .col-sm-6.fw-bold + Subs + .col-sm-6 + = @summary[:count] + .row + .col-sm-6.fw-bold + Solved/Attempted Problem + .col-sm-6 + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) -%h2 Problem Stat -%table.info - %thead - %tr.info-head - %th Stat - %th Value - %tbody - %tr{class: cycle('info-even','info-odd')} - %td.info_param Submissions - %td= @summary[:count] - %tr{class: cycle('info-even','info-odd')} - %td.info_param Solved/Attempted Problem - %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) - -%h2 Submission History - -=render partial: 'application/bar_graph', locals: {histogram: @histogram, param: {bar_width: 7}} - - -%table#submission_table.table.table-striped +%table#main_table.table.table-striped %thead %tr %th ID @@ -65,6 +69,27 @@ :javascript - $("#submission_table").DataTable({ - paging: false + $(document).on('import-map-loaded',(e) => { + //init datatable + $("#main_table").DataTable({ + paging: false + }); + + //history graph + data = #{@chart_dataset} + config = { + type: 'bar', + data: data, + options: { + plugins: { + legend: { + display: false + }, + }, + } + } + Chart.defaults.font.size = 15 + //Chart.defaults.font.family = 'Sarabun Light' + chart = new Chart($('#chart'),config) }); +