Merge branch 'main' into lexical
* main: Don't choke when rendering commands where the card was deleted Update tests Rework system events test: add missing assertions dep: bump active_record-tenanted to fix URI support Remove hyphen from "Un-do" Prevent default when handling keyboard shortcuts dep: update AR::Tenanted to support database URIs Detect platform and label the correct hotkey shortcut Things got too tight Don't require TLS for Beamer at the moment dep: update dependencies # Conflicts: # Gemfile # Gemfile.lock # app/assets/stylesheets/comments.css
This commit is contained in:
@@ -29,6 +29,7 @@ gem "rouge"
|
|||||||
gem "jbuilder"
|
gem "jbuilder"
|
||||||
gem "actiontext-lexical", github: "basecamp/actiontext-lexical"
|
gem "actiontext-lexical", github: "basecamp/actiontext-lexical"
|
||||||
gem "image_processing", "~> 1.14"
|
gem "image_processing", "~> 1.14"
|
||||||
|
gem "platform_agent"
|
||||||
|
|
||||||
# Telemetry and logging
|
# Telemetry and logging
|
||||||
gem "sentry-ruby"
|
gem "sentry-ruby"
|
||||||
|
|||||||
+24
-40
@@ -1,13 +1,6 @@
|
|||||||
GIT
|
|
||||||
remote: https://github.com/basecamp/actiontext-lexical.git
|
|
||||||
revision: 19038b86b8617062adbb930990edaacc1f643e3d
|
|
||||||
specs:
|
|
||||||
actiontext-lexical (0.1.0)
|
|
||||||
rails (>= 8.0.2)
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/basecamp/active_record-tenanted
|
remote: https://github.com/basecamp/active_record-tenanted
|
||||||
revision: 173048c2af29e9a723811e552bc59e3154e82e2a
|
revision: 523947a0f0f49f66a8a62eb93e9ba1a345b3076b
|
||||||
specs:
|
specs:
|
||||||
active_record-tenanted (0.1.0)
|
active_record-tenanted (0.1.0)
|
||||||
activerecord (>= 8.1.alpha)
|
activerecord (>= 8.1.alpha)
|
||||||
@@ -25,21 +18,20 @@ GIT
|
|||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/crmne/ruby_llm.git
|
remote: https://github.com/crmne/ruby_llm.git
|
||||||
revision: 87a86f70cb64e23d5b76994edf8080618f07e071
|
revision: 8412d51e869f1ee8e5229831a9a0bb5e9b8f3847
|
||||||
specs:
|
specs:
|
||||||
ruby_llm (1.3.0rc1)
|
ruby_llm (1.2.0)
|
||||||
base64
|
base64
|
||||||
event_stream_parser (~> 1)
|
event_stream_parser (~> 1)
|
||||||
faraday (>= 1.10.0)
|
faraday (~> 2)
|
||||||
faraday-multipart (>= 1)
|
faraday-multipart (~> 1)
|
||||||
faraday-net_http (>= 1)
|
faraday-net_http (~> 3)
|
||||||
faraday-retry (>= 1)
|
faraday-retry (~> 2)
|
||||||
marcel (~> 1.0)
|
|
||||||
zeitwerk (~> 2)
|
zeitwerk (~> 2)
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/rails/rails.git
|
remote: https://github.com/rails/rails.git
|
||||||
revision: bc7f77b32d7f3f26db654cae506c26a959852506
|
revision: c1d7d56e831acf0aff5f3e27a6b384f543f358d0
|
||||||
branch: main
|
branch: main
|
||||||
specs:
|
specs:
|
||||||
actioncable (8.1.0.alpha)
|
actioncable (8.1.0.alpha)
|
||||||
@@ -73,6 +65,7 @@ GIT
|
|||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
useragent (~> 0.16)
|
useragent (~> 0.16)
|
||||||
actiontext (8.1.0.alpha)
|
actiontext (8.1.0.alpha)
|
||||||
|
action_text-trix (~> 2.1.15)
|
||||||
actionpack (= 8.1.0.alpha)
|
actionpack (= 8.1.0.alpha)
|
||||||
activerecord (= 8.1.0.alpha)
|
activerecord (= 8.1.0.alpha)
|
||||||
activestorage (= 8.1.0.alpha)
|
activestorage (= 8.1.0.alpha)
|
||||||
@@ -139,6 +132,8 @@ GIT
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
action_text-trix (2.1.15)
|
||||||
|
railties
|
||||||
addressable (2.8.7)
|
addressable (2.8.7)
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
@@ -147,7 +142,7 @@ GEM
|
|||||||
bcrypt_pbkdf (1.1.1)
|
bcrypt_pbkdf (1.1.1)
|
||||||
benchmark (0.4.0)
|
benchmark (0.4.0)
|
||||||
bigdecimal (3.1.9)
|
bigdecimal (3.1.9)
|
||||||
bootsnap (1.18.4)
|
bootsnap (1.18.6)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (7.0.2)
|
brakeman (7.0.2)
|
||||||
racc
|
racc
|
||||||
@@ -193,10 +188,6 @@ GEM
|
|||||||
net-http (>= 0.5.0)
|
net-http (>= 0.5.0)
|
||||||
faraday-retry (2.3.1)
|
faraday-retry (2.3.1)
|
||||||
faraday (~> 2.0)
|
faraday (~> 2.0)
|
||||||
ffi (1.17.2)
|
|
||||||
ffi (1.17.2-arm64-darwin)
|
|
||||||
ffi (1.17.2-x86_64-darwin)
|
|
||||||
ffi (1.17.2-x86_64-linux-gnu)
|
|
||||||
fugit (1.11.1)
|
fugit (1.11.1)
|
||||||
et-orbi (~> 1, >= 1.2.11)
|
et-orbi (~> 1, >= 1.2.11)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
@@ -205,12 +196,9 @@ GEM
|
|||||||
addressable (>= 2.5.0)
|
addressable (>= 2.5.0)
|
||||||
globalid (1.2.1)
|
globalid (1.2.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
hashdiff (1.2.0)
|
hashdiff (1.1.2)
|
||||||
i18n (1.14.7)
|
i18n (1.14.7)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
image_processing (1.14.0)
|
|
||||||
mini_magick (>= 4.9.5, < 6)
|
|
||||||
ruby-vips (>= 2.0.17, < 3)
|
|
||||||
importmap-rails (2.1.0)
|
importmap-rails (2.1.0)
|
||||||
actionpack (>= 6.0.0)
|
actionpack (>= 6.0.0)
|
||||||
activesupport (>= 6.0.0)
|
activesupport (>= 6.0.0)
|
||||||
@@ -224,7 +212,7 @@ GEM
|
|||||||
actionview (>= 5.0.0)
|
actionview (>= 5.0.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
json (2.11.3)
|
json (2.11.3)
|
||||||
kamal (2.6.0)
|
kamal (2.6.1)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
@@ -248,9 +236,6 @@ GEM
|
|||||||
net-smtp
|
net-smtp
|
||||||
marcel (1.0.4)
|
marcel (1.0.4)
|
||||||
matrix (0.4.2)
|
matrix (0.4.2)
|
||||||
mini_magick (5.2.0)
|
|
||||||
benchmark
|
|
||||||
logger
|
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.9)
|
mini_portile2 (2.8.9)
|
||||||
minitest (5.25.5)
|
minitest (5.25.5)
|
||||||
@@ -258,7 +243,7 @@ GEM
|
|||||||
multipart-post (2.4.1)
|
multipart-post (2.4.1)
|
||||||
net-http (0.6.0)
|
net-http (0.6.0)
|
||||||
uri
|
uri
|
||||||
net-imap (0.5.7)
|
net-imap (0.5.8)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-pop (0.1.2)
|
net-pop (0.1.2)
|
||||||
@@ -287,6 +272,9 @@ GEM
|
|||||||
parser (3.3.8.0)
|
parser (3.3.8.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
|
platform_agent (1.0.1)
|
||||||
|
activesupport (>= 5.2.0)
|
||||||
|
useragent (~> 0.16.3)
|
||||||
pp (0.6.2)
|
pp (0.6.2)
|
||||||
prettyprint
|
prettyprint
|
||||||
prettyprint (0.2.0)
|
prettyprint (0.2.0)
|
||||||
@@ -366,24 +354,21 @@ GEM
|
|||||||
rubocop-performance (>= 1.24)
|
rubocop-performance (>= 1.24)
|
||||||
rubocop-rails (>= 2.30)
|
rubocop-rails (>= 2.30)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-vips (2.2.3)
|
|
||||||
ffi (~> 1.12)
|
|
||||||
logger
|
|
||||||
rubyzip (2.4.1)
|
rubyzip (2.4.1)
|
||||||
securerandom (0.4.1)
|
securerandom (0.4.1)
|
||||||
selenium-webdriver (4.31.0)
|
selenium-webdriver (4.32.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
logger (~> 1.4)
|
logger (~> 1.4)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
rubyzip (>= 1.2.2, < 3.0)
|
rubyzip (>= 1.2.2, < 3.0)
|
||||||
websocket (~> 1.0)
|
websocket (~> 1.0)
|
||||||
sentry-rails (5.23.0)
|
sentry-rails (5.24.0)
|
||||||
railties (>= 5.0)
|
railties (>= 5.0)
|
||||||
sentry-ruby (~> 5.23.0)
|
sentry-ruby (~> 5.24.0)
|
||||||
sentry-ruby (5.23.0)
|
sentry-ruby (5.24.0)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
solid_cable (3.0.7)
|
solid_cable (3.0.8)
|
||||||
actioncable (>= 7.2)
|
actioncable (>= 7.2)
|
||||||
activejob (>= 7.2)
|
activejob (>= 7.2)
|
||||||
activerecord (>= 7.2)
|
activerecord (>= 7.2)
|
||||||
@@ -463,7 +448,6 @@ PLATFORMS
|
|||||||
x86_64-mingw32
|
x86_64-mingw32
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
actiontext-lexical!
|
|
||||||
active_record-tenanted!
|
active_record-tenanted!
|
||||||
bcrypt (~> 3.1.7)
|
bcrypt (~> 3.1.7)
|
||||||
bootsnap
|
bootsnap
|
||||||
@@ -472,10 +456,10 @@ DEPENDENCIES
|
|||||||
capybara
|
capybara
|
||||||
debug
|
debug
|
||||||
geared_pagination (~> 1.2)
|
geared_pagination (~> 1.2)
|
||||||
image_processing (~> 1.14)
|
|
||||||
importmap-rails
|
importmap-rails
|
||||||
jbuilder
|
jbuilder
|
||||||
kamal
|
kamal
|
||||||
|
platform_agent
|
||||||
propshaft
|
propshaft
|
||||||
puma (>= 5.0)
|
puma (>= 5.0)
|
||||||
rails!
|
rails!
|
||||||
|
|||||||
@@ -37,8 +37,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.comment__author {
|
.comment__author {
|
||||||
margin-inline-end: calc(var(--comment-padding-inline) * -0.5);
|
.comment--system & strong {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
font-weight: inherit;
|
font-weight: inherit;
|
||||||
}
|
}
|
||||||
@@ -51,9 +53,17 @@
|
|||||||
.comment--mine_ & {
|
.comment--mine_ & {
|
||||||
margin-inline: calc(var(--comment-padding-inline) * -0.75);
|
margin-inline: calc(var(--comment-padding-inline) * -0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment--system & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment__body {
|
.comment__body {
|
||||||
|
.comment--system & {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
&:first-child {
|
&:first-child {
|
||||||
margin-block-start: 0;
|
margin-block-start: 0;
|
||||||
@@ -99,8 +109,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment__event {
|
.comment--system {
|
||||||
|
--comment-padding-block: calc(var(--block-space) * 0.66);
|
||||||
|
|
||||||
|
line-height: 1.2;
|
||||||
max-inline-size: var(--comment-max);
|
max-inline-size: var(--comment-max);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
/* Make up space for lack of avatar */
|
/* Make up space for lack of avatar */
|
||||||
@@ -108,5 +123,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
inline-size: calc(var(--comment-padding-inline) * 0.75);
|
inline-size: calc(var(--comment-padding-inline) * 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment__author {
|
||||||
|
a {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment__body {
|
||||||
|
margin-block-start: calc(var(--block-space-half) * -0.33);
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: var(--text-normal);
|
font-size: var(--text-normal);
|
||||||
inset: auto 0 0 0;
|
inset: auto 0 0 0;
|
||||||
padding: var(--block-space) calc(var(--tray-size) + var(--inline-space-double));
|
padding: var(--block-space) calc(var(--tray-size) + calc(var(--inline-space) * 3));
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: var(--z-terminal);
|
z-index: var(--z-terminal);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
include Authentication, CurrentTimezone
|
include Authentication, CurrentTimezone, SetPlatform
|
||||||
|
|
||||||
stale_when_importmap_changes
|
stale_when_importmap_changes
|
||||||
allow_browser versions: :modern
|
allow_browser versions: :modern
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
module SetPlatform
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
helper_method :platform
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def platform
|
||||||
|
@platform ||= ApplicationPlatform.new(request.user_agent)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
module HotkeysHelper
|
||||||
|
def hotkey_label(hotkey)
|
||||||
|
hotkey.split(",").first if hotkey
|
||||||
|
case hotkey
|
||||||
|
when Array
|
||||||
|
hotkey.map { |key|
|
||||||
|
if key == "ctrl" && platform.mac?
|
||||||
|
"⌘"
|
||||||
|
elsif key == "enter"
|
||||||
|
platform.mac? ? "return" : "enter"
|
||||||
|
else
|
||||||
|
key
|
||||||
|
end
|
||||||
|
}.join("+")
|
||||||
|
else
|
||||||
|
hotkey.split(",").first if hotkey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,6 +3,7 @@ import { Controller } from "@hotwired/stimulus"
|
|||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
click(event) {
|
click(event) {
|
||||||
if (this.#isClickable && !this.#shouldIgnore(event)) {
|
if (this.#isClickable && !this.#shouldIgnore(event)) {
|
||||||
|
event.preventDefault()
|
||||||
this.element.click()
|
this.element.click()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
class ApplicationPlatform < PlatformAgent
|
||||||
|
def ios?
|
||||||
|
match? /iPhone|iPad/
|
||||||
|
end
|
||||||
|
|
||||||
|
def android?
|
||||||
|
match? /Android/
|
||||||
|
end
|
||||||
|
|
||||||
|
def mac?
|
||||||
|
match? /Macintosh/
|
||||||
|
end
|
||||||
|
|
||||||
|
def chrome?
|
||||||
|
user_agent.browser.match? /Chrome/
|
||||||
|
end
|
||||||
|
|
||||||
|
def safari?
|
||||||
|
user_agent.browser.match? /Safari/
|
||||||
|
end
|
||||||
|
|
||||||
|
def mobile?
|
||||||
|
ios? || android?
|
||||||
|
end
|
||||||
|
|
||||||
|
def desktop?
|
||||||
|
!mobile?
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -8,46 +8,22 @@ class Card::Eventable::SystemCommenter
|
|||||||
def comment
|
def comment
|
||||||
return unless comment_body.present?
|
return unless comment_body.present?
|
||||||
|
|
||||||
if comment = find_replaceable_system_comment
|
card.comments.create! creator: User.system, body: comment_body, created_at: event.created_at
|
||||||
comment.update! body: comment_body
|
|
||||||
else
|
|
||||||
card.comments.create! creator: User.system, body: comment_body, created_at: event.created_at
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
RELATED_EVENTS = [
|
|
||||||
%w[ card_assigned card_unassigned ]
|
|
||||||
]
|
|
||||||
|
|
||||||
def comment_body
|
def comment_body
|
||||||
case event.action
|
case event.action
|
||||||
when "card_assigned"
|
when "card_assigned"
|
||||||
"Assigned to #{event.assignees.pluck(:name).to_sentence}."
|
"#{event.creator.name} assigned this to #{event.assignees.pluck(:name).to_sentence}."
|
||||||
when "card_unassigned"
|
when "card_unassigned"
|
||||||
"Unassigned from #{event.assignees.pluck(:name).to_sentence}."
|
"#{event.creator.name} unassigned from #{event.assignees.pluck(:name).to_sentence}."
|
||||||
when "card_staged"
|
when "card_staged"
|
||||||
"#{event.creator.name} moved this to '#{event.stage_name}'."
|
"#{event.creator.name} moved this to '#{event.stage_name}'."
|
||||||
when "card_closed"
|
when "card_closed"
|
||||||
"Closed by #{ event.creator.name }"
|
"Closed as “#{ card.closure.reason }” by #{ event.creator.name }"
|
||||||
when "card_title_changed"
|
when "card_title_changed"
|
||||||
"#{event.creator.name} changed title from '#{event.particulars.dig('particulars', 'old_title')}' to '#{event.particulars.dig('particulars', 'new_title')}'."
|
"#{event.creator.name} changed the title from '#{event.particulars.dig('particulars', 'old_title')}' to '#{event.particulars.dig('particulars', 'new_title')}'."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_replaceable_system_comment
|
|
||||||
previous_comment, previous_event = card.comments.last, card.events[-2]
|
|
||||||
if previous_comment&.creator&.system? && replaceable_event?(previous_event, event)
|
|
||||||
previous_comment
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def replaceable_event?(candidate_event, replacement_event)
|
|
||||||
candidate_event && replacement_event &&
|
|
||||||
(candidate_event.action == replacement_event.action || related_events?(candidate_event, replacement_event))
|
|
||||||
end
|
|
||||||
|
|
||||||
def related_events?(candidate_event, replacement_event)
|
|
||||||
RELATED_EVENTS.find { |related_actions| related_actions.include?(candidate_event.action) && related_actions.include?(replacement_event.action) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class Command::GoToCard < Command
|
|||||||
validates_presence_of :card
|
validates_presence_of :card
|
||||||
|
|
||||||
def title
|
def title
|
||||||
"Visit card '#{card.title}'"
|
"Visit card '#{card&.title}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
@@ -13,6 +13,6 @@ class Command::GoToCard < Command
|
|||||||
|
|
||||||
private
|
private
|
||||||
def card
|
def card
|
||||||
user.accessible_cards.find(card_id)
|
user.accessible_cards.find_by_id(card_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<% cache comment do %>
|
<% cache comment do %>
|
||||||
<%= turbo_frame_tag comment do %>
|
<%= turbo_frame_tag comment do %>
|
||||||
<div class="comment flex align-start full-width" data-creator-id="<%= comment.creator_id %>" data-created-by-current-user-target="creation">
|
<div class="comment flex align-start full-width <%= "comment--system" if comment.creator.system? %>" data-creator-id="<%= comment.creator_id %>" data-created-by-current-user-target="creation">
|
||||||
<figure class="comment__avatar flex-item-no-shrink" aria-hidden="true">
|
<figure class="comment__avatar flex-item-no-shrink" aria-hidden="true">
|
||||||
<%= avatar_tag comment.creator, hidden_for_screen_reader: true %>
|
<%= avatar_tag comment.creator, hidden_for_screen_reader: true %>
|
||||||
</figure>
|
</figure>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="flex gap-half margin-block-start-double margin-block-end">
|
<div class="flex gap-half margin-block-start-double margin-block-end">
|
||||||
<span class="card-perma__closure-message">Completed by <%= card.closed_by.name %> on <%= local_datetime_tag(card.closed_at, style: :shortdate) %>.</span>
|
<span class="card-perma__closure-message">Completed by <%= card.closed_by.name %> on <%= local_datetime_tag(card.closed_at, style: :shortdate) %>.</span>
|
||||||
<%= button_to card_closure_path(card), method: :delete, class: "btn btn--plain borderless fill-transparent" do %>
|
<%= button_to card_closure_path(card), method: :delete, class: "btn btn--plain borderless fill-transparent" do %>
|
||||||
<span class="pad-inline-end">Un-do</span>
|
<span class="pad-inline-end">Undo</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="card-filter--collection flex-inline flex-column align-center center position-relative" data-controller="dialog" data-action="click@document->dialog#closeOnClickOutside">
|
<div class="card-filter--collection flex-inline flex-column align-center center position-relative" data-controller="dialog" data-action="click@document->dialog#closeOnClickOutside">
|
||||||
<%= tag.button class: "txt-align-center input input--select borderless txt-medium",
|
<%= tag.button class: "txt-align-center input input--select borderless txt-medium",
|
||||||
data: {
|
data: {
|
||||||
action: "click->dialog#open:stop keydown.meta+j@document->hotkey#click",
|
action: "click->dialog#open:stop keydown.meta+j@document->hotkey#click keydown.ctrl+j@document->hotkey#click",
|
||||||
controller: "hotkey" } do %>
|
controller: "hotkey" } do %>
|
||||||
<h1 class="txt-large overflow-ellipsis margin-none">
|
<h1 class="txt-large overflow-ellipsis margin-none">
|
||||||
<span><%= filter_title filter %></span>
|
<span><%= filter_title filter %></span>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<%= render "cards/index/collections_filter", filter: filter %>
|
<%= render "cards/index/collections_filter", filter: filter %>
|
||||||
</menu>
|
</menu>
|
||||||
<p class="txt-small txt-nowrap txt-align-center margin-block-half full-width">
|
<p class="txt-small txt-nowrap txt-align-center margin-block-half full-width">
|
||||||
Press <kbd class="kbd">⌘j</kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close.
|
Press <kbd class="kbd"><%= hotkey_label(["ctrl", "J"]) -%></kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close.
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
data: {
|
data: {
|
||||||
controller: "form",
|
controller: "form",
|
||||||
terminal_target: "form",
|
terminal_target: "form",
|
||||||
action: "turbo:submit-start->terminal#commandSubmitted turbo:submit-end->terminal#focus keydown.meta+k@document->terminal#focus keydown.enter->terminal#executeCommand keydown.esc->terminal#hideMenus turbo:submit-end->terminal#handleCommandResponse"
|
action: "turbo:submit-start->terminal#commandSubmitted turbo:submit-end->terminal#focus keydown.meta+k@document->terminal#focus:prevent keydown.ctrl+k@document->terminal#focus:prevent keydown.enter->terminal#executeCommand keydown.esc->terminal#hideMenus turbo:submit-end->terminal#handleCommandResponse"
|
||||||
} do %>
|
} do %>
|
||||||
<label class="terminal__label txt-nowrap" for="fizzy_do">Fizzy do ></label>
|
<label class="terminal__label txt-nowrap" for="fizzy_do">Fizzy do ></label>
|
||||||
|
|
||||||
@@ -17,9 +17,8 @@
|
|||||||
terminal_target: "input",
|
terminal_target: "input",
|
||||||
action: "keydown.up->toggle-class#add:prevent keydown.up->navigable-list#selectCurrentOrLast terminal#hideError"
|
action: "keydown.up->toggle-class#add:prevent keydown.up->navigable-list#selectCurrentOrLast terminal#hideError"
|
||||||
},
|
},
|
||||||
placeholder: "Press ⌘+K to search or type commands…",
|
placeholder: "Press #{ hotkey_label(["ctrl", "K"]) } to search or type commands…",
|
||||||
spellcheck: "false" %>
|
spellcheck: "false" %>
|
||||||
|
|
||||||
<%= hidden_field_tag "confirmed", nil, data: { terminal_target: "confirmation" } %>
|
<%= hidden_field_tag "confirmed", nil, data: { terminal_target: "confirmation" } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||||
<%= tag.button class:"events__filter-btn input input--select flex-inline center min-width max-width txt-small",
|
<%= tag.button class:"events__filter-btn input input--select flex-inline center min-width max-width txt-small",
|
||||||
data: {
|
data: {
|
||||||
action: "click->dialog#open:stop keydown.meta+j@document->hotkey#click",
|
action: "click->dialog#open:stop keydown.meta+j@document->hotkey#click keydown.ctrl+j@document->hotkey#click",
|
||||||
controller: "hotkey" } do %>
|
controller: "hotkey" } do %>
|
||||||
<span class="overflow-ellipsis center">
|
<span class="overflow-ellipsis center">
|
||||||
<%= filter_selected_collections_label(filter) %>
|
<%= filter_selected_collections_label(filter) %>
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p class="txt-small txt-nowrap txt-align-center margin-block-half full-width">
|
<p class="txt-small txt-nowrap txt-align-center margin-block-half full-width">
|
||||||
Press <kbd class="kbd">⌘j</kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close.
|
Press <kbd class="kbd"><%= hotkey_label(["ctrl", "K"]) -%></kbd> anytime to open this, <kbd class="kbd">esc</kbd> to close.
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ accessories:
|
|||||||
beamer-primary:
|
beamer-primary:
|
||||||
<<: *beamer-accessory
|
<<: *beamer-accessory
|
||||||
service: beamer-primary
|
service: beamer-primary
|
||||||
cmd: beamer primary --remove-after=1h --dir=/storage
|
cmd: beamer primary --remove-after=1h --dir=/storage --disable-tls
|
||||||
port: 5000:80
|
port: 5000:80
|
||||||
roles:
|
roles:
|
||||||
- web
|
- web
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class Card::Eventable::SystemCommenterTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "card_assigned" do
|
test "card_assigned" do
|
||||||
assert_system_comment "Assigned to Kevin" do
|
assert_system_comment "David assigned this to Kevin." do
|
||||||
@card.toggle_assignment users(:kevin)
|
@card.toggle_assignment users(:kevin)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -16,7 +16,7 @@ class Card::Eventable::SystemCommenterTest < ActiveSupport::TestCase
|
|||||||
@card.toggle_assignment users(:kevin)
|
@card.toggle_assignment users(:kevin)
|
||||||
@card.comments.destroy_all # To skip deduplication logic
|
@card.comments.destroy_all # To skip deduplication logic
|
||||||
|
|
||||||
assert_system_comment "Unassigned from Kevin" do
|
assert_system_comment "David unassigned from Kevin" do
|
||||||
@card.toggle_assignment users(:kevin)
|
@card.toggle_assignment users(:kevin)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -28,35 +28,17 @@ class Card::Eventable::SystemCommenterTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "card_closed" do
|
test "card_closed" do
|
||||||
assert_system_comment "Closed by David" do
|
assert_system_comment "Closed as “Done” by David" do
|
||||||
@card.close
|
@card.close
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "card_title_changed" do
|
test "card_title_changed" do
|
||||||
assert_system_comment "David changed title from 'The text is too small' to 'Make text larger'" do
|
assert_system_comment "David changed the title from 'The text is too small' to 'Make text larger'." do
|
||||||
@card.update! title: "Make text larger"
|
@card.update! title: "Make text larger"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "don't duplicate comments for the same kind of events" do
|
|
||||||
@card.change_stage_to workflow_stages(:qa_in_progress)
|
|
||||||
|
|
||||||
assert_no_difference -> { @card.comments.count } do
|
|
||||||
@card.reload.change_stage_to workflow_stages(:qa_on_hold)
|
|
||||||
assert_match /David moved this to 'On hold'/i, @card.comments.last.body.to_plain_text
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "don't duplicate comments for related events" do
|
|
||||||
@card.toggle_assignment users(:kevin)
|
|
||||||
|
|
||||||
assert_no_difference -> { @card.comments.count } do
|
|
||||||
@card.reload.toggle_assignment users(:kevin)
|
|
||||||
assert_match /Unassigned from Kevin/i, @card.comments.last.body.to_plain_text
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "don't notify on system comments" do
|
test "don't notify on system comments" do
|
||||||
@card.watch_by(users(:david))
|
@card.watch_by(users(:david))
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class Command::CloseTest < ActionDispatch::IntegrationTest
|
|||||||
|
|
||||||
execute_command "/close", context_url: collection_cards_url(@card.collection)
|
execute_command "/close", context_url: collection_cards_url(@card.collection)
|
||||||
|
|
||||||
cards.each { it.reload.closed? }
|
assert cards.map(&:reload).all?(&:closed?)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "undo close" do
|
test "undo close" do
|
||||||
@@ -42,10 +42,10 @@ class Command::CloseTest < ActionDispatch::IntegrationTest
|
|||||||
command = parse_command "/close", context_url: collection_cards_url(@card.collection)
|
command = parse_command "/close", context_url: collection_cards_url(@card.collection)
|
||||||
command.execute
|
command.execute
|
||||||
|
|
||||||
cards.each { it.reload.closed? }
|
assert cards.map(&:reload).all?(&:closed?)
|
||||||
|
|
||||||
command.undo
|
command.undo
|
||||||
|
|
||||||
cards.each { it.reload.open? }
|
assert cards.map(&:reload).all?(&:open?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user