Skip to content

Commit

Permalink
Create basic UI for saving an annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
chvp committed May 9, 2022
1 parent 6f98720 commit 8c838a6
Show file tree
Hide file tree
Showing 24 changed files with 348 additions and 60 deletions.
35 changes: 27 additions & 8 deletions app/assets/javascripts/code_listing/annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export abstract class Annotation {
// Do nothing.
}

protected save(): void {
// Do nothing.
}

public get global(): boolean {
return this.line === null;
}
Expand Down Expand Up @@ -81,16 +85,27 @@ export abstract class Annotation {

// Update button.
if (this.modifiable) {
const link = document.createElement("a");
link.addEventListener("click", () => this.edit());
link.classList.add("btn", "btn-icon", "annotation-control-button", "annotation-edit");
link.title = this.editTitle;
const edit_link = document.createElement("a");
edit_link.addEventListener("click", () => this.edit());
edit_link.classList.add("btn", "btn-icon", "annotation-control-button", "annotation-edit");
edit_link.title = this.editTitle;

const icon = document.createElement("i");
icon.classList.add("mdi", "mdi-pencil");
link.appendChild(icon);
const edit_icon = document.createElement("i");
edit_icon.classList.add("mdi", "mdi-pencil");
edit_link.appendChild(edit_icon);

header.appendChild(link);
header.appendChild(edit_link);

const save_link = document.createElement("a");
save_link.addEventListener("click", () => this.save());
save_link.classList.add("btn", "btn-icon", "annotation-control-button", "annotation-edit");
save_link.title = this.saveTitle;

const save_icon = document.createElement("i");
save_icon.classList.add("mdi", "mdi-content-save");
save_link.appendChild(save_icon);

header.appendChild(save_link);
}

if (this.transitionable("answered")) {
Expand Down Expand Up @@ -196,6 +211,10 @@ export abstract class Annotation {
return "";
}

protected get saveTitle(): string {
return "";
}

protected get hasNotice(): boolean {
return false;
}
Expand Down
14 changes: 14 additions & 0 deletions app/assets/javascripts/code_listing/user_annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ export class UserAnnotation extends Annotation {
this.__html.querySelector(".annotation-text").replaceWith(editor);
}

protected save(): void {
const modal = new bootstrap.Modal(document.getElementById("save-annotation"));
const fromField = document.getElementById("save-annotation-from");
const textField = document.getElementById("save-annotation-text")

fromField.value = this.id;
textField.value = this.__rawText;
modal.show();
}

protected get meta(): string {
const timestamp = I18n.l("time.formats.annotation", this.createdAt);
const user = this.user.name;
Expand Down Expand Up @@ -136,4 +146,8 @@ export class UserAnnotation extends Annotation {
protected get editTitle(): string {
return I18n.t("js.user_annotation.edit");
}

protected get saveTitle(): string {
return I18n.t("js.user_annotation.save")
}
}
4 changes: 2 additions & 2 deletions app/assets/javascripts/i18n/translations.js

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions app/controllers/saved_annotations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class SavedAnnotationsController < ApplicationController
before_action :set_saved_annotation, only: %i[show update destroy]

def index
authorize SavedAnnotation
@saved_annotations = apply_scopes(policy_scope(SavedAnnotation.all))
end

def show; end

def create
annotation = Annotation.find(params[:from])
authorize annotation, :show?
@saved_annotation = SavedAnnotation.new(permitted_attributes(SavedAnnotation).merge({ user: current_user, course: annotation.course, exercise: annotation.submission.exercise }))
authorize @saved_annotation
respond_to do |format|
if @saved_annotation.save
annotation.update(saved_annotation: @saved_annotation)
format.json { render :show, status: :created, location: @saved_annotation }
else
format.json { render json: @saved_annotation.errors, status: :unprocessable_entity }
end
end
end

def update
respond_to do |format|
if @saved_annotation.update(args)
format.json { render :show, status: :ok, location: @saved_annotation }
else
format.json { render json: @saved_annotation.errors, status: :unprocessable_entity }
end
end
end

def destroy
@saved_annotation.destroy
end

private

def set_saved_annotation
@saved_annotation = SavedAnnotation.find(params[:id])
authorize @saved_annotation
end
end
26 changes: 14 additions & 12 deletions app/models/annotation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
#
# Table name: annotations
#
# id :bigint not null, primary key
# line_nr :integer
# submission_id :integer
# user_id :integer
# annotation_text :text(16777215)
# created_at :datetime not null
# updated_at :datetime not null
# evaluation_id :bigint
# type :string(255) default("Annotation"), not null
# question_state :integer
# last_updated_by_id :integer not null
# course_id :integer not null
# id :bigint not null, primary key
# line_nr :integer
# submission_id :integer
# user_id :integer
# annotation_text :text(16777215)
# created_at :datetime not null
# updated_at :datetime not null
# evaluation_id :bigint
# type :string(255) default("Annotation"), not null
# question_state :integer
# last_updated_by_id :integer not null
# course_id :integer not null
# saved_annotation_id :bigint
#
class Annotation < ApplicationRecord
include ApplicationHelper
Expand All @@ -22,6 +23,7 @@ class Annotation < ApplicationRecord
belongs_to :submission
belongs_to :user
belongs_to :evaluation, optional: true
belongs_to :saved_annotation, optional: true
belongs_to :last_updated_by, class_name: 'User'

validates :annotation_text, presence: true, length: { minimum: 1, maximum: 10_000 }
Expand Down
21 changes: 21 additions & 0 deletions app/models/provider/surf.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# == Schema Information
#
# Table name: providers
#
# id :bigint not null, primary key
# type :string(255) default("Provider::Saml"), not null
# institution_id :bigint not null
# identifier :string(255)
# certificate :text(16777215)
# entity_id :string(255)
# slo_url :string(255)
# sso_url :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# mode :integer default("prefer"), not null
# active :boolean default(TRUE)
# authorization_uri :string(255)
# client_id :string(255)
# issuer :string(255)
# jwks_uri :string(255)
#
class Provider::Surf < Provider
validates :certificate, :entity_id, :sso_url, :slo_url, absence: true
validates :authorization_uri, :client_id, :issuer, :jwks_uri, absence: true
Expand Down
25 changes: 13 additions & 12 deletions app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
#
# Table name: annotations
#
# id :bigint not null, primary key
# line_nr :integer
# submission_id :integer
# user_id :integer
# annotation_text :text(16777215)
# created_at :datetime not null
# updated_at :datetime not null
# evaluation_id :bigint
# type :string(255) default("Annotation"), not null
# question_state :integer
# last_updated_by_id :integer not null
# course_id :integer not null
# id :bigint not null, primary key
# line_nr :integer
# submission_id :integer
# user_id :integer
# annotation_text :text(16777215)
# created_at :datetime not null
# updated_at :datetime not null
# evaluation_id :bigint
# type :string(255) default("Annotation"), not null
# question_state :integer
# last_updated_by_id :integer not null
# course_id :integer not null
# saved_annotation_id :bigint
#
class Question < Annotation
after_commit :clear_transition
Expand Down
23 changes: 23 additions & 0 deletions app/models/saved_annotation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# == Schema Information
#
# Table name: saved_annotations
#
# id :bigint not null, primary key
# title :string(255) not null
# annotation_text :text(16777215)
# user_id :integer not null
# exercise_id :integer not null
# course_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
class SavedAnnotation < ApplicationRecord
validates :title, presence: true
validates :annotation_text, presence: true

belongs_to :user
belongs_to :exercise
belongs_to :course

has_many :annotations, dependent: :nullify
end
37 changes: 37 additions & 0 deletions app/policies/saved_annotation_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class SavedAnnotationPolicy < ApplicationPolicy
class Scope < ApplicationPolicy::Scope
def resolve
if user&.zeus?
scope.all
elsif user
scope.where(user_id: user.id)
else
scope.none
end
end
end

def index?
user&.a_course_admin?
end

def create?
record.course_id.present? && user&.course_admin?(record.course)
end

def show?
record.user_id == user.id
end

def update?
record.user_id == user.id
end

def destroy?
record.user_id == user.id
end

def permitted_attributes
%i[title annotation_text]
end
end
1 change: 1 addition & 0 deletions app/views/feedbacks/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
</div>
</div>
<% if @feedback.submission.present? %>
<%= render 'saved_annotations/modal' %>
<div class="code-table" data-submission-id="<%= @feedback.submission.id %>">
<%= @feedback.submission.judge.renderer.new(@feedback.submission, current_user).parse %>
</div>
Expand Down
12 changes: 12 additions & 0 deletions app/views/saved_annotations/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<%= form_for(model, html: { class: 'form' }) do |f| %>
<%= hidden_field_tag 'from', nil, id: "save-annotation-from" %>
<div class="field form-group row">
<%= f.label :title, class: "col-sm-4 col-form-label" %>
<div class="col-sm-8"><%= f.text_field :title, required: true, class: "form-control" %></div>
</div>
<div class="field form-group row">
<%= f.label :annotation_text, class: "col-sm-4 col-form-label" %>
<div class="col-sm-8"><%= f.text_area :annotation_text, required: true, class: "form-control", rows: "4", id: "save-annotation-text" %></div>
<span class="help-block offset-sm-4 col-sm-8"><%= t ".annotation_text-help_html" %></span>
</div>
<% end %>
16 changes: 16 additions & 0 deletions app/views/saved_annotations/_modal.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="modal fade" id="save-annotation" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"><%= t ".title" %></h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<%= render 'saved_annotations/form', model: SavedAnnotation.new %>
</div>
<div class="modal-footer">
<button id="save-annotation-submit" type="button" class="btn btn-primary btn-text"><%= t ".save" %></button>
</div>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions app/views/submissions/_description.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<% end %>

<% unless submission.queued? or submission.running? %>
<%= render 'saved_annotations/modal' %>
<%= submission.judge.renderer.new(submission, current_user).parse %>
<% end %>

Expand Down
1 change: 1 addition & 0 deletions config/locales/js/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ en:
cancel: 'Cancel'
delete: 'Delete'
edit: 'Edit comment'
save: 'Save comment'
help: 'Press Shift + Enter to send. <a href="https://docs.dodona.be/en/references/exercise-description/#markdown" target="_blank">Markdown</a> is supported.'
fields:
annotation_text: 'Comment'
Expand Down
3 changes: 2 additions & 1 deletion config/locales/js/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ nl:
cancel: 'Annuleren'
delete: 'Verwijderen'
edit: 'Opmerking bewerken'
help: 'Druk Shift + Enter om te verzenden. <a href="https://docs.dodona.be/nl/references/exercise-description/#markdown" target="_blank">Markdown</a> wordt ondersteund.'
save: 'Opmerking opslaan'
help: 'Druk Shift + Enter om te verzenden. <a href="https://docs.dodona.be/nl/references/exercise-description/#markdown" target="_blank">Markdown</a> wordt ondersteund.'
fields:
annotation_text: 'Opmerking'
delete_confirm: 'Ben je zeker dat je deze opmerking wil verwijderen?'
Expand Down
7 changes: 7 additions & 0 deletions config/locales/views/saved_annotations/en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
en:
saved_annotations:
form:
annotation_text-help_html: '<a href="https://docs.dodona.be/en/references/exercise-description/#markdown" target="_blank">Markdown</a> is supported.'
modal:
save: "Save"
title: "Save comment for re-use"
7 changes: 7 additions & 0 deletions config/locales/views/saved_annotations/nl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
nl:
saved_annotations:
form:
annotation_text-help_html: '<a href="https://docs.dodona.be/nl/references/exercise-description/#markdown" target="_blank">Markdown</a> wordt ondersteund.'
modal:
save: "Opslaan"
title: "Opmerking opslaan om later te hergebruiken"
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@

resources :annotations, only: %i[index show create update destroy]

resources :saved_annotations, only: %i[index show create update destroy]

get 'questions', to: 'annotations#question_index'

resources :submissions, only: %i[index show create edit] do
Expand Down
17 changes: 17 additions & 0 deletions db/migrate/20220502130036_create_saved_annotations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class CreateSavedAnnotations < ActiveRecord::Migration[7.0]
def change
create_table :saved_annotations do |t|
t.string :title, null: false
t.text :annotation_text, size: :medium
t.integer :user_id, foreign_key: true, type: :integer, null: false
t.references :exercise, foreign_key: { to_table: :activities }, type: :integer, null: false
t.references :course, foreign_key: true, type: :integer, null: false

t.timestamps
end

change_table :annotations do |t|
t.references :saved_annotation, foreign_key: true
end
end
end
Loading

0 comments on commit 8c838a6

Please sign in to comment.