diff --git a/app/assets/stylesheets/events.css b/app/assets/stylesheets/events.css
index 20fb53217..1dbdf0997 100644
--- a/app/assets/stylesheets/events.css
+++ b/app/assets/stylesheets/events.css
@@ -19,6 +19,33 @@
--events-day-header-height: 1.75rem;
}
+ .events--grid {
+ --events-grid-gap: 1rem;
+ --events-grid-columns: 1;
+
+ container-type: inline-size;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: var(--events-grid-gap);
+ justify-content: center;
+ margin: var(--block-space) auto;
+ max-inline-size: var(--main-width);
+
+ @media (min-width: 640px) {
+ --events-grid-columns: 2;
+ }
+
+ @media (min-width: 960px) {
+ --events-grid-columns: 3;
+ }
+
+ .event {
+ inline-size: calc((100% - var(--events-grid-gap) * (var(--events-grid-columns) - 1) ) / var(--events-grid-columns)) !important;
+ margin: 0 !important;
+ }
+ }
+
.events__activity-summary {
border: solid var(--color-ink-lighter);
border-width: 1px 1px 0 1px;
@@ -206,6 +233,23 @@
padding: var(--block-space-half) var(--inline-space);
}
+ .events__maximize-button {
+ inset: calc(var(--events-gap) * 3) 0 auto auto;
+ outline-offset: -2px;
+ position: absolute;
+ transform: translateY(-10%);
+ z-index: 1;
+
+ @media (any-hover: hover ) {
+ opacity: 0;
+
+ .events__column-header:hover &,
+ &:focus-visible {
+ opacity: 1;
+ }
+ }
+ }
+
.events__time-block {
align-content: end;
display: grid;
diff --git a/app/controllers/events/day_timeline/columns_controller.rb b/app/controllers/events/day_timeline/columns_controller.rb
new file mode 100644
index 000000000..db30c44d1
--- /dev/null
+++ b/app/controllers/events/day_timeline/columns_controller.rb
@@ -0,0 +1,21 @@
+class Events::DayTimeline::ColumnsController < ApplicationController
+ include DayTimelinesScoped
+
+ before_action :ensure_valid_column
+ before_action :set_column
+
+ def show
+ fresh_when @day_timeline
+ end
+
+ private
+ VALID_COLUMNS = %w[ added updated closed ]
+
+ def ensure_valid_column
+ head :not_found unless VALID_COLUMNS.include?(params[:id])
+ end
+
+ def set_column
+ @column = @day_timeline.public_send("#{params[:id]}_column")
+ end
+end
diff --git a/app/models/user/day_timeline/column.rb b/app/models/user/day_timeline/column.rb
index fe42c68dc..0331a83ff 100644
--- a/app/models/user/day_timeline/column.rb
+++ b/app/models/user/day_timeline/column.rb
@@ -1,7 +1,7 @@
class User::DayTimeline::Column
include ActionView::Helpers::TagHelper, ActionView::Helpers::OutputSafetyHelper, TimeHelper
- attr_reader :index
+ attr_reader :index, :base_title, :day_timeline, :events
def initialize(day_timeline, base_title, index, events)
@day_timeline = day_timeline
@@ -30,8 +30,6 @@ class User::DayTimeline::Column
end
private
- attr_reader :base_title, :day_timeline, :events
-
def limited_events
@limited_events ||= events.limit(100).load
end
diff --git a/app/views/events/day_timeline/_column.html.erb b/app/views/events/day_timeline/_column.html.erb
index 6e036a412..23bf7e34e 100644
--- a/app/views/events/day_timeline/_column.html.erb
+++ b/app/views/events/day_timeline/_column.html.erb
@@ -1,5 +1,14 @@
-
<%= column.title %>
+
+ <%= column.title %>
+
+ <% if column.events_by_hour.any? %>
+ <%= link_to events_day_timeline_column_path(id: column.base_title.downcase, day: column.day_timeline.day.to_date), class: "events__maximize-button btn btn--circle txt-x-small borderless", data: { turbo_frame: "_top" } do %>
+ <%= icon_tag "grid", class: "translucent" %>
+ Expand column
+ <% end %>
+ <% end %>
+
<% column.events_by_hour.each do |hour, events| %>
<%= events_at_hour_container(column, hour) do %>
<%= render partial: "events/event", collection: events, cached: true %>
diff --git a/app/views/events/day_timeline/columns/_events.html.erb b/app/views/events/day_timeline/columns/_events.html.erb
new file mode 100644
index 000000000..ac14102af
--- /dev/null
+++ b/app/views/events/day_timeline/columns/_events.html.erb
@@ -0,0 +1,7 @@
+
+ <% column.events_by_hour.each do |hour, events| %>
+ <% if events.any? %>
+ <%= render partial: "events/event", collection: events, cached: true %>
+ <% end %>
+ <% end %>
+
diff --git a/app/views/events/day_timeline/columns/show.html.erb b/app/views/events/day_timeline/columns/show.html.erb
new file mode 100644
index 000000000..3ef8e09e2
--- /dev/null
+++ b/app/views/events/day_timeline/columns/show.html.erb
@@ -0,0 +1,19 @@
+<% @page_title = @column.base_title %>
+
+<% content_for :header do %>
+
+
+
+<% end %>
+
+<%= render "events/day_timeline/columns/events", column: @column %>
\ No newline at end of file
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
index 6c2eb7f67..d51b4a4f3 100644
--- a/config/brakeman.ignore
+++ b/config/brakeman.ignore
@@ -1,5 +1,28 @@
{
"ignored_warnings": [
+ {
+ "warning_type": "Dangerous Send",
+ "warning_code": 23,
+ "fingerprint": "746ab8227e04231f0002e099e2f670bcc2b8927af85cdc69fab1440002d5c2a6",
+ "check_name": "Send",
+ "message": "User controlled method execution",
+ "file": "app/controllers/events/day_timeline/columns_controller.rb",
+ "line": 19,
+ "link": "https://brakemanscanner.org/docs/warning_types/dangerous_send/",
+ "code": "Current.user.timeline_for(day, :filter => ((Current.user.filters.find(params[:filter_id]) or Current.user.filters.from_params(filter_params)))).public_send(\"#{params[:id]}_column\")",
+ "render_path": null,
+ "location": {
+ "type": "method",
+ "class": "Events::DayTimeline::ColumnsController",
+ "method": "set_column"
+ },
+ "user_input": "params[:id]",
+ "confidence": "High",
+ "cwe_id": [
+ 77
+ ],
+ "note": ""
+ },
{
"warning_type": "Mass Assignment",
"warning_code": 70,
@@ -47,5 +70,5 @@
"note": ""
}
],
- "brakeman_version": "7.1.1"
+ "brakeman_version": "7.1.0"
}
diff --git a/config/routes.rb b/config/routes.rb
index 1fd25a50e..73acfa75e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -130,6 +130,9 @@ Rails.application.routes.draw do
resources :events, only: :index
namespace :events do
resources :days
+ namespace :day_timeline do
+ resources :columns, only: :show
+ end
end
resources :qr_codes
diff --git a/test/controllers/events/day_timeline/columns_controller_test.rb b/test/controllers/events/day_timeline/columns_controller_test.rb
new file mode 100644
index 000000000..9ee459cbd
--- /dev/null
+++ b/test/controllers/events/day_timeline/columns_controller_test.rb
@@ -0,0 +1,30 @@
+require "test_helper"
+
+class Events::DayTimeline::ColumnsControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ sign_in_as :kevin
+ end
+
+ test "show added column" do
+ get events_day_timeline_column_path("added")
+ assert_response :success
+ assert_select "h1", text: /Added/
+ end
+
+ test "show updated column" do
+ get events_day_timeline_column_path("updated")
+ assert_response :success
+ assert_select "h1", text: /Updated/
+ end
+
+ test "show closed column" do
+ get events_day_timeline_column_path("closed")
+ assert_response :success
+ assert_select "h1", text: /Closed/
+ end
+
+ test "show returns not found for invalid column" do
+ get events_day_timeline_column_path("invalid")
+ assert_response :not_found
+ end
+end