diff --git a/Gemfile b/Gemfile
index c72bd8326..9296044c0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -71,7 +71,7 @@ group :test do
end
require_relative "lib/bootstrap"
-unless Bootstrap.local_authentication?
+unless Bootstrap.oss_config?
eval_gemfile "gems/fizzy-saas/Gemfile"
gem "fizzy-saas", path: "gems/fizzy-saas"
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 91da8a5b6..16dca130d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -359,7 +359,7 @@ GEM
logger (~> 1.6)
letter_opener (1.10.0)
launchy (>= 2.2, < 4)
- lexxy (0.1.9.beta)
+ lexxy (0.1.10.beta)
rails (>= 8.0.2)
lint_roller (1.1.0)
logger (1.7.0)
diff --git a/app/assets/images/collection.svg b/app/assets/images/collection.svg
index 5d6249839..cdbe7d4da 100644
--- a/app/assets/images/collection.svg
+++ b/app/assets/images/collection.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/assets/stylesheets/card-columns.css b/app/assets/stylesheets/card-columns.css
index f4ff6ac05..1a50f110f 100644
--- a/app/assets/stylesheets/card-columns.css
+++ b/app/assets/stylesheets/card-columns.css
@@ -73,10 +73,6 @@
z-index: 3;
}
- &:not(.cards--considering, .is-collapsed, .cards--grid) {
- overflow: clip;
- }
-
&.is-collapsed {
border-radius: calc(var(--column-width-collapsed) / 2);
flex: 0 0 var(--column-width-collapsed);
diff --git a/app/assets/stylesheets/events.css b/app/assets/stylesheets/events.css
index 28d6b7c80..42d129125 100644
--- a/app/assets/stylesheets/events.css
+++ b/app/assets/stylesheets/events.css
@@ -97,6 +97,17 @@
position: absolute;
}
+ .events__filter-select {
+ font-weight: inherit;
+ text-decoration: underline;
+
+ @media (any-hover: hover) {
+ &:hover {
+ --btn-color: var(--color-link);
+ }
+ }
+ }
+
.events__day {
position: relative;
diff --git a/app/assets/stylesheets/lexxy.css b/app/assets/stylesheets/lexxy.css
index affd21fef..63f5f1f14 100644
--- a/app/assets/stylesheets/lexxy.css
+++ b/app/assets/stylesheets/lexxy.css
@@ -31,12 +31,6 @@
position: absolute;
white-space: pre-line;
}
-
- /* Disable the submit button when Lexical is empty */
- + .comment__submit {
- opacity: 0.5;
- pointer-events: none;
- }
}
}
diff --git a/app/assets/stylesheets/rich-text-content.css b/app/assets/stylesheets/rich-text-content.css
index 18641da1a..873ad8cd9 100644
--- a/app/assets/stylesheets/rich-text-content.css
+++ b/app/assets/stylesheets/rich-text-content.css
@@ -248,7 +248,7 @@
}
.attachment--file {
- --attachment-icon-color: var(--lexxy-color-text-subtle);
+ --attachment-icon-color: var(--color-ink-medium);
align-items: center;
display: flex;
@@ -266,6 +266,15 @@
color: var(--color-ink);
font-weight: bold;
}
+
+ /* Video attachments don't have an identifiable class, but we need to
+ * make sure the caption is always below the video */
+ &:has(video) {
+ .attachment__caption {
+ flex: none;
+ inline-size: 100%;
+ }
+ }
}
.attachment--psd,
diff --git a/app/controllers/cards_controller.rb b/app/controllers/cards_controller.rb
index 809428f91..526806879 100644
--- a/app/controllers/cards_controller.rb
+++ b/app/controllers/cards_controller.rb
@@ -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
diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb
index 89871a9f5..2ede3c108 100644
--- a/app/controllers/concerns/authentication.rb
+++ b/app/controllers/concerns/authentication.rb
@@ -37,7 +37,9 @@ module Authentication
end
def require_tenant
- ApplicationRecord.current_tenant.present? || request_authentication
+ unless ApplicationRecord.current_tenant.present?
+ render "sessions/login_menu"
+ end
end
def require_authentication
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index d066632bd..11b793b17 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -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
diff --git a/app/helpers/accesses_helper.rb b/app/helpers/accesses_helper.rb
index 8e3dee6a3..c446dc5a2 100644
--- a/app/helpers/accesses_helper.rb
+++ b/app/helpers/accesses_helper.rb
@@ -50,7 +50,7 @@ module AccessesHelper
collection_involvement_path(collection),
method: :put,
aria: { labelledby: involvement_label_id },
- class: "btn",
+ class: class_names("btn", { "btn--reversed": access.involvement == "watching" && icon_only }),
params: { show_watchers: show_watchers, involvement: next_involvement(access.involvement), icon_only: icon_only }
) do
safe_join([
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 0eecdb25f..9200f84b7 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -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)
diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb
index 8f2fc7988..6c67400c7 100644
--- a/app/helpers/pagination_helper.rb
+++ b/app/helpers/pagination_helper.rb
@@ -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),
+ class: "txt-reversed", 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)
diff --git a/app/javascript/controllers/collapsible_columns_controller.js b/app/javascript/controllers/collapsible_columns_controller.js
index 84ef0d315..5002c46e2 100644
--- a/app/javascript/controllers/collapsible_columns_controller.js
+++ b/app/javascript/controllers/collapsible_columns_controller.js
@@ -14,7 +14,7 @@ export default class extends Controller {
}
preventToggle(event) {
- if (event.detail.attributeName === "class") {
+ if (event.target.hasAttribute("data-collapsible-columns-target") && event.detail.attributeName === "class") {
event.preventDefault()
}
}
diff --git a/app/javascript/controllers/filter_settings_controller.js b/app/javascript/controllers/filter_settings_controller.js
index 7a207da80..6be549e5c 100644
--- a/app/javascript/controllers/filter_settings_controller.js
+++ b/app/javascript/controllers/filter_settings_controller.js
@@ -5,7 +5,7 @@ import { post } from "@rails/request.js"
export default class extends Controller {
static classes = ["filtersSet"]
static targets = ["field", "form"]
- static values = { refreshUrl: String, noFilteringUrl: String }
+ static values = { refreshUrl: String, noFilteringUrl: String, cardsUrl: String }
initialize() {
this.debouncedToggle = debounce(this.#toggle.bind(this), 50)
@@ -31,6 +31,12 @@ export default class extends Controller {
this.debouncedToggle()
}
+ submitToGenericCardsView() {
+ this.formTarget.action = this.cardsUrlValue
+ this.formTarget.dataset.turboFrame = "top"
+ this.formTarget.requestSubmit()
+ }
+
#toggle() {
this.element.classList.toggle(this.filtersSetClass, this.#hasFiltersSet)
}
diff --git a/app/javascript/controllers/form_controller.js b/app/javascript/controllers/form_controller.js
index 4e59f6055..2b30c99b9 100644
--- a/app/javascript/controllers/form_controller.js
+++ b/app/javascript/controllers/form_controller.js
@@ -1,8 +1,8 @@
import { Controller } from "@hotwired/stimulus"
-import { debounce } from "helpers/timing_helpers";
+import { debounce, nextFrame } from "helpers/timing_helpers";
export default class extends Controller {
- static targets = [ "cancel" ]
+ static targets = [ "cancel", "submit" ]
static values = {
debounceTimeout: { type: Number, default: 300 }
@@ -37,6 +37,16 @@ export default class extends Controller {
event.preventDefault()
}
+ async disableSubmitWhenInvalid(event) {
+ await nextFrame()
+
+ if (this.element.checkValidity()) {
+ this.submitTarget.removeAttribute("disabled")
+ } else {
+ this.submitTarget.toggleAttribute("disabled", true)
+ }
+ }
+
select(event) {
event.target.select()
}
diff --git a/app/javascript/controllers/multi_selection_combobox_controller.js b/app/javascript/controllers/multi_selection_combobox_controller.js
index 70a853b2b..80d7f0826 100644
--- a/app/javascript/controllers/multi_selection_combobox_controller.js
+++ b/app/javascript/controllers/multi_selection_combobox_controller.js
@@ -82,15 +82,14 @@ export default class extends Controller {
#clearHiddenFields() {
this.element.querySelectorAll('input[type="hidden"]').forEach(field => {
- if (field !== this.hiddenField) {
- field.remove()
- }
+ field.remove()
})
}
#addHiddenFields() {
this.#selectedValues().forEach(value => {
- const [field] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
+ const [ field ] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
+ field.removeAttribute("id")
field.value = value
this.element.appendChild(field)
})
diff --git a/app/models/account.rb b/app/models/account.rb
index 950c0a124..c29f61005 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -4,7 +4,7 @@ class Account < ApplicationRecord
has_many_attached :uploads
def slug
- "/#{tenant_id}"
+ "/#{tenant}"
end
def setup_basic_template
diff --git a/app/models/card.rb b/app/models/card.rb
index 9175d6b96..c837c781a 100644
--- a/app/models/card.rb
+++ b/app/models/card.rb
@@ -22,7 +22,6 @@ class Card < ApplicationRecord
case index
when "stalled" then stalled
when "postponing_soon" then postponing_soon
- when "falling_back_soon" then falling_back_soon
when "closed" then closed.recently_closed_first
when "golden" then golden
when "draft" then drafted
diff --git a/app/models/filter/fields.rb b/app/models/filter/fields.rb
index fc11752fc..027ae8ac6 100644
--- a/app/models/filter/fields.rb
+++ b/app/models/filter/fields.rb
@@ -1,7 +1,7 @@
module Filter::Fields
extend ActiveSupport::Concern
- INDEXES = %w[ all stalled postponing_soon falling_back_soon golden draft ]
+ INDEXES = %w[ all stalled postponing_soon golden draft ]
SORTED_BY = %w[ newest oldest latest ]
delegate :default_value?, to: :class
diff --git a/app/models/user/filtering.rb b/app/models/user/filtering.rb
index 9f321bbed..6e00ecbc1 100644
--- a/app/models/user/filtering.rb
+++ b/app/models/user/filtering.rb
@@ -67,6 +67,10 @@ class User::Filtering
filter.closers.any?
end
+ def show_collections?
+ filter.collections.any?
+ end
+
def enable_collection_filtering(&block)
@collection_filtering_route_resolver = block
end
diff --git a/app/views/cards/comments/_new.html.erb b/app/views/cards/comments/_new.html.erb
index 7931cd244..015c93a83 100644
--- a/app/views/cards/comments/_new.html.erb
+++ b/app/views/cards/comments/_new.html.erb
@@ -10,10 +10,10 @@
local_save_key_value: "comment-#{card.id}",
action: "turbo:submit-end->local-save#submit keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop" } do |form| %>
<%= form.rich_textarea :body, required: true, placeholder: new_comment_placeholder(card),
- data: { local_save_target: "input", action: "lexxy:change->local-save#save turbo:morph-element->local-save#restoreContent" } do %>
+ data: { local_save_target: "input", action: "lexxy:change->form#disableSubmitWhenInvalid lexxy:change->local-save#save turbo:morph-element->local-save#restoreContent" } do %>
<%= general_prompts(@card.collection) %>
<% end %>
- <%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start" do %>
+ <%= form.button class: "comment__submit btn btn--reversed flex-item-justify-start", data: { form_target: "submit" }, disabled: true do %>
Post this comment
<% end %>
diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb
index 3f3b4b139..ce8f3d026 100644
--- a/app/views/cards/display/_preview.html.erb
+++ b/app/views/cards/display/_preview.html.erb
@@ -27,7 +27,7 @@
diff --git a/app/views/cards/index.html.erb b/app/views/cards/index.html.erb
index 1e457c452..47d15dcb8 100644
--- a/app/views/cards/index.html.erb
+++ b/app/views/cards/index.html.erb
@@ -27,6 +27,8 @@
<%= turbo_frame_tag :cards_container do %>