Merge pull request #1214 from basecamp/live-updates

Live updates
This commit is contained in:
Jorge Manrubia
2025-10-02 16:12:19 +02:00
committed by GitHub
14 changed files with 79 additions and 33 deletions
+11 -1
View File
@@ -27,7 +27,9 @@ class CardsController < ApplicationController
end
def update
@card.update! card_params
suppressing_broadcasts_unless_published(@card) do
@card.update! card_params
end
if @card.published?
render_card_replacement
@@ -50,6 +52,14 @@ class CardsController < ApplicationController
@card = Current.user.accessible_cards.find params[:id]
end
def suppressing_broadcasts_unless_published(card, &block)
if card.published?
yield
else
Collection.suppressing_turbo_broadcasts(&block)
end
end
def card_params
params.expect(card: [ :status, :title, :description, :image, tag_ids: [] ])
end
+9 -1
View File
@@ -24,7 +24,7 @@ class UsersController < ApplicationController
def show
@filter = Current.user.filters.new(creator_ids: [ @user.id ])
@day_timeline = Current.user.timeline_for(Time.current, filter: @filter)
@day_timeline = Current.user.timeline_for(day_param, filter: @filter)
end
def update
@@ -50,6 +50,14 @@ class UsersController < ApplicationController
head :forbidden unless Current.user.can_change?(@user)
end
def day_param
if params[:day].present?
Time.zone.parse(params[:day])
else
Time.current
end
end
def user_params
params.expect(user: [ :name, :email_address, :password, :avatar ])
end
-11
View File
@@ -52,17 +52,6 @@ module EventsHelper
tag.div class: "events__time-block", style: "grid-area: #{row}/#{col}", &
end
def event_next_page_link(next_day)
if next_day
tag.div id: "next_page",
data: { controller: "fetch-on-visible",
fetch_on_visible_url_value: events_days_path(
day: next_day.strftime("%Y-%m-%d"),
**@filter.as_params
) }
end
end
def event_action_sentence(event)
if event.action.comment_created?
comment_event_action_sentence(event)
+24
View File
@@ -35,6 +35,30 @@ module PaginationHelper
end
end
def with_automatic_pagination(name, page, **properties)
pagination_list name, paginate_on_scroll: true, **properties do
concat(pagination_frame_tag(name, page) do
yield
concat link_to_next_page(name, page, activate_when_observed: true)
end)
end
end
def day_timeline_pagination_frame_tag(day_timeline, &)
turbo_frame_tag day_timeline_pagination_frame_id_for(day_timeline.day), data: { timeline_target: "frame" }, role: "presentation", refresh: :morph, &
end
def day_timeline_pagination_frame_id_for(day)
"day-timeline-pagination-contents-#{day.strftime("%Y-%m-%d")}"
end
def day_timeline_pagination_link(day_timeline, filter)
if day_timeline.next_day
link_to "Load more...", events_days_path(day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" }
end
end
private
def pagination_list(name, tag_element: :div, paginate_on_scroll: false, **properties, &block)
classes = properties.delete(:class)
+3 -1
View File
@@ -27,6 +27,8 @@
<%= turbo_frame_tag :cards_container do %>
<section class="cards cards--grid">
<%= render partial: "cards/display/preview", collection: @page.records, as: :card, locals: { draggable: true }, cached: ->(card) { cacheable_preview_parts_for(card) } %>
<%= with_automatic_pagination :cards_paginated_container, @page do %>
<%= render partial: "cards/display/preview", collection: @page.records, as: :card, locals: { draggable: true }, cached: ->(card) { cacheable_preview_parts_for(card) } %>
<% end %>
</section>
<% end %>
+2
View File
@@ -1,6 +1,8 @@
<% @page_title = @collection.name %>
<% turbo_exempts_page_from_cache %>
<%= turbo_stream_from @collection %>
<% content_for :head do %>
<%= tag.meta property: "og:title", content: @page_title %>
<%= tag.meta property: "og:description", content: Account.sole.name %>
+4
View File
@@ -0,0 +1,4 @@
<%= day_timeline_pagination_frame_tag @day_timeline do %>
<%= render "events/day", day_timeline: @day_timeline %>
<%= day_timeline_pagination_link(@day_timeline, @filter) %>
<% end %>
@@ -1,7 +0,0 @@
<%= turbo_stream.append :activity do %>
<%= render "events/day", day_timeline: @day_timeline %>
<% end %>
<%= turbo_stream.replace :next_page do %>
<%= event_next_page_link(@day_timeline.next_day) %>
<% end %>
+1 -1
View File
@@ -1,6 +1,6 @@
<%= link_to event.notifiable_target,
class: "event event--#{ event.action } #{ "golden-effect" if event.card.golden? } center-block flex flex-column full-width align-start justify-start position-relative",
style: "--card-color: #{ card.closed? ? "var(--color-card-complete)" : card.color };",
style: "--card-color: #{ card.closed? ? "var(--color-card-complete)" : card.color };", target: "_top",
data: { related_element_target: "related",
related_element_group_value: card.id,
action: "mouseover->related-element#highlight mouseout->related-element#unhighlight" } do %>
+8 -5
View File
@@ -1,7 +1,7 @@
<% @page_title = "Home" %>
<% @header_class = "header--events" %>
<%= turbo_stream_from :activity_summaries %>
<%= render "filters/broadcasts", filter: @filter %>
<% content_for :header do %>
<%= render "filters/menu", user_filtering: @user_filtering %>
@@ -14,7 +14,10 @@
</h1>
<% end %>
<div class="events" id="activity">
<%= render "events/day", day_timeline: @day_timeline %>
</div>
<%= event_next_page_link(@day_timeline.next_day) %>
<%= tag.div id: "activity", class: "events", data: { controller: "pagination", pagination_paginate_on_intersection_value: true } do %>
<%= day_timeline_pagination_frame_tag @day_timeline do %>
<%= render "events/day", day_timeline: @day_timeline %>
<%= day_timeline_pagination_link(@day_timeline, @filter) %>
<% end %>
<% end %>
+1 -1
View File
@@ -1,4 +1,4 @@
<nav data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
<nav data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" data-turbo-permanent>
<%= render "filters/menu/button" %>
<%= tag.dialog class: "fizzy-menu filter popup popup--animated panel margin-block-start-half",
+2 -1
View File
@@ -1,11 +1,12 @@
<% cache user_filtering do %>
<%= tag.aside id: "filter-settings",
<%= tag.aside \
class: class_names("filters flex align-center gap-half justify-center center margin-block-end", { "filters--expanded": user_filtering.expanded? }),
data: {
controller: "toggle-class filter-settings",
toggle_class_toggle_class: "filters--expanded",
filter_settings_filters_set_class: "filters--has-filters-set",
filter_settings_no_filtering_url_value: no_filtering_url,
turbo_permanent: true,
filter_settings_refresh_url_value: settings_refresh_path } do %>
<%= form_with url: filter_url, method: :get, class: "", data: {
controller: "form",
@@ -0,0 +1,13 @@
<div class="events margin-block-double" id="activity" data-controller="pagination" data-pagination-paginate-on-intersection-value="true">
<%= day_timeline_pagination_frame_tag day_timeline do %>
<%= render "events/day", day_timeline: day_timeline %>
<% if day_timeline.next_day %>
<%= link_to "Load more...", user_path(user, day: day_timeline.next_day.strftime("%Y-%m-%d"), **filter.as_params),
data: { frame: day_timeline_pagination_frame_id_for(day_timeline.next_day), pagination_target: "paginationLink" } %>
<% end %>
<% end %>
</div>
+1 -4
View File
@@ -50,7 +50,4 @@
<h1 class="font-weight-black txt-large margin-block-double"><%= "What #{ Current.user == @user ? "have you" : "has #{ @user.first_name }" } been up to?" %></h1>
<div class="events margin-block-double" id="activity">
<%= render "events/day", day_timeline: @day_timeline %>
</div>
<%= event_next_page_link(@day_timeline.next_day) %>
<%= render "users/activity_timeline", user: @user, day_timeline: @day_timeline, filter: @filter %>