-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/documents #8
Changes from 11 commits
5685bc8
0b6b6de
f5e2260
43f7111
1184207
5d3668a
1e945bd
ed64590
c714c11
8910aa5
42739fb
0f9d28a
f7f2151
b85841a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
ActiveAdmin.register Document do | ||
menu priority: 3 | ||
|
||
decorate_with DocumentDecorator | ||
|
||
filter :name_contains | ||
filter :documentable_type, label: 'Attached to' | ||
|
||
config.batch_actions = false | ||
|
||
actions :all, except: [:new, :edit, :create, :update] | ||
|
||
show do | ||
attributes_table do | ||
row :id | ||
row :name | ||
row :link, &:open_link | ||
row :last_verified_on | ||
row :created_at | ||
row :updated_at | ||
end | ||
end | ||
|
||
index do | ||
column 'name', &:name_link | ||
column 'Attached To', :documentable | ||
column :last_verified_on | ||
actions | ||
end | ||
|
||
controller do | ||
def scoped_collection | ||
super.includes(:documentable) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
$padding: 20px; | ||
|
||
//Colors | ||
$admin-red: red; | ||
|
||
// Active Material Theme Colors Change | ||
$am-theme-primary: #00689f; | ||
$am-theme-accent: #7dd2f7; | ||
$am-theme-accent-fallback: $admin-red; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
class DocumentDecorator < Draper::Decorator | ||
delegate_all | ||
|
||
def name_link | ||
h.link_to model.name, h.admin_document_path(model) | ||
end | ||
|
||
def open_link | ||
h.link_to model.name, model.url, target: '_blank' | ||
end | ||
|
||
def last_verified_on | ||
return 'N/A' if model.uploaded? | ||
|
||
model.last_verified_on | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,12 @@ def summary | |
def core_objective | ||
model.core_objective.html_safe | ||
end | ||
|
||
def document_list | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good idea. |
||
return [] if model.documents.empty? | ||
|
||
model.documents.map do |document| | ||
h.link_to document.name, document.url, target: '_blank' | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Controller } from 'stimulus'; | ||
|
||
export default class extends Controller { | ||
static targets = [ 'links', 'templateExternal', 'templateUploaded'] | ||
|
||
connect() { | ||
this.wrapperClass = this.data.get('wrapperClass') || 'nested-fields'; | ||
} | ||
|
||
addRecord(event) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code here looks like it shouldn't be directly related with "documents", rather, it is more like generic add/remove resource logic, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right. I will change that |
||
event.preventDefault(); | ||
|
||
const templateName = event.target.dataset['template']; | ||
const content = this[`template${templateName}Target`] | ||
.innerHTML | ||
.replace(/NEW_RECORD/g, new Date().getTime()); | ||
|
||
this.linksTarget.insertAdjacentHTML('beforebegin', content); | ||
} | ||
|
||
removeRecord(event) { | ||
event.preventDefault(); | ||
|
||
const wrapper = event.target.closest('.' + this.wrapperClass); | ||
|
||
// New records are simply removed from the page | ||
if (wrapper.dataset.newRecord == 'true') { | ||
wrapper.remove(); | ||
|
||
// Existing records are hidden and flagged for deletion | ||
} else { | ||
wrapper.querySelector('input[name*="_destroy"]').value = 1; | ||
wrapper.style.display = 'none'; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# == Schema Information | ||
# | ||
# Table name: documents | ||
# | ||
# id :bigint not null, primary key | ||
# name :string not null | ||
# type :string not null | ||
# external_url :text | ||
# language :string | ||
# last_verified_on :date | ||
# documentable_type :string | ||
# documentable_id :bigint | ||
# created_at :datetime not null | ||
# updated_at :datetime not null | ||
# | ||
|
||
class Document < ApplicationRecord | ||
self.inheritance_column = nil | ||
|
||
TYPES = %w[uploaded external].freeze | ||
enum type: array_to_enum_hash(TYPES) | ||
|
||
belongs_to :documentable, polymorphic: true | ||
|
||
has_one_attached :file | ||
|
||
before_create :set_last_verified_on | ||
|
||
validates :external_url, url: true, presence: true, if: :external? | ||
validates :file, attached: true, if: :uploaded? | ||
|
||
validates_presence_of :name, :type | ||
|
||
def url | ||
return file_url if uploaded? | ||
|
||
external_url | ||
end | ||
|
||
private | ||
|
||
def file_url | ||
return unless file.attached? | ||
|
||
Rails.application.routes.url_helpers.polymorphic_url(file, only_path: true) | ||
end | ||
|
||
def set_last_verified_on | ||
self.last_verified_on = Time.zone.now.to_date | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class AttachedValidator < ActiveModel::EachValidator | ||
def validate_each(record, attribute, value) | ||
record.errors.add(attribute, :attached, options) unless value.attached? | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class UrlValidator < ActiveModel::EachValidator | ||
def validate_each(record, attribute, value) | ||
return unless value.present? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could we combine There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I will make two separate guard clauses. I think 2 will be more readable. |
||
|
||
record.errors[attribute] << (options[:message] || 'must be a valid URL') unless url_valid?(value) | ||
end | ||
|
||
def url_valid?(url) | ||
url = begin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rubocop changed that automagically. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, let's not mess with RuboCop 🤖 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I already did. lol. I don't like that rule There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. haha ok ) |
||
URI.parse(url) | ||
rescue StandardError | ||
false | ||
end | ||
url.is_a?(URI::HTTP) || url.is_a?(URI::HTTPS) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<% is_new_record = form.object.new_record? %> | ||
|
||
<%= content_tag :div, class: "nested-fields inline-fields", data: { new_record: is_new_record } do %> | ||
<%= form.input :type, as: :hidden, input_html: { value: form.object.type } %> | ||
<div style="width: 33%;"> | ||
<% if form.object.external? %> | ||
<%= form.input :external_url, as: :string, label: 'Provide external url' %> | ||
<% else %> | ||
<%= form.input :file, as: :file %> | ||
<% end %> | ||
</div> | ||
<%= form.input :name, wrapper_html: { class: 'flex-grow-1' } %> | ||
<li class="input"> | ||
<%= button_tag "Remove", type: 'button', class: 'button button--raised button--red', data: { action: "click->document-list#removeRecord" } %> | ||
</li> | ||
<%= form.hidden_field :_destroy %> | ||
<% end %> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<div class="document-list" data-controller="document-list"> | ||
<template data-target="document-list.templateExternal"> | ||
<%= form.semantic_fields_for :documents, Document.new(type: 'external'), child_index: 'NEW_RECORD' do |document| %> | ||
<%= render "admin/documents/fields", form: document %> | ||
<% end %> | ||
</template> | ||
|
||
<template data-target="document-list.templateUploaded"> | ||
<%= form.semantic_fields_for :documents, Document.new(type: 'uploaded'), child_index: 'NEW_RECORD' do |document| %> | ||
<%= render "admin/documents/fields", form: document %> | ||
<% end %> | ||
</template> | ||
|
||
<%= form.semantic_fields_for :documents do |document| %> | ||
<%= render "admin/documents/fields", form: document %> | ||
<% end %> | ||
|
||
<div class="document-list__actions" data-target="document-list.links"> | ||
<%= button_tag "Add External URL", type: 'button', class: 'button button--raised', data: { action: "click->document-list#addRecord", template: 'External' } %> | ||
<%= button_tag "Upload a new file", type: 'button', class: 'button button--raised', data: { action: "click->document-list#addRecord", template: 'Uploaded' } %> | ||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you think about renaming those methods ..
name_link
=>document_page_link
(orjust document_link
)open_link
=>document_url_link
.. to indicate where those links actually go.