diff --git a/Untitled b/Untitled new file mode 100644 index 0000000..9a5985b --- /dev/null +++ b/Untitled @@ -0,0 +1 @@ +options: {scales: {xAxes: [{display: false} ] } } diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 38f1176..72f08ba 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,6 +14,9 @@ //= require jquery_ujs //= require jquery.slick //= require noty/lib/noty +//= require bulma-slider/slider +//= require Chart.bundle +//= require chartkick //= require turbolinks //= require_tree . $( function() { diff --git a/app/assets/javascripts/lessons.coffee b/app/assets/javascripts/lessons.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/lessons.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/lessons.js b/app/assets/javascripts/lessons.js new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/javascripts/main.coffee b/app/assets/javascripts/main.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/app/assets/javascripts/main.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js new file mode 100644 index 0000000..5ea76f4 --- /dev/null +++ b/app/assets/javascripts/main.js @@ -0,0 +1 @@ +//= require jquery.easy-pie-chart diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index e80dd03..8eae633 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -12,6 +12,7 @@ @import "font-awesome-sprockets"; @import "font-awesome"; @import 'slick'; +@import 'bulma-slider/slider'; //Mixins @mixin vertical-alignment($position: relative) { diff --git a/app/assets/stylesheets/lessons.scss b/app/assets/stylesheets/lessons.scss index 2b05ed0..904b13c 100644 --- a/app/assets/stylesheets/lessons.scss +++ b/app/assets/stylesheets/lessons.scss @@ -2,6 +2,9 @@ // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ //Mixins +@import 'bulma'; +@import 'bulma-tooltip/tooltip'; +@import 'jquery.easy-pie-chart'; @mixin vertical-alignment($position: relative) { position: $position; top: 50%; @@ -14,3 +17,69 @@ list-style: none !important; padding-left: 0 !important; } +.grader{ + min-height: 600px; + h5.subtitle{ + font-size: 1rem; + } +} + +#grades_submit{ + margin-right: -20px; + position: fixed; + bottom: 30px; + right: 30px; + cursor: pointer; + z-index: 999; + box-shadow: 0px 2px 5px #666; +} +nav.level.stats{ + margin: 10px; +} + +hr.major { + height: 10px; + border-style: solid; + border-color: $light; + border-width: 1px 0 0 0; + border-radius: 20px; + background-color: darken($light, 10%); +} +hr.major:before { + display: block; + content: ""; + height: 30px; + margin-top: -31px; + border-style: solid; + border-color: $light; + border-width: 0 0 1px 0; + border-radius: 20px; +} + +#status-table{ + border-radius: 10px; + text-align: center; +} + +strong.bright{ + background-color: $light; + border-radius: 10px; + border: 2px solid $grey; + padding: 5px 10px 5px 10px; +} +.box-container{ + display: flex !important; + align-items: center; + .box{ + h3{ + font-size: 20px; + font-weight: 800; + letter-spacing: 2px; + padding: 10px 0 10px 0; + } + width: 90%; + height: 90%; + align-self: center; + margin: auto; + } +} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 605d5bb..61bdcaf 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -46,3 +46,9 @@ margin-bottom: 10px; } } + +.columns.has-equal-heights{ + &:last-child{ + margin-right: 20px; + } +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c07694..910ddfd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,13 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception + layout :layout_by_resource + + # choose different layout for devise + def layout_by_resource + if devise_controller? + 'devise' + else + 'application' + end + end end diff --git a/app/controllers/lessons_controller.rb b/app/controllers/lessons_controller.rb index 892dc80..c4468e9 100644 --- a/app/controllers/lessons_controller.rb +++ b/app/controllers/lessons_controller.rb @@ -1,30 +1,31 @@ class LessonsController < ApplicationController - def index; end - - def new - @lessons = Lesson.all + before_action :authenticate_user! + def index + @list = current_user.lessons.where(selected: true).group_by(&:semester) end - def semesters - @semesters = Lesson.where(selected: true).group_by(&:semester) - end + def grades; end def show_semester - @semesters = Lesson.where(selected: true).group_by(&:semester) - @semester = @semesters[params[:id].to_i] + @semesters = current_user.lessons.where(selected: true) + .group_by(&:semester)[params[:id].to_i] end - def stats; end + def status; end + + def stats + @lessons = current_user.lessons.where(selected: true) + end def add - @basics = Lesson.where(ltype: 2) - @generals = Lesson.where(ltype: 3) - @specials = Lesson.where(ltype: 4) - @thesis = Lesson.where(ltype: 5) + @basics = current_user.lessons.where(ltype: 2) + @generals = current_user.lessons.where(ltype: 3) + @specials = current_user.lessons.where(ltype: 4) + @thesis = current_user.lessons.where(ltype: 5) end def submit_grades - Lesson.all.each do |les| + current_user.lessons.all.each do |les| @grade = params[les.name] les.update_attribute(:grade, @grade) end @@ -32,20 +33,20 @@ def submit_grades end def select - @les = Lesson.find(params[:lesson]) + @les = current_user.lessons.find(params[:lesson]) @les.update_attribute(:selected, true) unless @les.selected redirect_to action: 'add' end def delete - @basics = Lesson.where(ltype: 2, selected: true) - @generals = Lesson.where(ltype: 3, selected: true) - @specials = Lesson.where(ltype: 4, selected: true) - @thesis = Lesson.where(ltype: 5, selected: true) + @basics = current_user.lessons.where(ltype: 2, selected: true) + @generals = current_user.lessons.where(ltype: 3, selected: true) + @specials = current_user.lessons.where(ltype: 4, selected: true) + @thesis = current_user.lessons.where(ltype: 5, selected: true) end def remove - @les = Lesson.find(params[:lesson]) + @les = current_user.lessons.find(params[:lesson]) @les.update_attribute(:selected, false) if @les.selected redirect_to action: 'new' end diff --git a/app/helpers/lessons_helper.rb b/app/helpers/lessons_helper.rb index 5146138..a816136 100644 --- a/app/helpers/lessons_helper.rb +++ b/app/helpers/lessons_helper.rb @@ -1,6 +1,6 @@ module LessonsHelper def avg_calc - @lessons = Lesson.where(grade: [5..10], selected: true) + @lessons = current_user.lessons.where(grade: [5..10], selected: true) @sum = 0 @lessons.each do |les| @sum += les.ects * les.grade.to_f @@ -8,31 +8,101 @@ def avg_calc @avg = @sum / @lessons.sum(:ects) unless @lessons.sum(:ects).zero? end + def avg_color + case avg_calc + when 5..6 + 'has-text-info' + when 6.01..7 + 'has-text-primary' + when 7.01..8 + 'has-text-warning' + when 8.01..10 + 'has-text-success' + end + end + def sem_avg(i) - Lesson.where(semester: i, grade: [5..10]).average(:grade).to_s.first(4) + current_user.lessons.where(semester: i, grade: [5..10]).average(:grade) + end + + def avg_winter_semesters + @sum = 0 + for i in 1..8 + @sum += sem_avg(i) if i.odd? + end + @sum / 4.0 + end + + def avg_summer_semesters + @sum = 0 + for i in 1..8 + @sum += sem_avg(i) if i.even? + end + @sum / 4.0 + end + + def category_avg + @cats = current_user.lessons.map { |l| l.code.first(3) }.uniq + @averages = {} + @samps = [] + @cats.each do |cat| + current_user.lessons.where(selected: true, grade: [5..10]).each { |les| @samps << les if les.code.first(3) == cat } + @averages[cat] = arr_avg(@samps) + end + @averages + end + + def arr_avg(arr) + @sum = 0 + arr.each { |les| @sum += les.grade } + @sum.to_f / arr.count + end + + def avg_std + current_user.lessons.where(ltype: 1, grade: [5..10]).average(:grade) + end + + def avg_basic + current_user.lessons.where(ltype: 2, grade: [5..10]).average(:grade) + end + + def avg_gen + current_user.lessons.where(ltype: 3, grade: [5..10]).average(:grade) + end + + def avg_sp + current_user.lessons.where(ltype: 4, grade: [5..10]).average(:grade) end # Obligatory Classes def oblig_count - Lesson.where(grade: [5..10], ltype: 1).count + current_user.lessons.where(grade: [5..10], ltype: 1).count end # Basic Selection Classes def basic_ch_count - Lesson.where(grade: [5..10], ltype: 2).count + current_user.lessons.where(grade: [5..10], ltype: 2).count end # General Selection Classes def gen_ch_count - Lesson.where(grade: [5..10], ltype: 3).count + current_user.lessons.where(grade: [5..10], ltype: 3).count end # Special Selection Classes def spe_ch_count - Lesson.where(grade: [5..10], ltype: 4).count + current_user.lessons.where(grade: [5..10], ltype: 4).count end def th_count - Lesson.where(grade: [5..10], ltype: 5).count + current_user.lessons.where(grade: [5..10], ltype: 5).count + end + + def passed + current_user.lessons.where(grade: [5..10], selected: true) + end + + def icon_generator(cat) + cat ? 'check-square-o has-text-success' : 'times has-text-warning' end end diff --git a/app/models/lesson.rb b/app/models/lesson.rb index 66d296f..d462665 100644 --- a/app/models/lesson.rb +++ b/app/models/lesson.rb @@ -10,23 +10,11 @@ def default_values end end - def self.thesis? - Lesson.where(type: 5, grade: [5..10], selected: true).count == 1 - end - - def basics? - Lesson.where(type: 2, grade: [5..10]).count > 3 - end - - def generals? - Lesson.where(type: 2, grade: [5..10]).count > 1 - end - - def specials? - Lesson.where(type: 3, grade: [5..10]).count > 1 - end - - def self.no_thesis? - Lesson.where(type: [2..3], grade: [5..10]).count > 5 unless thesis? + def passed? + if grade > 4 + true + else + false + end end end diff --git a/app/models/subject.rb b/app/models/subject.rb new file mode 100644 index 0000000..8857c6e --- /dev/null +++ b/app/models/subject.rb @@ -0,0 +1,2 @@ +class Subject < ApplicationRecord +end diff --git a/app/models/user.rb b/app/models/user.rb index cb36c73..888a0cd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,24 +2,104 @@ class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable - has_many :lessons - - before_create do - create_user_lessons - select_obligatory - end + has_many :lessons, dependent: :destroy + after_create :create_user_lessons def create_user_lessons - Lesson.all.each do |les| - @lesson = lessons.new - @lesson = les - @lesson.save! + Subject.all.each do |les| + lessons.create!(les.attributes) end end - def select_obligatory - lessons.where(ltype: 1).each do |les| - les.update_attribute(:selected, true) - end + def s_avg + lessons.where(selected: true, grade: [5..10]).average(:grade) + end + + def lessons_total + lessons.where(selected: true).count + end + + def standards + lessons.where(selected: true, ltype: 1, grade: [5..10]).count + end + + def standards? + lessons.where(selected: true, ltype: 1, grade: [5..10]).count == 31 + end + + def basics + lessons.where(ltype: 2, selected: true).count + end + + def basics? + lessons.where(ltype: 2, selected: true).count > 3 + end + + def basics_passed? + lessons.where(ltype: 2, selected: true, grade: [5..10]).count > 3 + end + + def generals + lessons.where(ltype: 3, selected: true).count + end + + def generals? + lessons.where(ltype: 3, selected: true).count > 2 + end + + def generals_passed? + lessons.where(ltype: 3, selected: true, grade: [5..10]).count > 2 + end + + def specials + lessons.where(ltype: 4, selected: true).count + end + + def specials? + lessons.where(ltype: 4, selected: true).count > 2 + end + + def specials_passed? + lessons.where(ltype: 4, selected: true, grade: [5..10]).count > 2 + end + + def thesis? + !lessons.where(ltype: 5, selected: true).nil? + end + + def thesis_passed? + !lessons.where(ltype: 5, selected: true, grade: [5..10]).nil? + end + + def ects? + lessons.where(selected: true).sum(:ects) > 239 + end + + def ects + lessons.where(selected: true, grade: [5..10]).sum(:ects) + end + + def selections? + lessons.where(ltype: [2..5], selected: true).count > 10 + end + + def selections_ects? + lessons.where(ltype: [2..5], selected: true).sum(:ects) > 51 + end + + def all_passed? + lessons.where(selected: true, grade: [5..10]).count > 41 + end + + def eligible? + basics? && generals? && specials? && ects? && selections? && selections_ects? + end + + def graduated? + eligible? && all_passed? + end + + def passed + lessons.where(selected: true, grade: [5..10]).count end end diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 6444d1f..e825f4e 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -29,9 +29,9 @@ %a.navbar-item{href: about_path} About %a.navbar-item{href: 'https://twitter.com/wise_inno'} - %i.fa.fa-github - %a.navbar-item{href: 'https://github.com/dstrants'} %i.fa.fa-twitter + %a.navbar-item{href: 'https://github.com/dstrants'} + %i.fa.fa-github - if user_signed_in? %span.navbar-item %a.button.is-primary.is-inverted{href: destroy_user_session_path} @@ -56,9 +56,13 @@ %li %a{href: lessons_path} Overview %li - %a{href: lessons_semesters_path} Semesters + %a{href: "#{lessons_semesters_path}/1"} Semesters + %li + %a{href: lessons_status_path} Status + %li + %a{href: lessons_stats_path} Statistics %li - %a{href: lessons_stats_path} Stats + %a{href: lessons_grades_path} Grades %li %a{href: lessons_add_path} Add %li @@ -78,6 +82,10 @@ %br Picks by %a freepick - -if notice - %script - new Noty({type: 'success', layout: 'topRight',text: '#{notice}'}).show(); + -if flash + - flash.each do |key, val| + %script + - if key == 'info' || key == 'notice' + new Noty({type: 'information', layout: 'topRight', text: '#{val}'}).show(); + - else + new Noty({type: '#{key}', layout: 'topRight', text: '#{val}'}).show(); diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index bb53372..8f5f1d0 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -8,3 +8,10 @@ = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %body =yield + -if flash + - flash.each do |key, val| + %script + - if key == 'info' || key == 'notice' + new Noty({type: 'information', layout: 'topRight', text: '#{val}'}).show(); + - else + new Noty({type: '#{key}', layout: 'topRight', text: '#{val}'}).show(); diff --git a/app/views/lessons/_remove.html.haml b/app/views/lessons/_remove.html.haml index 1e67686..2e21370 100644 --- a/app/views/lessons/_remove.html.haml +++ b/app/views/lessons/_remove.html.haml @@ -5,9 +5,9 @@ %li %i.fa.fa-check.has-text-primary = les.name -= form_tag '/lessons/remove', method: 'post' do - .field - .control - .select.is-primary - = select_tag :lesson, options_from_collection_for_select(lessons, :id, :name) - %input.button.is-primary{type: 'submit'} + = form_tag '/lessons/remove', method: 'post' do + .field + .control + .select.is-primary + = select_tag :lesson, options_from_collection_for_select(lessons, :id, :name) + %input.button.is-primary{type: 'submit'} diff --git a/app/views/lessons/grades.html.haml b/app/views/lessons/grades.html.haml new file mode 100644 index 0000000..76b1370 --- /dev/null +++ b/app/views/lessons/grades.html.haml @@ -0,0 +1,25 @@ +.container + = form_tag '/lessons/submit_grades', method: 'post' do + %input.button.is-success.is-pulled-right#grades_submit{type: 'submit'} + .columns.is-multiline + - for i in 1..8 + .column.is-4 + .box.grader + %h3.title.has-text-centered.is-primary Semester #{i} + %hr + - current_user.lessons.where(semester: i, selected: true).each do |les| + %h5.subtitle.is-grey= les.name + %input.slider.is-fullwidth.is-primary.has-output{id: "lesson#{les.id}", step: 1, min: '0', max: '10', value: "#{les.grade}", type: 'range', name: les.name} + %output{for: "lesson#{les.id}"}= les.grade + + +:javascript + $( function(){ + $('.slider').on('change', function(){ + if (parseInt($(this)[0].value) >= 5){ + $(this).removeClass("is-danger is-primary").addClass("is-success"); + } else + $(this).removeClass("is-success is-primary").addClass("is-danger"); + console.log($(this)[0].value) + }); + }); diff --git a/app/views/lessons/index.html.haml b/app/views/lessons/index.html.haml index b6faebf..5e0419d 100644 --- a/app/views/lessons/index.html.haml +++ b/app/views/lessons/index.html.haml @@ -2,7 +2,7 @@ %section.hero.is-light.rounded .hero-body .container.has-text-centered - %h1.title Lesson List + %h1.title Classes List .column.is-10.is-offset-2 %section.section %table.table @@ -13,7 +13,7 @@ %th Semester %th Grade %tbody - - Lesson.where(selected: true).group_by(&:semester).each do |sem| + - @list.each do |sem| %thead %th.has-text-centered{ colspan: '5'} Semester #{sem[0]} - sem[1].each do |les| @@ -26,32 +26,12 @@ %thead %th %th - %th= Lesson.where(semester: sem[0], grade: [5..10]).sum(:ects) + %th= current_user.lessons.where(semester: sem[0], grade: [5..10]).sum(:ects) %th - %th= Lesson.where(semester: sem[0], grade: [5..10]).average(:grade).to_s.first(4) + %th= current_user.lessons.where(semester: sem[0], grade: [5..10]).average(:grade).to_s.first(4) %thead %th Summary %th - - %th= Lesson.where(selected: true, grade: [5..10]).sum(:ects) + %th= current_user.lessons.where(selected: true, grade: [5..10]).sum(:ects) %th - - %th= Lesson.where(selected: true, grade: [5..10]).average(:grade).to_s.first(4) -%section.section - %div.tile.is-vertical.is-ancestor - %div.tile.is-vertical.is-8 - %div.tile - %div.tile.is-parent.is-vertical - %article.tile.is-child.notification.is-primary - %p.title Μέσος Όρος: - %p.subtitle= avg_calc.nil? ? 'Πρόσθεσε Μαθήματα':avg_calc.to_s.first(4) - %article.tile.is-child.notification.is-info - %p.subtitle Σύνολο Μαθημάτων: #{Lesson.where(selected: true).count} - %p.subtitle Περασμένα/Χρωστούμενα: (#{Lesson.where(selected: true, grade: [5..10]).count}/#{Lesson.where(selected: true, grade: [0..4]).count}) - %p.subtitle Υποχρεωτικά: #{Lesson.where(selected: true, ltype: 1).count} - %p.subtitle Bασικής Επιλογής: #{Lesson.where(selected: true, ltype: 2).count} - %p.subtitle Γενικής Επιλογής: #{Lesson.where(selected: true, ltype: 3).count} - %p.subtitle Ειδικής Επιλογής: #{Lesson.where(selected: true, ltype: 4).count} - %div.tile.is-parent - %article.tile.is-child.notification{class: Lesson.thesis? || Lesson.no_thesis? ? 'is-success' : 'is-danger'} - %p.title Δυνατότα Αποφοίτησης? - %p.subtitle Πτυχιακή #{Lesson.thesis?} - %p.subtitle Χωρίς Πτυχιακή #{Lesson.no_thesis?} + %th= avg_calc.to_s.first(4) diff --git a/app/views/lessons/new.html.haml b/app/views/lessons/new.html.haml deleted file mode 100644 index 90a4b32..0000000 --- a/app/views/lessons/new.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -%div.container - = form_tag '/lessons/submit_grades', method: 'post' do - %input.button.is-primary.is-pulled-right{type: 'submit'} - .columns - .column.is-half.is-offset-one-quarter.box.has-text-centered{id: 'accordion'} - -for i in 1..8 - %h3.title Semester #{i} - %div - - Lesson.where(semester: i, selected: true).each do |les| - %label.label #{les.name} - %div.select.is-info - %select.select.is-multiple{id: "lesson#{les.id}", name: les.name} - - for i in 1..10 - - if les.grade == i - %option{value: i, selected: 'selected'} #{i} - - else - %option{value: i } #{i} -:javascript - $( function() { - $( "#accordion" ).accordion({ - collapsible: true - }); - } ); diff --git a/app/views/lessons/semesters.html.haml b/app/views/lessons/semesters.html.haml deleted file mode 100644 index 81467eb..0000000 --- a/app/views/lessons/semesters.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -%h3.title.has-text-centered Per Semester Analysis -.tabs.is-centered - %ul - - @semesters.each_with_index do |sem, i| - %li - %a{href: "/lessons/semesters/#{i+1}"} Semester #{i+1} diff --git a/app/views/lessons/show_semester.html.haml b/app/views/lessons/show_semester.html.haml index 0558b85..6ad16c1 100644 --- a/app/views/lessons/show_semester.html.haml +++ b/app/views/lessons/show_semester.html.haml @@ -6,7 +6,7 @@ %i.fa.fa-angle-left %span Previous %li - %a{href: '/lessons/semesters'} + %a{href: lessons_path} %span.icon %i.fa.fa-angle-up %span Back @@ -19,7 +19,7 @@ .columns .column.is-3.is-offset-2 .box - %h4.has-text-info Average: #{sem_avg(params[:id].to_i)} + %h4.has-text-info Average: #{sem_avg(params[:id]).to_s.first(4)} %h4.has-text-success Passed: #{Lesson.where(semester: params[:id].to_i, grade: [5..10]).count} .column.is-3 .box diff --git a/app/views/lessons/stats.html.haml b/app/views/lessons/stats.html.haml index e69de29..c39227c 100644 --- a/app/views/lessons/stats.html.haml +++ b/app/views/lessons/stats.html.haml @@ -0,0 +1,92 @@ +%nav.level.stats + .level-item.has-text-centered + %div + %p.heading Περασμενα + %p.title.has-text-success= passed.count + .level-item.has-text-centered + %div + %p.heading Χρωστουμενα + %p.title.has-text-danger= current_user.thesis? ? 42 - passed.count : 44 - passed.count + .level-item.has-text-centered + %div + %p.heading ECTS + %p.title.has-text-info= current_user.ects + .level-item.has-text-centered + %div + %p.heading ΒΑΘΜΟΣ + %p.title= current_user.s_avg.to_s.first(4) +%hr.major +.container + .columns.is-multiline + .column.is-12 + %h3.has-text-centered Your Grades + = area_chart @lessons.group(:name).maximum(:grade), colors: ["#008ed6"], library: {scales: { xAxes: [ { display: false } ]} } + .column.is-6 + %h3.has-text-centered Per Semester Avg + // passed is a helper method + = line_chart passed.group(:semester).average(:grade), xtitle: 'Semesters', colors: ["hsl(171, 100%, 41%)"], min: '5' + .column.is-6.box-container + .box + %h3.has-text-centered Performance + %h5 + Best Semester: + %strong.has-text-success #{passed.group(:semester).average(:grade).max_by(&:last).first} + with avg + %strong.has-text-success #{passed.group(:semester).average(:grade).max_by(&:last).last} + %h5 + Worst Semster: + %strong.has-text-danger #{passed.group(:semester).average(:grade).min_by(&:last).first} + with avg + %strong.has-text-danger #{passed.group(:semester).average(:grade).min_by(&:last).last} + %h5 + Winter Semesters + %strong= avg_winter_semesters.to_s.first(4) + %h5 + Summer Semesters + %strong= avg_summer_semesters.to_s.first(4) + %h5 + Κορμού + %strong= avg_std.to_s.first(4) + %h5 + Βασικής + %strong= avg_basic.to_s.first(4) + %h5 + Γενικής + %strong= avg_gen.to_s.first(4) + %h5 + Ειδικής + %strong= avg_sp.to_s.first(4) + .column.is-6.box-container + .box + %h3.has-text-centered Grades Distribution + %h5 Most Frequent: #{passed.group(:grade).count.max_by(&:last).first} (#{passed.group(:grade).count.max_by(&:last).last}) + %h5 Most Infrequent: #{passed.group(:grade).count.min_by(&:last).first} (#{passed.group(:grade).count.min_by(&:last).last}) + .column.is-6 + %h3.has-text-centered Grades Frequency + = pie_chart passed.group(:grade).count, colors: ["hsl(171, 100%, 41%)", "hsl(217, 71%, 53%)", "hsl(141, 71%, 48%)", 'hsl(48, 100%, 67%)','hsl(348, 100%, 61%)','hsl(204, 86%, 53%)'], donut: true, legend: false + .column.is-8 + %h3.has-text-centered By Lesson Category + = area_chart category_avg, min: 5, library: {scales: { xAxes: [ { display: false } ]} } + .column.is-4.box-container + .box + %h3.has-text-centered Best - Worst Categories + - @best = category_avg.max_by {|key, val| val} + %h5 + Best Category #{@best[0]} with + %strong= @best[1].to_s.first(4) + - @worst = category_avg.min_by {|key, val| val} + %h5 + Worst Category #{@worst[0]} with + %strong= @worst[1].to_s.first(4) + %h5 + Categories Count + %strong= category_avg.count + +:javascript + $(document).ready(function() { + $('.chart').easyPieChart({ + barColor: '#008ed6', + lineWidth: 8, + scaleColor: false + }); + }); diff --git a/app/views/lessons/status.html.haml b/app/views/lessons/status.html.haml new file mode 100644 index 0000000..c90a3a7 --- /dev/null +++ b/app/views/lessons/status.html.haml @@ -0,0 +1,70 @@ +- @usr = current_user +.container + %section.section + %div.tile.is-vertical.is-ancestor + %div.tile.is-vertical.is-12 + %div.tile + %div.tile.is-parent.is-vertical + %article.tile.is-child.notification.is-primary + %p.title + Μέσος Όρος: + %strong.bright{class: avg_color} #{avg_calc.nil? ? 'Πρόσθεσε Μαθήματα':avg_calc.to_s.first(4)} + %article.tile.is-child.notification.is-info + %p.subtitle Σύνολο Μαθημάτων: #{@usr.lessons_total} + %p.subtitle Περασμένα/Χρωστούμενα: (#{@usr.passed}/#{@usr.lessons_total - @usr.passed}) + %p.subtitle Υποχρεωτικά: 31 + %p.subtitle Bασικής Επιλογής: #{@usr.basics} + %p.subtitle Γενικής Επιλογής: #{@usr.generals} + %p.subtitle Ειδικής Επιλογής: #{@usr.specials} + %div.tile.is-parent + %article.tile.is-child.notification{class: @usr.graduated? ? 'is-success' : 'is-danger'} + %p.title Δυνατότα Αποφοίτησης? + %p.subtitle Πτυχιακή #{@usr.eligible?} + %p.subtitle + %table.table.is-fullwidth.has-text-centered#status-table + %thead + %td + %td Δηλωμένα + %td Περασμένα + %tbody + %tr + %td Υποχρεωτικά + %td.has-text-centered + %a.tooltip.is-tooltip-success{data: { tooltip: "Εχουν δηλωθεί όλα τα υποχρεωτικά" } } + %i.fa{class: "fa-#{icon_generator(true)}"} + %td.has-text-centered + %a.tooltip{class: (@usr.standards? ? 'is-tooltip-success' : 'is-tooltip-danger'), data: { tooltip: (@usr.standards? ? 'Έχεις περάσει όλα τα υποχρεωτικά' : "Πρέπει να περάσεις ακόμη #{31 - @usr.standards}") } } + %i.fa{class: "fa-#{icon_generator(@usr.standards?)}"} + %tr + %td Βασικής + %td.has-text-centered + %a.tooltip{class: (@usr.basics? ? 'is-tooltip-success' : 'is-tooltip-danger'), data: { tooltip: (@usr.basics? ? 'Έχεις δηλώσει όλα τα ΒΕ' : "Πρέπει να δηλώσεις ακόμη #{4 - @usr.basics}") } } + %i.fa{class: "fa-#{icon_generator(@usr.basics?)}"} + %td.has-text-centered + %a.tooltip{class: (@usr.basics_passed? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.basics_passed? ? 'Έχεις περάσει όλα τα ΒΕ' : "Πρέπει να περάσεις ακόμη #{4 - @usr.basics}") } } + %i.fa{class: "fa-#{icon_generator(@usr.basics_passed?)}"} + %tr + %td Γενικής + %td.has-text-centered + %a.tooltip{class: (@usr.generals? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.generals? ? 'Έχεις δηλώσει όλα τα ΓΕ' : "Πρέπει να δηλώσεις ακόμη #{3 - @usr.generals}") } } + %i.fa{class: "fa-#{icon_generator(@usr.generals?)}"} + %td.has-text-centered + %a.tooltip{class: (@usr.generals_passed? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.generals_passed? ? 'Έχεις περάσει όλα τα ΓΕ' : "Πρέπει να περάσεις ακόμη #{3 - @usr.basics}") } } + %i.fa{class: "fa-#{icon_generator(@usr.generals_passed?)}"} + %tr + %td Ειδικής + %td.has-text-centered + %a.tooltip{class: (@usr.specials? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.specials? ? 'Έχεις δηλώσεις όλα τα EIE' : "Πρέπει να δηλώσεις ακόμη #{3 - @usr.specials}") } } + %i.fa{class: "fa-#{icon_generator(@usr.specials?)}"} + %td.has-text-centered + %a.tooltip{class: (@usr.specials_passed? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.specials_passed? ? 'Έχεις περάσει όλα τα EIE' : "Πρέπει να περάσεις ακόμη #{3 - @usr.specials_passed}") } } + %i.fa{class: "fa-#{icon_generator(@usr.specials_passed?)}"} + - if @usr.thesis? + %tr + %td Πτυχιακή + %td.has-text-centered + %a.tooltip{class: (@usr.thesis? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.thesis? ? 'Έχεις δηλώσει πτυχιακή' : "Πρέπει να δηλώσεις πτυχιακή ή 2 ακόμη ΓΕ ή ΕΙΕ") } } + %i.fa{class: "fa-#{icon_generator(@usr.thesis?)}"} + %td.has-text-centered + %a.tooltip{class: (@usr.thesis_passed? ? 'is-tooltip-success' : 'is-tooltip-danger'),data: { tooltip: (@usr.thesis_passed? ? 'Έχεις περάσει την πτυχιακή' : "Πρέπει να περάσεις πτυχιακή") } } + %i.fa{class: "fa-#{icon_generator(@usr.thesis_passed?)}"} diff --git a/app/views/users/confirmations/new.html.haml b/app/views/users/confirmations/new.html.haml new file mode 100644 index 0000000..54a0069 --- /dev/null +++ b/app/views/users/confirmations/new.html.haml @@ -0,0 +1,14 @@ +.column.is-3.is-offset-3 + %h2 Resend confirmation instructions + = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| + = devise_error_messages! + + .field + %p.control.has-icons-left + = f.email_field :email, autofocus: true, value: (resource.pending_reconfirmation? resource.unconfirmed_email : resource.email), class: 'input', placeholder: 'Email' + %span.icon.is-small.is-left + %i.fa.fa-envelope + .control + = f.submit "Resend confirmation instructions", class: 'button is-primary' + + = render "users/shared/links" diff --git a/app/views/users/mailer/confirmation_instructions.html.erb b/app/views/users/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..dc55f64 --- /dev/null +++ b/app/views/users/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

diff --git a/app/views/users/mailer/email_changed.html.erb b/app/views/users/mailer/email_changed.html.erb new file mode 100644 index 0000000..32f4ba8 --- /dev/null +++ b/app/views/users/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @email %>!

+ +<% if @resource.try(:unconfirmed_email?) %> +

We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

+<% else %> +

We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

+<% end %> diff --git a/app/views/users/mailer/password_change.html.erb b/app/views/users/mailer/password_change.html.erb new file mode 100644 index 0000000..b41daf4 --- /dev/null +++ b/app/views/users/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +

Hello <%= @resource.email %>!

+ +

We're contacting you to notify you that your password has been changed.

diff --git a/app/views/users/mailer/reset_password_instructions.html.erb b/app/views/users/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..f667dc1 --- /dev/null +++ b/app/views/users/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password. You can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/users/mailer/unlock_instructions.html.erb b/app/views/users/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..41e148b --- /dev/null +++ b/app/views/users/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

diff --git a/app/views/users/passwords/edit.html.haml b/app/views/users/passwords/edit.html.haml new file mode 100644 index 0000000..3c85814 --- /dev/null +++ b/app/views/users/passwords/edit.html.haml @@ -0,0 +1,18 @@ +.column.is-3.is-offset-3 + %h2 Change your password + = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| + = devise_error_messages! + = f.hidden_field :reset_password_token + .field + %p.control.has-icons-left + = f.password_field :password, autofocus: true, autocomplete: "off", class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-lock + .field + %p.control.has-icons-left + = f.password_field :password_confirmation, autocomplete: "off", class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-lock + .control + = f.submit "Change my password", class: 'button is-primary' + = render "users/shared/links" diff --git a/app/views/users/passwords/new.html.haml b/app/views/users/passwords/new.html.haml new file mode 100644 index 0000000..23a3af5 --- /dev/null +++ b/app/views/users/passwords/new.html.haml @@ -0,0 +1,13 @@ +.column.is-3.is-offset-3 + %h2 Forgot your password? + + = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| + = devise_error_messages! + .field + %p.control.has-icons-left + = f.email_field :email, autofocus: true, placeholder: 'Email', class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-envelope + .control + = f.submit "Send me reset password instructions", class: 'button is-primary ' + = render "users/shared/links" diff --git a/app/views/users/registrations/edit.html.haml b/app/views/users/registrations/edit.html.haml new file mode 100644 index 0000000..0d0565b --- /dev/null +++ b/app/views/users/registrations/edit.html.haml @@ -0,0 +1,33 @@ +.column.is-3.is-offset-3 + %h2 + Edit #{resource_name.to_s.humanize} + = form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| + = devise_error_messages! + .field + %p.control.has-icons-left + = f.email_field :email, autofocus: true, placeholder: 'Email', class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-envelope + - if devise_mapping.confirmable? && resource.pending_reconfirmation? + %div + Currently waiting confirmation for: #{resource.unconfirmed_email} + .field + %small leave blank if you don't want to change it + %p.control.has-icons-left + = f.password_field :password, autocomplete: "off", class: 'input', placeholder: 'New Password' + %span.icon.is-small.is-left + %i.fa.fa-lock + .field + %p.control.has-icons-left + = f.password_field :password_confirmation, autocomplete: "off",class: 'input', placeholder: 'New Password Verification' + %span.icon.is-small.is-left + %i.fa.fa-lock + .field + %p.control.has-icons-left + = f.password_field :current_password, autocomplete: "off", class: 'input', placeholder: 'Old Password' + .control + = f.submit "Update", class: 'button is-primary' + %p + %i.fa.fa-frown-o.has-text-danger + Unhappy? #{button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete, class: 'button is-danger'} + = link_to "Back", :back diff --git a/app/views/users/registrations/new.html.haml b/app/views/users/registrations/new.html.haml new file mode 100644 index 0000000..8b5fbc1 --- /dev/null +++ b/app/views/users/registrations/new.html.haml @@ -0,0 +1,28 @@ +.column.is-3.is-offset-3 + %h2 Sign up + = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| + -unless devise_error_messages!.empty? + .notification.is-warning{style: 'width: 140%'} + =devise_error_messages! + + .field + %p.control.has-icons-left + = f.email_field :email, autofocus: true, class: 'input', placeholder: 'Email' + %span.icon.is-small.is-left + %i.fa.fa-envelope + + .field + %p.control.has-icons-left + = f.password_field :password, autocomplete: "off", placeholder: 'Password', class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-lock + .field + %p.control.has-icons-left + = f.password_field :password_confirmation, autocomplete: "off", class: 'input', placeholder: 'Verify Password' + %span.icon.is-small.is-left + %i.fa.fa-lock + + .control + = f.submit "Sign up", class: 'button is-primary' + + = render "users/shared/links" diff --git a/app/views/users/sessions/new.html.haml b/app/views/users/sessions/new.html.haml new file mode 100644 index 0000000..064f959 --- /dev/null +++ b/app/views/users/sessions/new.html.haml @@ -0,0 +1,21 @@ +.box.column.is-5.is-offset-3.devise-form.is-centered + = image_tag 'logo', class: 'is-centered' + %h2 Log in + = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| + .field + %p.control.has-icons-left + = f.email_field :email, autofocus: true, placeholder: 'Email', class: 'input' + %span.icon.is-small.is-left + %i.fa.fa-envelope + .field + %p.control.has-icons-left + = f.password_field :password, autocomplete: "off", class: 'input', placeholder: 'Password' + %span.icon.is-small.is-left + %i.fa.fa-lock + - if devise_mapping.rememberable? + .field + = f.check_box :remember_me + = f.label :remember_me + .control.is-grouped.is-grouped-right.is-pulled-right + = f.submit "Log in", class: 'button is-primary' + = render "users/shared/links" diff --git a/app/views/users/shared/_links.html.haml b/app/views/users/shared/_links.html.haml new file mode 100644 index 0000000..19219bf --- /dev/null +++ b/app/views/users/shared/_links.html.haml @@ -0,0 +1,23 @@ +.field.is-grouped-left + - if controller_name != 'sessions' + %p.control + = link_to "Log in", new_session_path(resource_name), class: 'button is-primary' + - if devise_mapping.registerable? && controller_name != 'registrations' + %p.control + = link_to "Sign up", new_registration_path(resource_name), class: 'button is-success' + + - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' + %p.control + = link_to "Password Reset", new_password_path(resource_name), class: 'button is-warning' + + - if devise_mapping.confirmable? && controller_name != 'confirmations' + %p.control + = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'button is-info' + + - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' + %p.control + = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: 'button is-info' + + - if devise_mapping.omniauthable? + - resource_class.omniauth_providers.each do |provider| + = link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) diff --git a/app/views/users/unlocks/new.html.haml b/app/views/users/unlocks/new.html.haml new file mode 100644 index 0000000..0b42f20 --- /dev/null +++ b/app/views/users/unlocks/new.html.haml @@ -0,0 +1,19 @@ +- if controller_name != 'sessions' + = link_to "Log in", new_session_path(resource_name), class: 'button is-primary' + %br/ +- if devise_mapping.registerable? && controller_name != 'registrations' + = link_to "Sign up", new_registration_path(resource_name), class: 'button is-info' + %br/ +- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' + = link_to "Forgot your password?", new_password_path(resource_name), class: 'button is-warning' + %br/ +- if devise_mapping.confirmable? && controller_name != 'confirmations' + = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'button is-warning' + %br/ +- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' + = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: 'button is-warning' + %br/ +- if devise_mapping.omniauthable? + - resource_class.omniauth_providers.each do |provider| + = link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) + %br/ diff --git a/config/initializers/chartkick.rb b/config/initializers/chartkick.rb new file mode 100644 index 0000000..a754bf5 --- /dev/null +++ b/config/initializers/chartkick.rb @@ -0,0 +1,3 @@ +Chartkick.options = { + download: 'gpa_chart' +} diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 311b058..43ea3a4 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -6,16 +6,11 @@ # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. - # config.secret_key = 'e238b70dfe64f1867f3d45e5d6779ff7f536fd344bcea0a098b6571fff5b988c863dd5744615af0b01aa947a8872eded2c0bdac4d235ac9faa2a3728bc4fc3c9' - # ==> Mailer Configuration # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' - Rails.application.config.to_prepare do - Devise::RegistrationsController.layout(proc) { |controller| user_signed_in? ? 'application' : 'devise' } - end + config.mailer_sender = 'grades@wiseinno.tech' # Configure the class responsible to send e-mails. # config.mailer = 'Devise::Mailer' diff --git a/config/routes.rb b/config/routes.rb index 958a498..ed8c711 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,7 @@ devise_for :users get '/lessons' => 'lessons#index' post '/lessons/submit_grades' => 'lessons#submit_grades' - get '/lessons/new' => 'lessons#new' + get '/lessons/grades' => 'lessons#grades' get '/lessons/add' => 'lessons#add' post '/lessons/select' => 'lessons#select' get 'lessons/delete' => 'lessons#delete' @@ -10,6 +10,7 @@ get 'lessons/semesters' => 'lessons#semesters' get 'lessons/semesters/:id' => 'lessons#show_semester' get 'lessons/stats' => 'lessons#stats' + get 'lessons/status' => 'lessons#status' get '/about' => 'main#about' root 'main#index' end diff --git a/db/migrate/20171023170738_create_subjects.rb b/db/migrate/20171023170738_create_subjects.rb new file mode 100644 index 0000000..5e358f2 --- /dev/null +++ b/db/migrate/20171023170738_create_subjects.rb @@ -0,0 +1,13 @@ +class CreateSubjects < ActiveRecord::Migration[5.1] + def change + create_table :subjects do |t| + t.string :name + t.string :code + t.integer :ects + t.integer :semester + t.integer :ltype + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 3cd4ac4..fe22f08 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171023091505) do +ActiveRecord::Schema.define(version: 20171023170738) do create_table "lessons", force: :cascade do |t| t.string "code" @@ -27,6 +27,16 @@ t.index ["user_id"], name: "index_lessons_on_user_id" end + create_table "subjects", force: :cascade do |t| + t.string "name" + t.string "code" + t.integer "ects" + t.integer "semester" + t.integer "ltype" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false diff --git a/db/seeds.rb b/db/seeds.rb index a3c8502..6ce1115 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -2,6 +2,6 @@ @thing = YAML.load_file('config/lessons.yml') @thing['lessons'].each do |les| - Lesson.create!(name: les['name'], code: les['code'], ects: les['ects'], + Subject.create!(name: les['name'], code: les['code'], ects: les['ects'], semester: les['semester'], ltype: les['type']) end diff --git a/package.json b/package.json index 2b5cab9..187c8d3 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,8 @@ "name": "grades", "private": true, "dependencies": { + "bulma-slider": "^0.0.2", + "bulma-tooltip": "^0.0.4", "noty": "^3.1.3" } } diff --git a/test/fixtures/subjects.yml b/test/fixtures/subjects.yml new file mode 100644 index 0000000..d6a41b3 --- /dev/null +++ b/test/fixtures/subjects.yml @@ -0,0 +1,15 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + code: MyString + ects: 1 + semester: 1 + ltype: 1 + +two: + name: MyString + code: MyString + ects: 1 + semester: 1 + ltype: 1 diff --git a/test/models/subject_test.rb b/test/models/subject_test.rb new file mode 100644 index 0000000..d54e76f --- /dev/null +++ b/test/models/subject_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SubjectTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/yarn.lock b/yarn.lock index 60785b8..fe51823 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +bulma-slider@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/bulma-slider/-/bulma-slider-0.0.2.tgz#589f03b654c434a2b39c9acaff3781b85e92e3e7" + +bulma-tooltip@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/bulma-tooltip/-/bulma-tooltip-0.0.4.tgz#05e734158a56fae839056a07f3e25ef09407c91a" + noty@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/noty/-/noty-3.1.3.tgz#4fbc8068b9b6b29386f73c902a9ff84ad612ab14"