Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/javascript/controllers/better_together/uploads_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["search", "sort", "list", "item"]

filter() {
const query = this.searchTarget.value.toLowerCase()
this.itemTargets.forEach((item) => {
const name = item.dataset.name.toLowerCase()
item.classList.toggle("d-none", !name.includes(query))
})
}

sort() {
const key = this.sortTarget.value
const items = this.itemTargets.slice().sort((a, b) => {
if (key === "name") {
return a.dataset.name.localeCompare(b.dataset.name)
}
if (key === "created_at") {
return new Date(b.dataset.createdAt) - new Date(a.dataset.createdAt)
}
return 0
})
items.forEach((item) => this.listTarget.appendChild(item))
}

copy(event) {
const url = event.currentTarget.dataset.url
navigator.clipboard?.writeText(url)
}

insert(event) {
const signedId = event.currentTarget.dataset.signedId
this.dispatch("insert", { detail: { signedId } })
}
}
43 changes: 41 additions & 2 deletions app/views/better_together/uploads/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,2 +1,41 @@
<h1>Files#index</h1>
<p>Find me in app/views/better_together/files/index.html.erb</p>
<% content_for :page_title do %>
<%= BetterTogether::Upload.model_name.human.pluralize %>
<% end %>

<div class="container mt-4" data-controller="better_together--uploads">
<div class="row mb-3">
<div class="col-sm">
<input type="search" class="form-control" placeholder="Search uploads" data-better_together--uploads-target="search" data-action="input->better_together--uploads#filter">
</div>
<div class="col-sm-auto">
<select class="form-select" data-better_together--uploads-target="sort" data-action="change->better_together--uploads#sort">
<option value="created_at">Newest</option>
<option value="name">Name</option>
</select>
</div>
</div>

<div class="row g-3" data-better_together--uploads-target="list">
<% @uploads.each do |upload| %>
<div class="col-md-3" data-better_together--uploads-target="item" data-name="<%= upload.name.to_s %>" data-created-at="<%= upload.created_at.iso8601 %>">
<div class="card h-100">
<% if upload.file.attached? %>
<%= image_tag upload.file.variant(resize_to_limit: [200, 200]), class: "card-img-top", alt: upload.name %>
<% end %>
<div class="card-body d-flex flex-column">
<h6 class="card-title text-truncate"><%= upload.name %></h6>
<ul class="list-unstyled small mb-3">
<li><strong>Filename:</strong> <%= upload.filename %></li>
<li><strong>Size:</strong> <%= number_to_human_size(upload.byte_size) %></li>
<li><strong>Type:</strong> <%= upload.content_type %></li>
</ul>
<div class="mt-auto btn-group">
<button class="btn btn-sm btn-outline-secondary" data-action="better_together--uploads#copy" data-url="<%= url_for(upload.file) %>">Copy URL</button>
<button class="btn btn-sm btn-primary" data-action="better_together--uploads#insert" data-signed-id="<%= upload.file.blob.signed_id %>">Insert</button>
</div>
</div>
</div>
</div>
<% end %>
</div>
</div>
47 changes: 47 additions & 0 deletions spec/features/uploads/gallery_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'uploads gallery', type: :feature, js: true do # rubocop:disable Metrics/BlockLength
include BetterTogether::DeviseSessionHelpers

before do
configure_host_platform
login_as_platform_manager
@creator = BetterTogether::User.find_by(email: '[email protected]').person
end

def create_upload(name, creator:, created_at: Time.current)
create(:better_together_upload, name:, creator:, created_at:).tap do |upload|
upload.file.attach(io: StringIO.new('stub'), filename: "#{name}.txt", content_type: 'text/plain')
end
end

scenario 'searches, sorts, and copies upload urls' do
create_upload('Alpha', creator: @creator, created_at: 2.days.ago)
create_upload('Beta', creator: @creator, created_at: 1.day.ago)

visit file_index_path(locale: I18n.default_locale)

expect(page.all('[data-better_together--uploads-target="item"] .card-title').map(&:text))
.to eq(%w[Beta Alpha])

fill_in placeholder: 'Search uploads', with: 'Al'
expect(page).to have_selector('[data-name="Alpha"]', visible: true)
expect(page).to have_selector('[data-name="Beta"].d-none', visible: :all)

find('select[data-better_together--uploads-target="sort"]').select('Name')
expect(page.all('[data-better_together--uploads-target="item"] .card-title').map(&:text))
.to eq(%w[Alpha Beta])

copy_button = find('button', text: 'Copy URL', match: :first)
page.execute_script <<~JS
window.copiedText = null;
Object.defineProperty(navigator, "clipboard", {
value: { writeText: function(t){ window.copiedText = t } }
});
JS
copy_button.click
expect(page.evaluate_script('window.copiedText')).to eq(copy_button['data-url'])
end
end
5 changes: 4 additions & 1 deletion spec/support/capybara.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
)
# Generate a unique temporary directory for each session to avoid conflicts
options.add_argument("--user-data-dir=#{Dir.mktmpdir}")
options.binary = '/usr/bin/chromium-browser'
service = Selenium::WebDriver::Service.chrome(path: '/usr/bin/chromedriver')

Capybara::Selenium::Driver.new(
app,
browser: :chrome,
options: options
options: options,
service: service
)
end

Expand Down
Loading