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 %> +
+ <%= link_to events_path, class: "btn btn--back", data: { controller: "hotkey", action: "keydown.left@document->hotkey#click" } do %> + + <%= icon_tag "arrow-left" %> + Back to Actvity + + + <% end %> +
+ +

+ <%= @column.title %> +

+<% 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