Reapply "Add a description field for cards"
This reverts commit a4cc143b09.
This commit is contained in:
@@ -96,6 +96,7 @@
|
||||
|
||||
border-color: var(--card-color) !important;
|
||||
border-style: dashed !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.card__background {
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btn:not(.popup__item, .btn--plain) {
|
||||
.btn:not(.popup__item, .btn--plain, .btn--reversed) {
|
||||
--btn-background: var(--card-color);
|
||||
--btn-color: var(--color-ink-reversed);
|
||||
}
|
||||
@@ -110,6 +110,11 @@
|
||||
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn--reversed {
|
||||
--btn-background: var(--color-bg);
|
||||
--btn-color: var(--card-color);
|
||||
}
|
||||
}
|
||||
|
||||
.card-perma__closure-message {
|
||||
@@ -119,29 +124,4 @@
|
||||
padding-left: 1ch;
|
||||
}
|
||||
}
|
||||
|
||||
/* Variants
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
.card-perma--pointing {
|
||||
--arrow-size: 20em;
|
||||
--aspect-ratio: 7;
|
||||
|
||||
position: relative;
|
||||
margin-block-end: calc(var(--arrow-size) / var(--aspect-ratio));
|
||||
|
||||
&::after {
|
||||
aspect-ratio: var(--aspect-ratio);
|
||||
background-color: var(--color-container);
|
||||
clip-path: polygon(50% 100%, 100% 0, 0 0);
|
||||
inline-size: var(--arrow-size);
|
||||
content: "";
|
||||
display: block;
|
||||
inset-block-start: 99%;
|
||||
inset-inline-start: 50%;
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,18 +99,42 @@
|
||||
padding-block: var(--card-padding-block);
|
||||
}
|
||||
|
||||
.card__description {
|
||||
house-md-toolbar,
|
||||
.house-md-content {
|
||||
color: color-mix(in srgb, var(--card-color) 40%, var(--color-ink));
|
||||
}
|
||||
|
||||
.house-md-content {
|
||||
min-block-size: 3lh;
|
||||
padding: var(--block-space-half) var(--inline-space) 0 0;
|
||||
}
|
||||
|
||||
& ~ .btn {
|
||||
--btn-background: var(--card-color);
|
||||
--btn-color: var(--color-ink-reversed);
|
||||
}
|
||||
}
|
||||
|
||||
.card__title {
|
||||
--hover-size: 0;
|
||||
--input-border-radius: 0;
|
||||
--input-color: color-mix(in srgb, var(--card-color) 40%, var(--color-ink));
|
||||
--lines: 3;
|
||||
|
||||
color: inherit;
|
||||
flex: 2 1 75%;
|
||||
font-size: var(--text-xx-large);
|
||||
font-weight: 900;
|
||||
line-height: 1.1;
|
||||
line-height: 1.2;
|
||||
min-block-size: 3lh;
|
||||
text-wrap: balance;
|
||||
|
||||
.card__title-field {
|
||||
.card-perma__bg & {
|
||||
min-block-size: unset;
|
||||
}
|
||||
|
||||
.card-field__title {
|
||||
&:is(textarea)::placeholder {
|
||||
color: inherit;
|
||||
opacity: 0.5;
|
||||
@@ -118,8 +142,6 @@
|
||||
}
|
||||
|
||||
.card__title-link {
|
||||
--lines: 3;
|
||||
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
@@ -130,11 +152,11 @@
|
||||
flex-direction: column;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
padding-block: var(--block-space);
|
||||
padding-block: var(--block-space-half);
|
||||
}
|
||||
|
||||
.card__move-button {
|
||||
--btn-background: color-mix(in srgb, var(--card-color) 40%, var(--color-ink));
|
||||
--btn-background: color-mix(in srgb, inherit 40%, var(--color-ink));
|
||||
|
||||
margin-block-start: calc(var(--block-space) * 1.2);
|
||||
margin-inline-end: calc(var(--inline-space) * -4);
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
padding:
|
||||
var(--comment-padding-block)
|
||||
var(--comment-padding-inline);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.comment__edit {
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
/* Markdown Content */
|
||||
.house-md-content {
|
||||
caret-color: var(--color-link);
|
||||
flex-grow: 1;
|
||||
font-family: var(--font-sans);
|
||||
text-align: left;
|
||||
@@ -67,7 +66,7 @@
|
||||
|
||||
&.house-md-content-empty::before {
|
||||
content: attr(placeholder);
|
||||
color: var(--color-ink);
|
||||
color: currentColor;
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
|
||||
@@ -54,7 +54,7 @@ class CardsController < ApplicationController
|
||||
end
|
||||
|
||||
def card_params
|
||||
params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ])
|
||||
params.expect(card: [ :status, :title, :description, :image, tag_ids: [] ])
|
||||
end
|
||||
|
||||
def render_card_replacement
|
||||
|
||||
@@ -19,7 +19,8 @@ module CardsHelper
|
||||
classes = [
|
||||
options.delete(:class),
|
||||
("card--golden" if card.golden?),
|
||||
("card--doing" if card.doing?)
|
||||
("card--doing" if card.doing?),
|
||||
("card--drafted" if card.drafted?)
|
||||
].compact.join(" ")
|
||||
|
||||
tag.article \
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
class Card < ApplicationRecord
|
||||
include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden,
|
||||
include Assignable, Colored, Engageable, Eventable, Golden,
|
||||
Messages, Notifiable, Pinnable, Closeable, Searchable, Staged,
|
||||
Statuses, Taggable, Watchable
|
||||
|
||||
@@ -10,6 +10,8 @@ class Card < ApplicationRecord
|
||||
|
||||
has_one_attached :image, dependent: :purge_later
|
||||
|
||||
has_markdown :description
|
||||
|
||||
scope :reverse_chronologically, -> { order created_at: :desc, id: :desc }
|
||||
scope :chronologically, -> { order created_at: :asc, id: :asc }
|
||||
scope :latest, -> { order updated_at: :desc, id: :desc }
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
module Card::DraftCommenting
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
after_save :capture_draft_comment
|
||||
end
|
||||
|
||||
def draft_comment
|
||||
find_or_build_initial_comment.body.content
|
||||
end
|
||||
|
||||
def draft_comment=(body)
|
||||
if body.present?
|
||||
@draft_comment = body
|
||||
else
|
||||
messages.comments.destroy_all
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_or_build_initial_comment
|
||||
message = messages.comments.first || messages.new(messageable: Comment.new)
|
||||
message.comment
|
||||
end
|
||||
|
||||
def capture_draft_comment
|
||||
if @draft_comment.present?
|
||||
find_or_build_initial_comment.update! body: @draft_comment, creator: creator
|
||||
end
|
||||
|
||||
@draft_comment = nil
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,7 @@ module Card::Searchable
|
||||
included do
|
||||
include ::Searchable
|
||||
|
||||
searchable_by :title, using: :cards_search_index
|
||||
searchable_by :title_and_description, using: :cards_search_index, as: :title
|
||||
|
||||
scope :mentioning, ->(query) do
|
||||
if query = sanitize_query_syntax(query)
|
||||
@@ -18,25 +18,31 @@ module Card::Searchable
|
||||
end
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def sanitize_query_syntax(terms)
|
||||
terms = terms.to_s
|
||||
terms = remove_invalid_search_characters(terms)
|
||||
terms = remove_unbalanced_quotes(terms)
|
||||
terms.presence
|
||||
class_methods do
|
||||
def sanitize_query_syntax(terms)
|
||||
terms = terms.to_s
|
||||
terms = remove_invalid_search_characters(terms)
|
||||
terms = remove_unbalanced_quotes(terms)
|
||||
terms.presence
|
||||
end
|
||||
|
||||
private
|
||||
def remove_invalid_search_characters(terms)
|
||||
terms.gsub(/[^\w"]/, " ")
|
||||
end
|
||||
|
||||
private
|
||||
def remove_invalid_search_characters(terms)
|
||||
terms.gsub(/[^\w"]/, " ")
|
||||
def remove_unbalanced_quotes(terms)
|
||||
if terms.count("\"").even?
|
||||
terms
|
||||
else
|
||||
terms.gsub("\"", " ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_unbalanced_quotes(terms)
|
||||
if terms.count("\"").even?
|
||||
terms
|
||||
else
|
||||
terms.gsub("\"", " ")
|
||||
end
|
||||
end
|
||||
private
|
||||
# TODO: Temporary until we stabilize the search API
|
||||
def title_and_description
|
||||
[ title, description.to_plain_text ].join(" ")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<section id="<%= dom_id(card, :card_container) %>"
|
||||
class="card-perma <%= "card-perma--pointing" unless card.published? %>" style="--card-color: <%= card.color %>;">
|
||||
class="card-perma" style="--card-color: <%= card.color %>;">
|
||||
<%= render "cards/container/engagement", card: card %>
|
||||
|
||||
<aside class="card-perma__actions card-perma__actions--left" role="toolbar">
|
||||
<%= render "cards/container/edit", card: card if card.published? %>
|
||||
<%= render "cards/container/gild", card: card if card.doing? %>
|
||||
<%= render "cards/container/image", card: card %>
|
||||
|
||||
@@ -32,11 +33,8 @@
|
||||
</div>
|
||||
|
||||
<% if card.published? %>
|
||||
<aside class="card-perma__actions card-perma__actions--right" role="toolbar">
|
||||
<%= turbo_frame_tag card, :watch, src: card_watch_path(card), data: { turbo_permanent: true } %>
|
||||
<%= turbo_frame_tag card, :pin, src: card_pin_path(card), data: { turbo_permanent: true } %>
|
||||
</aside>
|
||||
|
||||
<%= render "cards/container/closure", card: card %>
|
||||
<%= render "cards/container/footer/published", card: card %>
|
||||
<% elsif card.creating? %>
|
||||
<%= render "cards/container/footer/draft", card: card %>
|
||||
<% end %>
|
||||
</section>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
<div class="comments pad-block">
|
||||
<div class="comment comment--new flex-inline align-start full-width">
|
||||
<figure class="comment__avatar flex-item-no-shrink" aria-hidden="true">
|
||||
<%= avatar_tag Current.user, hidden_for_screen_reader: true %>
|
||||
</figure>
|
||||
|
||||
<div class="comment__content flex-inline flex-column full-width">
|
||||
<div class="comment__body txt-align-start">
|
||||
<form data-controller="outlet-auto-save paste"
|
||||
class="flex flex-column gap full-width"
|
||||
data-outlet-auto-save-auto-save-outlet="#card_form"
|
||||
data-action="paste->paste#pasteFiles">
|
||||
<%= tag.house_md card.draft_comment, name: "card[draft_comment]", class: "input comment__input",
|
||||
form: "card_form",
|
||||
placeholder: new_comment_placeholder(card),
|
||||
data: { action: "house-md:change->outlet-auto-save#change focusout->outlet-auto-save#submit", uploads_url: uploads_url(format: "json") } %>
|
||||
</form>
|
||||
|
||||
<% if card.creating? %>
|
||||
<div class="margin-block-start flex align-center gap">
|
||||
<%= button_to "Create card", card_publish_path(card), class: "btn btn--reversed" %>
|
||||
<%= button_to "Save as draft", collection_card_path(card.collection, card), name: "card[status]", value: "drafted", method: :put, class: "btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="card-perma__notch card-perma__notch--bottom flex-column" id="<%= dom_id(@card, :card_closure_toggle) %>" style="--card-color: <%= @card.color %>">
|
||||
<div class="card-perma__notch card-perma__notch--bottom flex-column" id="<%= dom_id(card, :card_closure_toggle) %>" style="--card-color: <%= card.color %>">
|
||||
<% if card.closed? %>
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<%= link_to edit_collection_card_path(card.collection, card), class: "btn", data: { turbo_frame: dom_id(card, :edit) } do %>
|
||||
<%= icon_tag "pencil" %>
|
||||
<span class="for-screen-reader">Edit</span>
|
||||
<% end %>
|
||||
@@ -1,14 +1,27 @@
|
||||
<h1 class="card__title">
|
||||
<% if card.published? %>
|
||||
<%= turbo_frame_tag card, :edit do %>
|
||||
<%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link overflow-line-clamp" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", data: { controller: "auto-save" } do |form| %>
|
||||
<% if card.published? %>
|
||||
<%= turbo_frame_tag card, :edit do %>
|
||||
<div class="full-width">
|
||||
<h1 class="card__title flex align-start gap-half">
|
||||
<%= link_to card.title, edit_collection_card_path(card.collection, card), class: "card__title-link" %>
|
||||
</h1>
|
||||
<p class="card__description margin-block-half">
|
||||
<%= sanitize card.description_html %>
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= form_with model: card, url: collection_card_path(card.collection, card), id: "card_form", class: "full-width", data: { controller: "auto-save" } do |form| %>
|
||||
<h1 class="card__title">
|
||||
<%= form.text_area :title, placeholder: "Name it…",
|
||||
class: "input input--textarea full-width borderless txt-align-start #{ "fill-highlight" if card.creating? }",
|
||||
class: "input input--textarea full-width borderless txt-align-start",
|
||||
autofocus: card.title.blank?,
|
||||
data: { action: "auto-save#change blur->auto-save#submit keydown.enter->auto-save#submit:prevent keydown.ctrl+enter->auto-save#submit:prevent" } %>
|
||||
<% end %>
|
||||
</h1>
|
||||
<div class="card__description margin-block-half">
|
||||
<%= form.markdown_area :description, class: "input input--textarea full-width borderless txt-align-start card-field__description",
|
||||
placeholder: "Add some notes, context, pictures, or video about this…",
|
||||
data: { action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } %>
|
||||
</div>
|
||||
<%= form.button "Save changes", type: :submit, class: "btn"%>
|
||||
<% end %>
|
||||
</h1>
|
||||
<% end %>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="card-perma__notch card-perma__notch--bottom">
|
||||
<%= button_to "Create card", card_publish_path(card), class: "btn" %>
|
||||
<%= button_to "Save as draft", collection_card_path(card.collection, card), name: "card[status]", value: "drafted", method: :put, class: "btn btn--reversed" %>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
<%# FIXME: Let's move this aside outside of the card container section so these frames don't reload/flicker when card is replaced %>
|
||||
<aside class="card-perma__actions card-perma__actions--right" role="toolbar">
|
||||
<%= turbo_frame_tag card, :watch, src: card_watch_path(card) %>
|
||||
<%= turbo_frame_tag card, :pin, src: card_pin_path(card) %>
|
||||
</aside>
|
||||
|
||||
<%= render "cards/container/closure", card: card %>
|
||||
@@ -6,8 +6,8 @@
|
||||
</header>
|
||||
|
||||
<div class="card__body flex gap full-width flex-item-grow">
|
||||
<h1 class="card__title">
|
||||
<span class="card__title-link overflow-line-clamp"><%= card.title %></span>
|
||||
<h1 class="card__title overflow-line-clamp">
|
||||
<%= card.title %>
|
||||
</h1>
|
||||
|
||||
<%= link_to collection_card_path(card.collection, card), class: "card__link" do %>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<% end %>
|
||||
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" <%= "hidden" if card.closed? %>>
|
||||
<button class="btn card__hide-on-index <%= card.creating? || card.drafted? ? "fill-highlight" : "fill-transparent" %>" data-action="click->dialog#open:stop">
|
||||
<button class="btn card__hide-on-index fill-transparent" data-action="click->dialog#open:stop">
|
||||
<%= icon_tag "person-add" %>
|
||||
<span class="for-screen-reader">Assign</span>
|
||||
</button>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" <%= "hidden" if card.closed? %>>
|
||||
<button class="tag-picker__button btn card__hide-on-index <%= card.creating? || card.drafted? ? "fill-highlight" : "fill-transparent" %>" data-action="click->dialog#open:stop">
|
||||
<button class="tag-picker__button btn card__hide-on-index fill-transparent" data-action="click->dialog#open:stop">
|
||||
<%= icon_tag "tag" %>
|
||||
<span class="for-screen-reader">Add a tag</span>
|
||||
</button>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
<%= turbo_frame_tag @card, :edit do %>
|
||||
<%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "flex flex-column gap full-width", data: { controller: "form" } do |form| %>
|
||||
<%= form.label :title, class: "flex flex-column align-center" do %>
|
||||
<%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card__title-field",
|
||||
required: true, autofocus: true, placeholder: "Name it…",
|
||||
rows: 3,
|
||||
data: { action: "keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" },
|
||||
style: "color: var(--spat-color); --input-border-radius: 0" %>
|
||||
<% end %>
|
||||
<%= form.button "Save", type: :submit, hidden: true %>
|
||||
<%= form_with model: @card, url: collection_card_path(@card.collection, @card), class: "full-width", data: { controller: "form paste" } do |form| %>
|
||||
<h1 class="card__title">
|
||||
<%= form.label :title, class: "flex flex-column align-center" do %>
|
||||
<%= form.text_area :title, class: "input input--textarea full-width borderless txt-align-start card-field__title",
|
||||
required: true, autofocus: true, placeholder: "Name it…",
|
||||
rows: 1,
|
||||
data: { action: "keydown.enter->form#submit:prevent keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel focus->form#select" } %>
|
||||
<% end %>
|
||||
</h1>
|
||||
<div class="card__description margin-block-half">
|
||||
<%= form.markdown_area :description, class: "input input--textarea full-width borderless txt-align-start card-field__description",
|
||||
placeholder: "Add some notes, context, pictures, or video about this…",
|
||||
data: { action: "keydown.ctrl+enter->form#submit:prevent keydown.meta+enter->form#submit:prevent keydown.esc->form#cancel:stop paste->paste#pasteFiles" } %>
|
||||
</div>
|
||||
<%= form.button "Save changes", type: :submit, class: "btn"%>
|
||||
<%= link_to "Close editor and discard changes", collection_card_path(@card.collection, @card), data: { form_target: "cancel" }, hidden: true %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -34,7 +34,5 @@
|
||||
|
||||
<% if @card.published? %>
|
||||
<%= render "cards/messages", card: @card %>
|
||||
<% else %>
|
||||
<%= render "cards/description_as_draft_comment", card: @card %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -36,19 +36,17 @@ class CardsControllerTest < ActionDispatch::IntegrationTest
|
||||
patch collection_card_path(collections(:writebook), cards(:logo)), params: {
|
||||
card: {
|
||||
title: "Logo needs to change",
|
||||
due_on: 1.week.from_now,
|
||||
image: fixture_file_upload("moon.jpg", "image/jpeg"),
|
||||
draft_comment: "Something more in-depth",
|
||||
description: "Something more in-depth",
|
||||
tag_ids: [ tags(:mobile).id ] } }
|
||||
assert_response :success
|
||||
|
||||
card = cards(:logo).reload
|
||||
assert_equal "Logo needs to change", card.title
|
||||
assert_equal 1.week.from_now.to_date, card.due_on
|
||||
assert_equal "moon.jpg", card.image.filename.to_s
|
||||
assert_equal [ tags(:mobile) ], card.tags
|
||||
|
||||
assert_equal "Something more in-depth", card.messages.comments.first.comment.body_plain_text.strip
|
||||
assert_equal "Something more in-depth", card.description_plain_text.strip
|
||||
end
|
||||
|
||||
test "users can only see cards in collections they have access to" do
|
||||
|
||||
@@ -6,41 +6,4 @@ class Card::MessagesTest < ActiveSupport::TestCase
|
||||
|
||||
assert_empty card.messages
|
||||
end
|
||||
|
||||
test "creating a card with an initial draft comment" do
|
||||
card = collections(:writebook).cards.create! creator: users(:kevin), title: "New",
|
||||
draft_comment: "This is a comment"
|
||||
|
||||
assert_equal 1, card.messages.count
|
||||
assert_equal "This is a comment", card.draft_comment.strip
|
||||
end
|
||||
|
||||
test "updating the draft comment" do
|
||||
card = collections(:writebook).cards.create! creator: users(:kevin), title: "New",
|
||||
draft_comment: "This is a comment"
|
||||
|
||||
card.update! draft_comment: "This is an updated comment"
|
||||
|
||||
assert_equal 1, card.messages.count
|
||||
assert_equal "This is an updated comment", card.draft_comment.strip
|
||||
end
|
||||
|
||||
test "setting the draft comment to be blank removes it" do
|
||||
card = collections(:writebook).cards.create! creator: users(:kevin), title: "New",
|
||||
draft_comment: "This is a comment"
|
||||
|
||||
card.update! draft_comment: " "
|
||||
|
||||
assert card.messages.first.nil?
|
||||
end
|
||||
|
||||
test "omitting the draft comment does not remove it" do
|
||||
card = collections(:writebook).cards.create! creator: users(:kevin), title: "New",
|
||||
draft_comment: "This is a comment"
|
||||
|
||||
card.update! title: "Newer"
|
||||
|
||||
assert_equal 1, card.messages.count
|
||||
assert_equal "This is a comment", card.draft_comment.strip
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user