diff --git a/apps/api/app/admin/events.rb b/apps/api/app/admin/events.rb index d78826f..5f91f01 100644 --- a/apps/api/app/admin/events.rb +++ b/apps/api/app/admin/events.rb @@ -3,11 +3,23 @@ ActiveAdmin.register Event do menu priority: 3 + scope :all, default: true + scope("Upcoming") { |scope| scope.where("date >= ?", Time.current) } + scope("Past") { |scope| scope.where("date < ?", Time.current) } + index do selectable_column id_column column :name - column :date + column :date do |event| + if event.date >= Time.current + status_tag "upcoming", class: "ok" + text_node " #{l event.date, format: :long}" + else + status_tag "past", class: "default" + text_node " #{l event.date, format: :long}" + end + end column :created_at actions end diff --git a/apps/api/app/admin/files.rb b/apps/api/app/admin/files.rb index 622661c..efe6d4b 100644 --- a/apps/api/app/admin/files.rb +++ b/apps/api/app/admin/files.rb @@ -39,8 +39,8 @@ ActiveAdmin.register_page "Files" do end end - # Action bar - div class: "fm-actions" do + # Action bar (also drop zone on standalone page) + div class: "fm-actions fm-dropzone", id: "fm-page-dropzone" do form action: admin_files_upload_path, method: "post", enctype: "multipart/form-data", class: "fm-inline-form" do |_f| input type: "hidden", name: "authenticity_token", value: form_authenticity_token input type: "hidden", name: "dir", value: current_dir diff --git a/apps/api/app/admin/images.rb b/apps/api/app/admin/images.rb index 39742a3..dddd6e9 100644 --- a/apps/api/app/admin/images.rb +++ b/apps/api/app/admin/images.rb @@ -3,6 +3,20 @@ ActiveAdmin.register Image do menu priority: 5 + scope :all, default: true + scope("In use") { |scope| scope.where(id: SoftwareImage.select(:image_id)).or(scope.where(id: Member.where.not(image_id: nil).select(:image_id))) } + scope("Orphan") { |scope| scope.where.not(id: SoftwareImage.select(:image_id)).where.not(id: Member.where.not(image_id: nil).select(:image_id)) } + + batch_action :delete_orphans, confirm: "Delete all selected orphan images and their files?" do |ids| + in_use_ids = SoftwareImage.where(image_id: ids).pluck(:image_id) + Member.where(image_id: ids).pluck(:image_id) + orphan_ids = ids.map(&:to_i) - in_use_ids + Image.where(id: orphan_ids).find_each do |img| + File.delete(img.file_path) if File.exist?(img.file_path) + img.destroy + end + redirect_to admin_images_path, notice: "Deleted #{orphan_ids.size} orphan image(s)." + end + index do selectable_column id_column @@ -13,6 +27,12 @@ ActiveAdmin.register Image do image_tag("/api/image/#{img.id}", style: "max-height:60px;max-width:120px;object-fit:contain;") end end + column(:usage) do |img| + uses = [] + uses << "#{img.software_images.size} software(s)" if img.software_images.any? + uses << "member" if Member.where(image_id: img.id).exists? + uses.any? ? uses.join(", ") : status_tag("orphan", class: "warning") + end column :created_at actions end @@ -44,4 +64,10 @@ ActiveAdmin.register Image do end f.actions end + + controller do + def scoped_collection + super.includes(:software_images) + end + end end diff --git a/apps/api/app/admin/members.rb b/apps/api/app/admin/members.rb index 51a9a48..6c21480 100644 --- a/apps/api/app/admin/members.rb +++ b/apps/api/app/admin/members.rb @@ -3,17 +3,18 @@ ActiveAdmin.register Member do menu priority: 4 + actions :all, except: [:edit] + index do selectable_column id_column column :nick do |m| - link_to m.nick, edit_admin_member_path(m) + link_to m.nick, admin_member_path(m) end column :real_nick column :motto do |m| truncate m.motto, length: 60 end - column :avatar_filename column(:image) do |m| if m.image && File.exist?(m.image.file_path) image_tag "/api/image/#{m.image.id}", style: "max-height:40px;max-width:80px;object-fit:contain;" @@ -33,26 +34,27 @@ ActiveAdmin.register Member do f.input :real_nick f.input :motto f.input :avatar_filename, - hint: "Fallback image filename (e.g. mr.zero.png) — only used when no image is selected above." + hint: "Fallback image filename (e.g. mr.zero.png) — only used when no image is selected." + + img_hint = if resource.image_id.present? && resource.image + f.template.image_tag("/api/image/#{resource.image_id}", style: "max-height:80px;max-width:160px;object-fit:contain;margin-top:6px;").html_safe + end f.input :image_id, as: :select, label: "Image", - collection: Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] }, - include_blank: "— no image (use avatar_filename) —" + collection: Image.order(:original_filename).map { |img| [img.original_filename, img.id] }, + include_blank: "— no image (use avatar_filename) —", + hint: img_hint end f.actions end end - form do |f| - f.inputs do - f.input :nick - f.input :real_nick - f.input :motto - f.input :avatar_filename, - hint: "Fallback image filename (e.g. mr.zero.png) — only used when no image is selected above." - f.input :image_id, as: :select, label: "Image", - collection: Image.order(:original_filename).map { |img| [ img.original_filename, img.id ] }, - include_blank: "— no image (use avatar_filename) —" + controller do + def scoped_collection + super.includes(:image) + end + + def find_resource + scoped_collection.find(params[:id]) end - f.actions end end diff --git a/apps/api/app/admin/softwares.rb b/apps/api/app/admin/softwares.rb index f8d9d7e..838facb 100644 --- a/apps/api/app/admin/softwares.rb +++ b/apps/api/app/admin/softwares.rb @@ -9,6 +9,8 @@ ActiveAdmin.register Software do actions :all, except: [:edit] + config.sort_order = 'title_asc' + index do selectable_column id_column @@ -21,6 +23,7 @@ ActiveAdmin.register Software do status_tag sw.status end column :highlighted + column(:releases) { |sw| sw.releases.size } column(:image) do |sw| si = sw.software_images.detect(&:is_default?) || sw.software_images.first if si&.image && File.exist?(si.image.file_path) @@ -39,7 +42,7 @@ ActiveAdmin.register Software do filter :highlighted show title: proc { |sw| sw.title } do - active_admin_form_for [ :admin, resource ], url: admin_software_path(resource), html: { method: :put } do |f| + active_admin_form_for [ :admin, resource ], url: admin_software_path(resource), html: { method: :put, multipart: true } do |f| f.inputs "Details" do f.input :name f.input :title @@ -91,7 +94,7 @@ ActiveAdmin.register Software do controller do def scoped_collection - super.includes(software_images: :image) + super.includes(:releases, software_images: :image) end def find_resource diff --git a/apps/api/app/assets/javascripts/active_admin.js b/apps/api/app/assets/javascripts/active_admin.js index 7a0aac6..0c3ca1e 100644 --- a/apps/api/app/assets/javascripts/active_admin.js +++ b/apps/api/app/assets/javascripts/active_admin.js @@ -101,10 +101,11 @@ } html += ''; - // Upload bar - html += '