Merge branch 'main' into consolidate-cards
* main: (94 commits) Source order seems to be significant Use `card.title` Nicer flow Fix string interpolation Fix constant Use record lookup Always use sole Explained less and extracted nothing of value Weird double negative Remove anemic and indirect method that explained nothing Can use record lookup for workflows Access control has already been done through the card Style Use _path in all cases where we are not potentially changing the domain Clearer Spacing Get rid of card_title Join the two users controllers but split out role setting Ensure user is returned We are not using the parameter ...
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
class Accounts::JoinCodesController < ApplicationController
|
||||
def show
|
||||
render svg: RQRCode::QRCode.new(join_url(Current.account.join_code)).as_svg(viewbox: true, fill: :white, color: :black)
|
||||
render svg: RQRCode::QRCode.new(join_url(Account.sole.join_code)).as_svg(viewbox: true, fill: :white, color: :black)
|
||||
end
|
||||
|
||||
def update
|
||||
Current.account.reset_join_code
|
||||
redirect_to account_users_path
|
||||
Account.sole.reset_join_code
|
||||
redirect_to users_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
class Accounts::UsersController < ApplicationController
|
||||
before_action :set_user, only: %i[ update destroy ]
|
||||
before_action :ensure_permission_to_administer_user, only: %i[ update destroy ]
|
||||
|
||||
def index
|
||||
@users = Current.account.users.active
|
||||
end
|
||||
|
||||
def update
|
||||
@user.update(role_params)
|
||||
redirect_to account_users_path
|
||||
end
|
||||
|
||||
def destroy
|
||||
@user.deactivate
|
||||
redirect_to account_users_path
|
||||
end
|
||||
|
||||
private
|
||||
def set_user
|
||||
@user = Current.account.users.active.find(params[:id])
|
||||
end
|
||||
|
||||
def ensure_permission_to_administer_user
|
||||
head :forbidden unless Current.user.can_administer?(@user)
|
||||
end
|
||||
|
||||
def role_params
|
||||
{ role: params.require(:user)[:role].presence_in(%w[ member admin ]) || "member" }
|
||||
end
|
||||
end
|
||||
@@ -1,12 +0,0 @@
|
||||
class Cards::BoostsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
def create
|
||||
count = if params[:boost_count].to_i == @card.boosts_count
|
||||
@card.boosts_count + 1
|
||||
else
|
||||
params[:boost_count].to_i
|
||||
end
|
||||
@card.boost!(count)
|
||||
end
|
||||
end
|
||||
@@ -1,42 +1,38 @@
|
||||
class Cards::Comments::ReactionsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
before_action :set_comment
|
||||
|
||||
def index
|
||||
@reactions = @comment.reactions.ordered.includes(:reacter)
|
||||
end
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
@reaction = @comment.reactions.create!(reaction_params)
|
||||
reaction = @comment.reactions.create!(params.expect(reaction: :content))
|
||||
|
||||
broadcast_create
|
||||
redirect_to card_comment_reactions_url(@comment.card, @comment)
|
||||
broadcast_create(reaction)
|
||||
redirect_to card_comment_reactions_path(@card, @comment)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@reaction = @comment.reactions.find(params[:id])
|
||||
@reaction.destroy!
|
||||
reaction = @comment.reactions.find(params[:id])
|
||||
reaction.destroy
|
||||
|
||||
broadcast_remove
|
||||
broadcast_remove(reaction)
|
||||
end
|
||||
|
||||
private
|
||||
def set_comment
|
||||
@comment = Current.account.comments.find(params[:comment_id])
|
||||
@comment = Comment.belonging_to_card(@card).find(params[:comment_id])
|
||||
end
|
||||
|
||||
def reaction_params
|
||||
params.require(:reaction).permit(:content)
|
||||
def broadcast_create(reaction)
|
||||
reaction.broadcast_append_to @card, target: [ @comment, :reactions ], partial: "cards/comments/reactions/reaction"
|
||||
end
|
||||
|
||||
def broadcast_create
|
||||
@reaction.broadcast_append_to @reaction.comment, :comments,
|
||||
target: "reactions_comment_#{@comment.id}", partial: "cards/comments/reactions/reaction", locals: { comment: @comment }
|
||||
end
|
||||
|
||||
def broadcast_remove
|
||||
@reaction.broadcast_remove_to @reaction.comment, :comments
|
||||
def broadcast_remove(reaction)
|
||||
reaction.broadcast_remove_to @card
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
class Cards::CommentsController < ApplicationController
|
||||
include CardScoped
|
||||
before_action :set_comment, only: [ :show, :edit, :update, :destroy ]
|
||||
before_action :require_own_comment, only: [ :edit, :update, :destroy ]
|
||||
|
||||
before_action :set_comment, only: %i[ show edit update destroy ]
|
||||
before_action :ensure_creatorship, only: %i[ edit update destroy ]
|
||||
|
||||
def create
|
||||
@card.capture new_comment
|
||||
@card.capture Comment.new(comment_params)
|
||||
end
|
||||
|
||||
def show
|
||||
@@ -23,21 +24,15 @@ class Cards::CommentsController < ApplicationController
|
||||
end
|
||||
|
||||
private
|
||||
def comment_params
|
||||
params.require(:comment).permit(:body)
|
||||
end
|
||||
|
||||
def new_comment
|
||||
Comment.new(comment_params)
|
||||
end
|
||||
|
||||
def set_comment
|
||||
@comment = Comment.joins(:message)
|
||||
.where(messages: { card_id: @card.id })
|
||||
.find(params[:id])
|
||||
@comment = Comment.belonging_to_card(@card).find(params[:id])
|
||||
end
|
||||
|
||||
def require_own_comment
|
||||
head :forbidden unless Current.user == @comment.creator
|
||||
def ensure_creatorship
|
||||
head :forbidden if Current.user != @comment.creator
|
||||
end
|
||||
|
||||
def comment_params
|
||||
params.expect(comment: :body)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
class Cards::PreviewsController < ApplicationController
|
||||
include FilterScoped
|
||||
|
||||
before_action :set_filter, only: :index
|
||||
|
||||
def index
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
class Cards::StagingsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
before_action :set_stage
|
||||
|
||||
def create
|
||||
if params[:stage_id].present?
|
||||
@card.toggle_stage Current.account.stages.find(params[:stage_id])
|
||||
if @stage
|
||||
@card.toggle_stage @stage
|
||||
else
|
||||
@card.update!(stage: nil)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def set_stage
|
||||
@stage = Workflow::Stage.find_by(id: params[:stage_id])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ class Cards::TaggingsController < ApplicationController
|
||||
include CardScoped
|
||||
|
||||
def new
|
||||
@tags = Current.account.tags.alphabetically
|
||||
@tags = Tag.all.alphabetically
|
||||
end
|
||||
|
||||
def create
|
||||
|
||||
@@ -15,7 +15,8 @@ class CardsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
redirect_to @collection.cards.create!
|
||||
card = @collection.cards.create!
|
||||
redirect_to card
|
||||
end
|
||||
|
||||
def show
|
||||
@@ -26,7 +27,7 @@ class CardsController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@card.destroy!
|
||||
redirect_to cards_path(collection_ids: [ @card.collection ]), notice: deleted_notice
|
||||
redirect_to cards_path(collection_ids: [ @card.collection ]), notice: ("Card deleted" unless @card.creating?)
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -50,8 +51,4 @@ class CardsController < ApplicationController
|
||||
def card_params
|
||||
params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ])
|
||||
end
|
||||
|
||||
def deleted_notice
|
||||
"Card deleted" unless @card.creating?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,12 +5,11 @@ class Collections::WorkflowsController < ApplicationController
|
||||
|
||||
def update
|
||||
@collection.update! workflow: @workflow
|
||||
|
||||
redirect_to cards_path(collection_ids: [ @collection ])
|
||||
end
|
||||
|
||||
private
|
||||
def set_workflow
|
||||
@workflow = Current.account.workflows.find(params.expect(collection: [ :workflow_id ]).require(:workflow_id))
|
||||
@workflow = Workflow.find(params.expect(collection: [ :workflow_id ]).require(:workflow_id))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,11 +2,11 @@ class CollectionsController < ApplicationController
|
||||
before_action :set_collection, except: %i[ new create ]
|
||||
|
||||
def new
|
||||
@collection = Current.account.collections.build
|
||||
@collection = Collection.new
|
||||
end
|
||||
|
||||
def create
|
||||
@collection = Current.account.collections.create! collection_params
|
||||
@collection = Collection.create! collection_params
|
||||
redirect_to cards_path(collection_ids: [ @collection ])
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ class CollectionsController < ApplicationController
|
||||
end
|
||||
|
||||
def grantees
|
||||
Current.account.users.active.where id: grantee_ids
|
||||
User.active.where id: grantee_ids
|
||||
end
|
||||
|
||||
def revokees
|
||||
|
||||
@@ -40,7 +40,7 @@ module Authentication
|
||||
|
||||
def request_authentication
|
||||
session[:return_to_after_authenticating] = request.url
|
||||
redirect_to new_session_url
|
||||
redirect_to new_session_path
|
||||
end
|
||||
|
||||
def after_authentication_url
|
||||
|
||||
@@ -11,6 +11,6 @@ module CardScoped
|
||||
end
|
||||
|
||||
def set_collection
|
||||
@collection = Current.user.collections.find(@card.collection_id)
|
||||
@collection = @card.collection
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,13 +19,9 @@ module EventsTimeline
|
||||
end
|
||||
|
||||
def events_for_activity_day
|
||||
user_events.where(created_at: @activity_day.all_day).
|
||||
group_by { |event| [ event.created_at.hour, helpers.event_column(event) ] }.
|
||||
map { |hour_col, events|
|
||||
[ hour_col,
|
||||
events.uniq { |e| e.action == "boosted" ? [ e.creator_id, e.card_id ] : e.id }
|
||||
]
|
||||
}
|
||||
user_events.where(created_at: @activity_day.all_day)
|
||||
.group_by { |event| [ event.created_at.hour, helpers.event_column(event) ] }
|
||||
.map { |hour_col, events| [ hour_col, events.uniq { |e| e.id } ] }
|
||||
end
|
||||
|
||||
def latest_event_before_activity_day
|
||||
@@ -33,12 +29,12 @@ module EventsTimeline
|
||||
end
|
||||
|
||||
def user_events
|
||||
Event.where(card: user_cards, creator: Current.account.users)
|
||||
Event.where(card: user_cards)
|
||||
end
|
||||
|
||||
def user_cards
|
||||
Current.user.accessible_cards
|
||||
.published_or_drafted_by(Current.user)
|
||||
.where(collection_id: collection_filter)
|
||||
.published_or_drafted_by(Current.user)
|
||||
.where(collection_id: collection_filter)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,6 @@ module WorkflowScoped
|
||||
|
||||
private
|
||||
def set_workflow
|
||||
@workflow = Current.account.workflows.find params[:workflow_id]
|
||||
@workflow = Workflow.find(params[:workflow_id])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,12 @@ class FiltersController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@filter.destroy!
|
||||
redirect_after_destroy
|
||||
|
||||
if request.referer == root_url
|
||||
redirect_to root_path
|
||||
else
|
||||
redirect_to cards_path(@filter.as_params)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
@@ -19,12 +24,4 @@ class FiltersController < ApplicationController
|
||||
def filter_params
|
||||
params.permit(*Filter::PERMITTED_PARAMS).compact_blank
|
||||
end
|
||||
|
||||
def redirect_after_destroy
|
||||
if request.referer == root_url
|
||||
redirect_to root_path
|
||||
else
|
||||
redirect_to cards_path(@filter.as_params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,17 +7,13 @@ class FirstRunsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
user = FirstRun.create!(user_params)
|
||||
user = FirstRun.create!(params.expect(user: [ :name, :email_address, :password ]))
|
||||
start_new_session_for user
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
def prevent_repeats
|
||||
redirect_to root_path unless Account.none?
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.expect(user: [ :name, :email_address, :password ])
|
||||
redirect_to root_path if Account.any?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,10 +2,7 @@ class QrCodesController < ApplicationController
|
||||
allow_unauthenticated_access
|
||||
|
||||
def show
|
||||
qr_code_link = QrCodeLink.from_signed(params[:id])
|
||||
svg = RQRCode::QRCode.new(qr_code_link.url).as_svg(viewbox: true, fill: :white, color: :black)
|
||||
|
||||
expires_in 1.year, public: true
|
||||
render plain: svg, content_type: "image/svg+xml"
|
||||
render svg: RQRCode::QRCode.new(QrCodeLink.from_signed(params[:id]).url).as_svg(viewbox: true, fill: :white, color: :black)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
class TerminalsController < ApplicationController
|
||||
def show
|
||||
@events = Event.where(card: user_cards, creator: Current.user).chronologically.reverse_order.limit(20)
|
||||
@events = Event.where(card: Current.user.accessible_cards, creator: Current.user).chronologically.reverse_order.limit(20)
|
||||
end
|
||||
|
||||
def edit
|
||||
@filter = Current.user.filters.from_params params.permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
|
||||
private
|
||||
def user_cards
|
||||
Current.user.accessible_cards
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,8 @@ class UploadsController < ApplicationController
|
||||
before_action :set_attachment, only: :show
|
||||
|
||||
def create
|
||||
@upload = Current.account.uploads_attachments.create! blob: create_blob!
|
||||
# FIXME: Try to get upload attachments on root
|
||||
@upload = Account.sole.uploads_attachments.create! blob: create_blob!
|
||||
end
|
||||
|
||||
def show
|
||||
|
||||
@@ -24,7 +24,7 @@ class Users::AvatarsController < ApplicationController
|
||||
end
|
||||
|
||||
def set_user
|
||||
@user = Current.account.users.find(params[:user_id])
|
||||
@user = User.find(params[:user_id])
|
||||
end
|
||||
|
||||
def render_avatar_or_initials
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
class Users::RolesController < ApplicationController
|
||||
before_action :set_user
|
||||
before_action :ensure_permission_to_administer_user
|
||||
|
||||
def update
|
||||
@user.update(role_params)
|
||||
redirect_to users_path
|
||||
end
|
||||
|
||||
private
|
||||
def set_user
|
||||
@user = User.active.find(params[:user_id])
|
||||
end
|
||||
|
||||
def ensure_permission_to_administer_user
|
||||
head :forbidden unless Current.user.can_administer?(@user)
|
||||
end
|
||||
|
||||
def role_params
|
||||
{ role: params.require(:user)[:role].presence_in(%w[ member admin ]) || "member" }
|
||||
end
|
||||
end
|
||||
@@ -1,15 +1,20 @@
|
||||
class UsersController < ApplicationController
|
||||
require_unauthenticated_access only: %i[ new create ]
|
||||
|
||||
before_action :set_user, only: %i[ show edit update ]
|
||||
before_action :set_user, only: %i[ show edit update destroy ]
|
||||
before_action :set_account_from_join_code, only: %i[ new create ]
|
||||
before_action :ensure_permission_to_administer_user, only: %i[ update destroy ]
|
||||
|
||||
def index
|
||||
@users = User.active
|
||||
end
|
||||
|
||||
def new
|
||||
@user = @account.users.build
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create
|
||||
user = @account.users.create!(user_params)
|
||||
user = User.create!(user_params)
|
||||
start_new_session_for user
|
||||
redirect_to root_path
|
||||
end
|
||||
@@ -21,8 +26,13 @@ class UsersController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
@user.update user_params
|
||||
redirect_to user_path(@user)
|
||||
@user.update! user_params
|
||||
redirect_to @user
|
||||
end
|
||||
|
||||
def destroy
|
||||
@user.deactivate
|
||||
redirect_to users_path
|
||||
end
|
||||
|
||||
private
|
||||
@@ -31,7 +41,11 @@ class UsersController < ApplicationController
|
||||
end
|
||||
|
||||
def set_user
|
||||
@user = Current.account.users.active.find(params[:id])
|
||||
@user = User.active.find(params[:id])
|
||||
end
|
||||
|
||||
def ensure_permission_to_administer_user
|
||||
head :forbidden unless Current.user.can_administer?(@user)
|
||||
end
|
||||
|
||||
def user_params
|
||||
|
||||
@@ -9,7 +9,7 @@ class Workflows::StagesController < ApplicationController
|
||||
|
||||
def create
|
||||
@stage = @workflow.stages.create! stage_params
|
||||
redirect_to workflow_path(@workflow)
|
||||
redirect_to @workflow
|
||||
end
|
||||
|
||||
def edit
|
||||
@@ -17,12 +17,12 @@ class Workflows::StagesController < ApplicationController
|
||||
|
||||
def update
|
||||
@stage.update! stage_params
|
||||
redirect_to workflow_path(@workflow)
|
||||
redirect_to @workflow
|
||||
end
|
||||
|
||||
def destroy
|
||||
@stage.destroy
|
||||
redirect_to workflow_path(@workflow)
|
||||
redirect_to @workflow
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -2,15 +2,15 @@ class WorkflowsController < ApplicationController
|
||||
before_action :set_workflow, only: %i[ show edit update destroy ]
|
||||
|
||||
def index
|
||||
@workflows = Current.account.workflows
|
||||
@workflows = Workflow.all
|
||||
end
|
||||
|
||||
def new
|
||||
@workflow = Current.account.workflows.new
|
||||
@workflow = Workflow.new
|
||||
end
|
||||
|
||||
def create
|
||||
@workflow = Current.account.workflows.create! workflow_params
|
||||
@workflow = Workflow.create! workflow_params
|
||||
# FIXME: this should definitely change.
|
||||
[ "Triage", "In progress", "On Hold", "Review" ].each { |name| @workflow.stages.create! name: name }
|
||||
redirect_to workflows_path
|
||||
@@ -24,7 +24,7 @@ class WorkflowsController < ApplicationController
|
||||
|
||||
def update
|
||||
@workflow.update! workflow_params
|
||||
redirect_to workflow_path(@workflow)
|
||||
redirect_to @workflow
|
||||
end
|
||||
|
||||
def destroy
|
||||
@@ -34,10 +34,10 @@ class WorkflowsController < ApplicationController
|
||||
|
||||
private
|
||||
def set_workflow
|
||||
@workflow = Current.account.workflows.find params[:id]
|
||||
@workflow = Workflow.find params[:id]
|
||||
end
|
||||
|
||||
def workflow_params
|
||||
params.expect workflow: [ :name ]
|
||||
params.expect workflow: :name
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,9 +4,6 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def icon_tag(name, **options)
|
||||
classes = class_names "icon icon--#{name}", options.delete(:class)
|
||||
options["aria-hidden"] = true
|
||||
|
||||
content_tag :span, "", class: classes, **options
|
||||
tag.span class: class_names("icon icon--#{name}", options.delete(:class)), "aria-hidden": true, **options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
module CardsHelper
|
||||
CARD_ROTATION = %w[ 75 60 45 35 25 5 ]
|
||||
|
||||
def card_title(card)
|
||||
card.title.presence || "Untitled"
|
||||
end
|
||||
|
||||
def card_rotation(card)
|
||||
value = CARD_ROTATION[Zlib.crc32(card.to_param) % CARD_ROTATION.size]
|
||||
|
||||
"--card-rotate: #{value}deg;"
|
||||
end
|
||||
|
||||
def cards_next_page_link(target, page:, filter:, fetch_on_visible: false, data: {}, **options)
|
||||
url = cards_previews_path(target: target, page: page.next_param, **filter.as_params)
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
module CommentsHelper
|
||||
def comment_tag(comment, &)
|
||||
tag.div id: dom_id(comment), class: "comment flex align-start full-width",
|
||||
data: { creator_id: comment.creator_id, created_by_current_user_target: "creation" }, &
|
||||
end
|
||||
|
||||
def new_comment_placeholder(card)
|
||||
if card.creator == Current.user && card.messages.comments.empty?
|
||||
"Next, add some notes, context, pictures, or video about this…"
|
||||
|
||||
@@ -66,32 +66,30 @@ module EventsHelper
|
||||
case event.action
|
||||
when "assigned"
|
||||
if event.assignees.include?(Current.user)
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } will handle <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } will handle <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
else
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } assigned #{ event.assignees.pluck(:name).to_sentence } to <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } assigned #{ event.assignees.pluck(:name).to_sentence } to <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
end
|
||||
when "unassigned"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } unassigned #{ event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence } from <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
when "boosted"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } boosted <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } unassigned #{ event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence } from <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "commented"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } commented on <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } commented on <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "published"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } added <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } added <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "closed"
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } closed <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{ event.creator == Current.user ? "You" : event.creator.name } closed <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "staged"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} moved <span style='color: var(--card-color)'>#{ card_title(event.card) }</span> to the #{event.stage_name} stage".html_safe
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} moved <span style='color: var(--card-color)'>#{ event.card.title }</span> to the #{event.stage_name} stage".html_safe
|
||||
when "unstaged"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} moved <span style='color: var(--card-color)'>#{ card_title(event.card) }</span> out ofthe #{event.stage_name} stage".html_safe
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} moved <span style='color: var(--card-color)'>#{ event.card.title }</span> out ofthe #{event.stage_name} stage".html_safe
|
||||
when "due_date_added"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} set the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} set the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "due_date_changed"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} changed the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>".html_safe
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} changed the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ event.card.title }</span>".html_safe
|
||||
when "due_date_removed"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} removed the date on <span style='color: var(--card-color)'>#{ card_title(event.card) }</span>"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} removed the date on <span style='color: var(--card-color)'>#{ event.card.title }</span>"
|
||||
when "title_changed"
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} renamed <span style='color: var(--card-color)'>#{ card_title(event.card) }</span> (was: '#{event.particulars.dig('particulars', 'old_title')})'".html_safe
|
||||
"#{event.creator == Current.user ? "You" : event.creator.name} renamed <span style='color: var(--card-color)'>#{ event.card.title }</span> (was: '#{event.particulars.dig('particulars', 'old_title')})'".html_safe
|
||||
end
|
||||
end
|
||||
|
||||
@@ -99,8 +97,6 @@ module EventsHelper
|
||||
case event.action
|
||||
when "assigned"
|
||||
"assigned"
|
||||
when "boosted"
|
||||
"thumb-up"
|
||||
when "staged"
|
||||
"bolt"
|
||||
when "unstaged"
|
||||
|
||||
@@ -2,7 +2,7 @@ module MessagesHelper
|
||||
def messages_tag(card, &)
|
||||
turbo_frame_tag dom_id(card, :messages),
|
||||
class: "comments gap center",
|
||||
style: "--card-color: <%= card.color %>",
|
||||
style: "--card-color: #{card.color}",
|
||||
role: "group", aria: { label: "Messages" },
|
||||
data: {
|
||||
controller: "created-by-current-user",
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
module NotificationsHelper
|
||||
def notification_title(notification)
|
||||
title = card_title(notification.card)
|
||||
|
||||
if notification.resource.is_a? Comment
|
||||
"RE: " + title
|
||||
"RE: " + notification.card.title
|
||||
elsif notification_event_action(notification) == "assigned"
|
||||
"Assigned to you: " + title
|
||||
"Assigned to you: " + notification.card.title
|
||||
else
|
||||
title
|
||||
end
|
||||
|
||||
+1
-17
@@ -1,21 +1,5 @@
|
||||
class Account < ApplicationRecord
|
||||
include ClosureReasons, Joinable
|
||||
|
||||
has_many :collections, dependent: :destroy
|
||||
has_many :cards, through: :collections
|
||||
|
||||
has_many :users, dependent: :destroy do
|
||||
def system
|
||||
find_or_create_system_user(proxy_association.owner)
|
||||
end
|
||||
end
|
||||
|
||||
has_many :comments, through: :users
|
||||
|
||||
has_many :workflows, dependent: :destroy
|
||||
has_many :stages, through: :workflows, class_name: "Workflow::Stage"
|
||||
|
||||
has_many :tags, dependent: :destroy
|
||||
include Joinable
|
||||
|
||||
has_many_attached :uploads
|
||||
end
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
module Account::ClosureReasons
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
DEFAULT_LABELS = [
|
||||
"Completed",
|
||||
"Duplicate",
|
||||
"Maybe later",
|
||||
"Working as intended"
|
||||
]
|
||||
|
||||
FALLBACK_LABEL = "Done"
|
||||
|
||||
included do
|
||||
has_many :closure_reasons, dependent: :destroy, class_name: "Closure::Reason" do
|
||||
def labels
|
||||
pluck(:label).presence || [ FALLBACK_LABEL ]
|
||||
end
|
||||
end
|
||||
|
||||
after_create :create_default_closure_reasons
|
||||
end
|
||||
|
||||
private
|
||||
def create_default_closure_reasons
|
||||
DEFAULT_LABELS.each do |label|
|
||||
closure_reasons.create! label: label
|
||||
end
|
||||
end
|
||||
end
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
class Card < ApplicationRecord
|
||||
include Assignable, Boostable, Colored, Commentable, Engageable, Eventable, Golden,
|
||||
include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden,
|
||||
Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged,
|
||||
Statuses, Taggable, Watchable
|
||||
|
||||
@@ -22,8 +22,6 @@ class Card < ApplicationRecord
|
||||
scope :indexed_by, ->(index) do
|
||||
case index
|
||||
when "most_active" then ordered_by_activity
|
||||
when "most_discussed" then ordered_by_comments
|
||||
when "most_boosted" then ordered_by_boosts
|
||||
when "newest" then reverse_chronologically
|
||||
when "oldest" then chronologically
|
||||
when "latest" then latest
|
||||
@@ -39,6 +37,10 @@ class Card < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def title=(new_title)
|
||||
self[:title] = new_title.presence || "Untitled"
|
||||
end
|
||||
|
||||
def cache_key
|
||||
[ super, collection&.name ].compact.join("/")
|
||||
end
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
module Card::Boostable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
scope :ordered_by_boosts, -> { order boosts_count: :desc }
|
||||
end
|
||||
|
||||
def boost!(count = 1)
|
||||
count = count.to_i
|
||||
count = 1 if count < 1
|
||||
|
||||
transaction do
|
||||
track_event :boosted, count: count
|
||||
update! boosts_count: count
|
||||
rescore
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,7 +16,7 @@ module Card::Closeable
|
||||
class_methods do
|
||||
def auto_close_all_due
|
||||
due_to_be_closed.find_each do |card|
|
||||
card.close(user: card.collection.account.users.system, reason: "Closed")
|
||||
card.close(user: User.system, reason: "Closed")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -41,7 +41,7 @@ module Card::Closeable
|
||||
closure&.created_at
|
||||
end
|
||||
|
||||
def close(user: Current.user, reason: Account::ClosureReasons::FALLBACK_LABEL)
|
||||
def close(user: Current.user, reason: Closure::Reason::FALLBACK_LABEL)
|
||||
unless closed?
|
||||
transaction do
|
||||
create_closure! user: user, reason: reason
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
module Card::Commentable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
scope :ordered_by_comments, -> { order comments_count: :desc }
|
||||
end
|
||||
|
||||
def comment_created(comment)
|
||||
increment! :comments_count
|
||||
watch_by comment.creator
|
||||
|
||||
track_event :commented, comment_id: comment.id
|
||||
rescore
|
||||
end
|
||||
|
||||
def comment_destroyed
|
||||
decrement! :comments_count
|
||||
rescore
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
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
|
||||
@@ -10,14 +10,14 @@ module Card::Eventable
|
||||
touch :last_active_at
|
||||
end
|
||||
|
||||
private
|
||||
def track_event(action, creator: Current.user, **particulars)
|
||||
if published?
|
||||
event = find_or_capture_event_summary.events.create! action: action, creator: creator, card: self, particulars: particulars
|
||||
event.generate_notifications_later
|
||||
end
|
||||
def track_event(action, creator: Current.user, **particulars)
|
||||
if published?
|
||||
event = find_or_capture_event_summary.events.create! action: action, creator: creator, card: self, particulars: particulars
|
||||
event.generate_notifications_later
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def find_or_capture_event_summary
|
||||
transaction do
|
||||
messages.last&.event_summary || capture(EventSummary.new).event_summary
|
||||
|
||||
@@ -3,35 +3,9 @@ module Card::Messages
|
||||
|
||||
included do
|
||||
has_many :messages, -> { chronologically }, dependent: :destroy
|
||||
after_save :capture_draft_comment
|
||||
end
|
||||
|
||||
def capture(messageable)
|
||||
messages.create! messageable: messageable
|
||||
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
|
||||
|
||||
@@ -36,7 +36,6 @@ module Card::Scorable
|
||||
|
||||
def event_weight(event)
|
||||
case
|
||||
when event.boosted? then 1
|
||||
when event.comment&.first_by_author_on_card? then 20
|
||||
when event.comment&.follows_comment_by_another_author? then 15
|
||||
when event.commented? then 10
|
||||
@@ -60,6 +59,6 @@ module Card::Scorable
|
||||
end
|
||||
|
||||
def scorable_events
|
||||
events.where(action: [ :commented, :boosted ])
|
||||
events.where(action: :commented)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@ module Card::Taggable
|
||||
end
|
||||
|
||||
def toggle_tag_with(title)
|
||||
tag = collection.account.tags.find_or_create_by!(title: title)
|
||||
tag = Tag.find_or_create_by!(title: title)
|
||||
|
||||
transaction do
|
||||
if tagged_with?(tag)
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
class Closure::Reason < ApplicationRecord
|
||||
belongs_to :account
|
||||
DEFAULT_LABELS = [
|
||||
"Completed",
|
||||
"Duplicate",
|
||||
"Maybe later",
|
||||
"Working as intended"
|
||||
]
|
||||
|
||||
FALLBACK_LABEL = "Done"
|
||||
|
||||
class << self
|
||||
def labels
|
||||
pluck(:label).presence || [ FALLBACK_LABEL ]
|
||||
end
|
||||
|
||||
def create_defaults
|
||||
DEFAULT_LABELS.each do |label|
|
||||
create! label: label
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
class Collection < ApplicationRecord
|
||||
include Accessible, Broadcastable, Filterable
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
||||
belongs_to :workflow, optional: true
|
||||
|
||||
|
||||
@@ -34,6 +34,6 @@ module Collection::Accessible
|
||||
|
||||
private
|
||||
def grant_access_to_everyone
|
||||
accesses.grant_to(account.users) if all_access_previously_changed?(to: true)
|
||||
accesses.grant_to(User.all) if all_access_previously_changed?(to: true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,6 @@ module Collection::Broadcastable
|
||||
|
||||
included do
|
||||
broadcasts_refreshes
|
||||
broadcasts_refreshes_to ->(collection) { [ collection.account, :collections ] }
|
||||
broadcasts_refreshes_to ->(_) { :collections }
|
||||
end
|
||||
end
|
||||
|
||||
+16
-25
@@ -1,43 +1,34 @@
|
||||
class Comment < ApplicationRecord
|
||||
include Messageable, Notifiable, Searchable
|
||||
include Messageable, Searchable
|
||||
|
||||
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
||||
has_many :reactions, dependent: :destroy
|
||||
|
||||
searchable_by :body_plain_text, using: :comments_search_index, as: :body
|
||||
has_many :reactions, dependent: :delete_all
|
||||
|
||||
has_markdown :body
|
||||
searchable_by :body_plain_text, using: :comments_search_index, as: :body
|
||||
|
||||
before_destroy :cleanup_events
|
||||
# FIXME: Not a fan of this. Think all references to comment should come directly from the message.
|
||||
scope :belonging_to_card, ->(card) { joins(:message).where(messages: { card_id: card.id }) }
|
||||
|
||||
def first_by_author_on_card?
|
||||
card_comments.many? && card_comments_prior.where(creator_id: creator_id).none?
|
||||
end
|
||||
|
||||
def follows_comment_by_another_author?
|
||||
card_comments.many? && card_comments_prior.last&.creator != creator
|
||||
end
|
||||
after_create_commit :watch_card_by_creator, :track_commented_card
|
||||
after_destroy_commit :cleanup_events
|
||||
|
||||
def to_partial_path
|
||||
"cards/#{super}"
|
||||
end
|
||||
|
||||
private
|
||||
def cleanup_events
|
||||
# Delete events that reference through event_summary
|
||||
if message&.event_summary.present?
|
||||
Event.where(summary: message.event_summary).destroy_all
|
||||
end
|
||||
def watch_card_by_creator
|
||||
card.watch_by creator
|
||||
end
|
||||
|
||||
def track_commented_card
|
||||
card.track_event :commented, comment_id: id
|
||||
end
|
||||
|
||||
# FIXME: This isn't right. We need to introduce an eventable polymorphic association for this.
|
||||
def cleanup_events
|
||||
# Delete events that reference directly in particulars
|
||||
Event.where(particulars: { comment_id: id }).destroy_all
|
||||
end
|
||||
|
||||
def card_comments_prior
|
||||
card_comments.where(created_at: ...created_at)
|
||||
end
|
||||
|
||||
def card_comments
|
||||
Comment.joins(:message).where(messages: { card: card })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,5 +2,4 @@ class Current < ActiveSupport::CurrentAttributes
|
||||
attribute :session
|
||||
|
||||
delegate :user, to: :session, allow_nil: true
|
||||
delegate :account, to: :user, allow_nil: true
|
||||
end
|
||||
|
||||
@@ -5,21 +5,13 @@ class Event < ApplicationRecord
|
||||
belongs_to :summary, touch: true, class_name: "EventSummary"
|
||||
belongs_to :card
|
||||
|
||||
has_one :account, through: :creator
|
||||
has_one :message, through: :summary
|
||||
has_one :comment, through: :message, source: :messageable, source_type: "Comment"
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
scope :non_boosts, -> { where.not action: :boosted }
|
||||
scope :boosts, -> { where action: :boosted }
|
||||
scope :comments, -> { where action: :commented }
|
||||
|
||||
after_create -> { card.touch_last_active_at }
|
||||
|
||||
def boosted?
|
||||
action == "boosted"
|
||||
end
|
||||
|
||||
def commented?
|
||||
action == "commented"
|
||||
end
|
||||
|
||||
@@ -6,10 +6,10 @@ module Event::Particulars
|
||||
end
|
||||
|
||||
def assignees
|
||||
@assignees ||= account.users.where id: assignee_ids
|
||||
@assignees ||= User.where id: assignee_ids
|
||||
end
|
||||
|
||||
def comment
|
||||
@comment ||= account.comments.find_by(id: comment_id)
|
||||
@comment ||= Comment.find_by id: comment_id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,16 +5,12 @@ class EventSummary < ApplicationRecord
|
||||
|
||||
# FIXME: Consider persisting the body and compute at write time.
|
||||
def body
|
||||
"#{main_summary} #{boosts_summary}".squish
|
||||
events.map { |event| summarize(event) }.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
delegate :time_ago_in_words, to: "ApplicationController.helpers"
|
||||
|
||||
def main_summary
|
||||
events.non_boosts.map { |event| summarize(event) }.join(" ")
|
||||
end
|
||||
|
||||
def summarize(event)
|
||||
case event.action
|
||||
when "published"
|
||||
@@ -39,12 +35,4 @@ class EventSummary < ApplicationRecord
|
||||
"#{event.creator.name} changed title from '#{event.particulars.dig('particulars', 'old_title')}' to '#{event.particulars.dig('particulars', 'new_title')}'."
|
||||
end
|
||||
end
|
||||
|
||||
def boosts_summary
|
||||
if tally = events.boosts.group(:creator).count.presence
|
||||
tally.map do |creator, count|
|
||||
"#{creator.name} +#{count}"
|
||||
end.to_sentence + "."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module Filter::Fields
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
INDEXES = %w[ most_discussed most_boosted newest oldest latest stalled ]
|
||||
INDEXES = %w[ newest oldest latest stalled ]
|
||||
|
||||
delegate :default_value?, to: :class
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class FirstRun
|
||||
def self.create!(user_attributes)
|
||||
account = Account.create!(name: "Fizzy")
|
||||
account.users.member.create!(user_attributes)
|
||||
Account.create!(name: "Fizzy")
|
||||
Closure::Reason.create_defaults
|
||||
User.member.create!(user_attributes)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,16 +4,4 @@ class Message < ApplicationRecord
|
||||
delegated_type :messageable, types: Messageable::TYPES, inverse_of: :message, dependent: :destroy
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
|
||||
after_create :created
|
||||
after_destroy :destroyed
|
||||
|
||||
private
|
||||
def created
|
||||
card.comment_created(comment) if comment?
|
||||
end
|
||||
|
||||
def destroyed
|
||||
card.comment_destroyed if comment?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,8 +4,6 @@ class Reaction < ApplicationRecord
|
||||
|
||||
scope :ordered, -> { order(:created_at) }
|
||||
|
||||
validates_presence_of :content
|
||||
|
||||
def all_emoji?
|
||||
content.match? /\A(\p{Emoji_Presentation}|\p{Extended_Pictographic}|\uFE0F)+\z/u
|
||||
end
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
class Tag < ApplicationRecord
|
||||
include Filterable
|
||||
|
||||
belongs_to :account, default: -> { Current.account }, touch: true
|
||||
|
||||
has_many :taggings, dependent: :destroy
|
||||
has_many :cards, through: :taggings
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
class User < ApplicationRecord
|
||||
include Accessor, Assignee, Avatar, Role, Transferable
|
||||
|
||||
belongs_to :account
|
||||
|
||||
has_many :sessions, dependent: :destroy
|
||||
has_secure_password validations: false
|
||||
|
||||
|
||||
@@ -11,6 +11,6 @@ module User::Accessor
|
||||
|
||||
private
|
||||
def grant_access_to_collections
|
||||
Access.insert_all account.collections.all_access.pluck(:id).collect { |collection_id| { collection_id: collection_id, user_id: id } }
|
||||
Access.insert_all Collection.all_access.pluck(:id).collect { |collection_id| { collection_id: collection_id, user_id: id } }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,10 +10,8 @@ module User::Role
|
||||
end
|
||||
|
||||
class_methods do
|
||||
def find_or_create_system_user(account)
|
||||
account.users.find_or_create_by!(role: :system) do |user|
|
||||
user.name = "System"
|
||||
end
|
||||
def system
|
||||
find_or_create_by!(role: :system) { it.name = "System" }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
class Workflow < ApplicationRecord
|
||||
belongs_to :account
|
||||
has_many :stages, dependent: :delete_all
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<%= icon_tag "caret-down" %>
|
||||
</summary>
|
||||
<div class="expander__content btn borderless">
|
||||
<% Current.account.closure_reasons.labels.each do |label| %>
|
||||
<% Closure::Reason.labels.each do |label| %>
|
||||
<%= button_to card_closure_path(card, reason: label), class: "expander__item btn" do %>
|
||||
<span class="overflow-ellipsis"><%= label %></span>
|
||||
<% end %>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= messages_tag(card) do %>
|
||||
<%= render partial: "messages/message", collection: card.messages, cached: true %>
|
||||
<%= render "cards/comments/new", card: card, cached: true %>
|
||||
<%= render partial: "cards/messages/message", collection: card.messages, cached: true %>
|
||||
<%= render "cards/comments/new", card: card %>
|
||||
|
||||
<div class="comments__subscribers flex flex-column margin-block txt-align-start full-width">
|
||||
<strong class="txt-uppercase">Subscribers</strong>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<%= form_with url: card_boosts_path(card), class: "pad-inline flex align-center gap" do %>
|
||||
<span class="overflow-ellipsis">
|
||||
<strong><%= number_field_tag :boost_count, card.boosts_count, min: 1, class: "boost__input input", autocomplete: "off" %></strong>
|
||||
<span><%= card.boosts_count == 1 ? "boost" : "boosts" %></span>
|
||||
</span>
|
||||
<%= tag.button class: "btn", type: :submit, style: "font-size: 0.4em" do %>
|
||||
<%= icon_tag "add" %>
|
||||
<span class="for-screen-reader">Boost</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -1,7 +0,0 @@
|
||||
<%= turbo_stream.update dom_id(@card, :boosts) do %>
|
||||
<%= render "cards/boosts/boosts", card: @card %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.replace dom_id(@card, :messages) do %>
|
||||
<%= render "cards/messages", card: @card %>
|
||||
<% end %>
|
||||
@@ -1,26 +0,0 @@
|
||||
<% cache comment do %>
|
||||
<%= turbo_frame_tag dom_id(comment) do %>
|
||||
<div class="comment__content flex flex-column flex-item-grow full-width">
|
||||
<div class="comment__author flex align-center gap-half">
|
||||
<strong>
|
||||
<%= link_to comment.creator.name, user_path(comment.creator), class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %>
|
||||
</strong>
|
||||
|
||||
<%= link_to card_path(comment.card, anchor: "comment_#{comment.id}"), class: "txt-undecorated txt-uppercase" do %>
|
||||
<%= local_datetime_tag comment.created_at, style: :shortdate, class: "txt-ink translucent" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to edit_card_comment_path(comment.card, comment),
|
||||
class: "comment__edit btn btn--plain txt-xx-small fill-transparent translucent flex-item-justify-end" do %>
|
||||
<%= icon_tag "menu-dots-horizontal" %>
|
||||
<span class="for-screen-reader">Edit this comment</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="comment__body txt-align-start">
|
||||
<%= sanitize comment.body_html %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/comments/reactions/reactions", comment: comment %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -1,7 +1,32 @@
|
||||
<%= comment_tag comment do %>
|
||||
<figure class="comment__avatar flex-item-no-shrink" aria-hidden="true">
|
||||
<%= avatar_tag comment.creator, hidden_for_screen_reader: true %>
|
||||
</figure>
|
||||
<% cache 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">
|
||||
<figure class="comment__avatar flex-item-no-shrink" aria-hidden="true">
|
||||
<%= avatar_tag comment.creator, hidden_for_screen_reader: true %>
|
||||
</figure>
|
||||
|
||||
<%= render "cards/comments/body", comment: comment %>
|
||||
<div class="comment__content flex flex-column flex-item-grow full-width">
|
||||
<div class="comment__author flex align-center gap-half">
|
||||
<strong>
|
||||
<%= link_to comment.creator.name, comment.creator, class: "txt-ink btn btn--plain fill-transparent", data: { turbo_frame: "_top" } %>
|
||||
</strong>
|
||||
|
||||
<%= link_to card_path(comment.card, anchor: "comment_#{comment.id}"), class: "txt-undecorated txt-uppercase" do %>
|
||||
<%= local_datetime_tag comment.created_at, style: :shortdate, class: "txt-ink translucent" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to edit_card_comment_path(comment.card, comment),
|
||||
class: "comment__edit btn btn--plain txt-xx-small fill-transparent translucent flex-item-justify-end" do %>
|
||||
<%= icon_tag "menu-dots-horizontal" %> <span class="for-screen-reader">Edit this comment</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="comment__body txt-align-start">
|
||||
<%= sanitize comment.body_html %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/comments/reactions/reactions", comment: comment %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
<% cache reaction do %>
|
||||
<div id="<%= dom_id(reaction) %>"
|
||||
class="reaction flex-inline postion--relative max-width align-center fill-white gap"
|
||||
data-controller="reaction-delete"
|
||||
data-reaction-delete-reacter-id-value="<%= reaction.reacter.id %>"
|
||||
data-controller="reaction-delete" data-reaction-delete-perform-class="reaction--deleting"
|
||||
data-reaction-delete-reveal-class="expanded" data-reaction-delete-reacter-id-value="<%= reaction.reacter.id %>">
|
||||
<figure class="reaction__avatar margin-none flex-item-no-shrink">
|
||||
<%= avatar_tag reaction.reacter, aria: { label: "#{reaction.reacter.name} reacted #{reaction.content}" } %>
|
||||
</figure>
|
||||
<div id="<%= dom_id(reaction) %>"
|
||||
class="reaction flex-inline postion--relative max-width align-center fill-white gap"
|
||||
data-controller="reaction-delete"
|
||||
data-reaction-delete-reacter-id-value="<%= reaction.reacter.id %>"
|
||||
data-controller="reaction-delete" data-reaction-delete-perform-class="reaction--deleting"
|
||||
data-reaction-delete-reveal-class="expanded" data-reaction-delete-reacter-id-value="<%= reaction.reacter.id %>">
|
||||
<figure class="reaction__avatar margin-none flex-item-no-shrink">
|
||||
<%= avatar_tag reaction.reacter, aria: { label: "#{reaction.reacter.name} reacted #{reaction.content}" } %>
|
||||
</figure>
|
||||
|
||||
<%= tag.span reaction.content, role: "button",
|
||||
class: [ "txt-small", { "txt-medium": reaction.all_emoji? } ],
|
||||
data: { action: "click->reaction-delete#reveal keydown.enter->reaction-delete#reveal:prevent", reaction_delete_target: "content" } %>
|
||||
<%= tag.span reaction.content, role: "button",
|
||||
class: [ "txt-small", { "txt-medium": reaction.all_emoji? } ],
|
||||
data: { action: "click->reaction-delete#reveal keydown.enter->reaction-delete#reveal:prevent", reaction_delete_target: "content" } %>
|
||||
|
||||
<%= button_to card_comment_reaction_path(comment.card, comment, reaction),
|
||||
method: :delete,
|
||||
class: "btn btn--negative flex-item-justify-end reaction__delete",
|
||||
data: { action: "reaction-delete#perform", reaction_delete_target: "button" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Delete this reaction</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<span id="delete_reaction_accessible_label" class="for-screen-reader">Press enter to delete this reaction</span>
|
||||
<% end %>
|
||||
<%= button_to card_comment_reaction_path(reaction.comment.card, reaction.comment, reaction),
|
||||
method: :delete,
|
||||
class: "btn btn--negative flex-item-justify-end reaction__delete",
|
||||
data: { action: "reaction-delete#perform", reaction_delete_target: "button" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Delete this reaction</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<span id="delete_reaction_accessible_label" class="for-screen-reader">Press enter to delete this reaction</span>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
<%= turbo_frame_tag comment, :reacting do %>
|
||||
<%= turbo_stream_from comment, :comments %>
|
||||
<div class="reactions flex flex-wrap align-center gap full-width">
|
||||
<div class="flex-inline flex-wrap gap" id="<%= dom_id(comment, :reactions) %>" data-turbo-streaming-target="container">
|
||||
<%= render partial: "cards/comments/reactions/reaction", collection: comment.reactions.ordered, locals: { comment: comment }, cached: true %>
|
||||
<div id="<%= dom_id(comment, :reactions) %>" class="flex-inline flex-wrap gap">
|
||||
<%= render partial: "cards/comments/reactions/reaction", collection: comment.reactions.includes(:reacter).ordered %>
|
||||
</div>
|
||||
|
||||
<%= turbo_frame_tag comment, :new_reaction do %>
|
||||
<div class="flex-inline" data-controller="soft-keyboard">
|
||||
<%= link_to new_card_comment_reaction_path(comment.card, comment), role: "button",
|
||||
class: "btn reaction__action", action: "soft-keyboard#open" do %>
|
||||
<%= icon_tag "reaction" %>
|
||||
<span class="for-screen-reader">Add a reaction</span>
|
||||
<%= icon_tag "reaction" %> <span class="for-screen-reader">Add a reaction</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%= turbo_frame_tag dom_id(@comment, :new_reaction) do %>
|
||||
<%= form_with url: card_comment_reactions_path(@comment.card, @comment),
|
||||
<%= turbo_frame_tag @comment, :new_reaction do %>
|
||||
<%= form_with model: [ @comment.card, @comment, Reaction.new ],
|
||||
class: "reaction reaction__form flex-inline postion--relative max-width align-center fill-white gap expanded",
|
||||
html: { aria: { label: "New reaction" } },
|
||||
data: { controller: "form", turbo_frame: dom_id(@comment, :reacting), action: "keydown.esc->form#cancel" } do |form| %>
|
||||
@@ -7,20 +7,18 @@
|
||||
<figure class="reaction__avatar margin-none flex-item-no-shrink">
|
||||
<%= avatar_tag Current.user %>
|
||||
</figure>
|
||||
<%= form.text_field :content, name: "reaction[content]", autofocus: true, autocomplete: "off", autocorrect: "off", maxlength: 16,
|
||||
required: true, pattern: /\S+.*/, class: "input reaction__input txt-small",
|
||||
aria: { label: "Add a reaction" } %>
|
||||
|
||||
<%= form.text_field :content, autofocus: true, autocomplete: "off", autocorrect: "off", maxlength: 16,
|
||||
required: true, pattern: /\S+.*/, class: "input reaction__input txt-small", aria: { label: "Add a reaction" } %>
|
||||
</label>
|
||||
|
||||
<%= form.button class: "btn btn--reversed", type: "submit" do %>
|
||||
<%= icon_tag "check" %>
|
||||
<span class="for-screen-reader">Submit</span>
|
||||
<%= icon_tag "check" %> <span class="for-screen-reader">Submit</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to card_comment_reactions_path(@comment.card, @comment), role: "button",
|
||||
data: { turbo_frame: dom_id(@comment, :reactions), form_target: "cancel" }, class: "btn btn--negative" do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Cancel</span>
|
||||
data: { turbo_frame: dom_id(@comment, :reacting), form_target: "cancel" }, class: "btn btn--negative" do %>
|
||||
<%= icon_tag "minus" %> <span class="for-screen-reader">Cancel</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<%= render "cards/comments/body", comment: @comment %>
|
||||
<%= render "cards/comments/comment", comment: @comment %>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<%= render "cards/comments/body", comment: @comment %>
|
||||
<%= render "cards/comments/comment", comment: @comment %>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<h1 class="card__title">
|
||||
<% if card.published? %>
|
||||
<%= turbo_frame_tag card, :edit do %>
|
||||
<%= link_to card_title(card), edit_collection_card_path(card.collection, card), class: "card__title-link overflow-line-clamp" %>
|
||||
<%= 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| %>
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
<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(card) %></span>
|
||||
<span class="card__title-link overflow-line-clamp"><%= card.title %></span>
|
||||
</h1>
|
||||
|
||||
<%= link_to collection_card_path(card.collection, card), class: "card__link" do %>
|
||||
<span class="for-screen-reader"><%= card_title(card) %></span>
|
||||
<span class="for-screen-reader"><%= card.title %></span>
|
||||
<% end %>
|
||||
|
||||
<%= render "cards/stagings/stages", card: card if card.doing? %>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<%= 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" %>
|
||||
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 %>
|
||||
<%= link_to "Close editor and discard changes", collection_card_path(@card.collection, @card), data: { form_target: "cancel" }, hidden: true %>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<% @page_title = card_title(@card) %>
|
||||
<% @page_title = @card.title %>
|
||||
<%= turbo_stream_from @card %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<% if @card.creating? && @card.can_recover_abandoned_creation? %>
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<strong class="txt-large">Choose a workflow</strong>
|
||||
<p class="margin-none">Use a workflow to track progress in this collection.</p>
|
||||
<%= form_with model: @collection, url: collection_workflow_path(@collection), local: true, method: :patch, data: { controller: "form" } do |form| %>
|
||||
<%= form.select :workflow_id, Current.account.workflows.map { |w| [w.name, w.id] }, { include_blank: "Choose…" }, class: "input input--select full-width", data: { action: "change->form#submit" } %>
|
||||
<%= form.select :workflow_id, Workflow.all.map { |w| [w.name, w.id] }, { include_blank: "Choose…" }, class: "input input--select full-width", data: { action: "change->form#submit" } %>
|
||||
<% end %>
|
||||
<p><%= link_to "Manage workflows", workflows_path, class: "btn btn--plain txt-link" %></p>
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
<div class="btn btn--circle btn--placeholder flex-item-justify-start"></div>
|
||||
|
||||
<div class="events__index-header flex-inline flex-column center gap-half margin-block-end-double txt-align-center">
|
||||
<h2 class="txt-large txt-nowrap center"><%= Current.account.name %> / Latest activity</h2>
|
||||
<h2 class="txt-large txt-nowrap center"><%= Account.sole.name %> / Latest activity</h2>
|
||||
<%= render "events/filter" %>
|
||||
</div>
|
||||
|
||||
<%= link_to account_users_path, class: "btn flex-item-justify-end" do %>
|
||||
<%= link_to users_path, class: "btn flex-item-justify-end" do %>
|
||||
<%= icon_tag "settings" %>
|
||||
<span class="for-screen-reader">Account settings</span>
|
||||
<% end %>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
</div>
|
||||
|
||||
<% Current.account.users.active.order(:name).each do |user| %>
|
||||
<% User.active.order(:name).each do |user| %>
|
||||
<div class="btn popup__item">
|
||||
<%= form.check_box "assignee_ids[]", {
|
||||
checked: filter.assignees.include?(user),
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
<%= turbo_stream_from collection %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= turbo_stream_from Current.account, :collections %>
|
||||
<%= turbo_stream_from :collections %>
|
||||
<% end %>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
||||
</div>
|
||||
|
||||
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
|
||||
<% User.active.without(Current.user).order(:name).each do |user| %>
|
||||
<div class="btn popup__item">
|
||||
<%= form.check_box :creator_ids, {
|
||||
multiple: true,
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<% end %>
|
||||
</menu>
|
||||
|
||||
<% if workflow = Current.account.workflows.first %>
|
||||
<% if workflow = Workflow.first %>
|
||||
<menu class="filter__menu">
|
||||
<li class="filter__label"><strong>In Stage</strong></li>
|
||||
<% workflow.stages.each do |stage| %>
|
||||
@@ -93,7 +93,7 @@
|
||||
</menu>
|
||||
<% end %>
|
||||
|
||||
<% if (tags = Current.account.tags.order(:title)).any? %>
|
||||
<% if (tags = Tag.all.order(:title)).any? %>
|
||||
<div class="filter__menu" role="group" aria-label="Tagged">
|
||||
<div class="filter__label"><strong>Tagged</strong></div>
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
|
||||
<% User.active.without(Current.user).order(:name).each do |user| %>
|
||||
<div>
|
||||
<label class="btn filter__button">
|
||||
<%= check_box_tag "assignee_ids[]", user.id, filter.assignees.include?(user), class: "visually-hidden",
|
||||
@@ -157,7 +157,7 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<% Current.account.users.active.without(Current.user).order(:name).each do |user| %>
|
||||
<% User.active.without(Current.user).order(:name).each do |user| %>
|
||||
<div>
|
||||
<label class="btn filter__button">
|
||||
<%= check_box_tag "creator_ids[]", user.id, filter.creators.include?(user), class: "visually-hidden" %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% if Current.account.workflows.any? %>
|
||||
<% if Workflow.any? %>
|
||||
<div class="quick-filter position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<button class="btn input input--select flex-inline txt-small" data-action="click->dialog#open:stop">
|
||||
<span class="overflow-ellipsis">
|
||||
@@ -20,8 +20,7 @@
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<% workflow = Current.account.workflows.first %>
|
||||
<% workflow.stages.each do |stage| %>
|
||||
<% Workflow.first.stages.each do |stage| %>
|
||||
<div class="btn popup__item">
|
||||
<%= form.check_box :stage_ids, {
|
||||
multiple: true,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<span class="overflow-ellipsis">Clear all</span>
|
||||
<% end %>
|
||||
|
||||
<% Current.account.tags.order(:title).each do |tag| %>
|
||||
<% Tag.order(:title).each do |tag| %>
|
||||
<div class="btn popup__item">
|
||||
<%= form.check_box "tag_ids[]", {
|
||||
checked: filter.tags.include?(tag),
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<% cache [notification, "2025-04-09"] do %>
|
||||
<% cache notification do %>
|
||||
<%= notification_tag notification do %>
|
||||
<div class="avatar txt-x-small flex-item-no-shrink">
|
||||
<%= avatar_image_tag(notification.creator) %>
|
||||
<%= avatar_image_tag notification.creator %>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-column min-width flex-item-grow">
|
||||
<strong class="overflow-ellipsis notification__title txt-small txt-tight-lines"><%= notification_title(notification) %></strong>
|
||||
<div class="overflow-ellipsis txt-small txt-tight-lines">
|
||||
<% if notification.event.action == "commented" %>
|
||||
<%= "#{ strip_tags(notification.event.comment.body_html).blank? ? "#{ notification.event.creator.name } replied" : "#{ notification.event.creator.name }:" } #{ strip_tags(notification.event.comment.body_html).truncate(200) }" %>
|
||||
<%= "#{strip_tags(notification.event.comment.body_html).blank? ? "#{notification.event.creator.name} replied" : "#{notification.event.creator.name}:" } #{strip_tags(notification.event.comment.body_html).truncate(200)}" %>
|
||||
<% else %>
|
||||
<%= notification_body(notification) %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="flex flex-column align-center gap">
|
||||
<% url = join_url(Current.account.join_code) %>
|
||||
<% url = join_url(Account.sole.join_code) %>
|
||||
|
||||
<label class="flex flex-column gap full-width txt-align-center">
|
||||
<strong id="invite_label" class="invite-label">Share to invite more people</strong>
|
||||
@@ -2,12 +2,12 @@
|
||||
<%= avatar_tag user, class: "flex-item-no-shrink" %>
|
||||
|
||||
<strong class="overflow-ellipsis">
|
||||
<%= link_to user.name, user_path(user), class: "txt-ink btn btn--plain" %>
|
||||
<%= link_to user.name, user, class: "txt-ink btn btn--plain" %>
|
||||
</strong>
|
||||
|
||||
<hr class="separator--horizontal flex-item-grow" style="--border-color: var(--color-subtle-dark); --border-style: dashed" aria-hidden="true">
|
||||
|
||||
<%= form_with model: user, url: account_user_path(user), data: { controller: "form" }, method: :patch do | form | %>
|
||||
<%= form_with model: user, url: user_role_path(user), data: { controller: "form" }, method: :patch do | form | %>
|
||||
<label class="btn txt-small flex-item-no-shrink" for="<%= dom_id(user, :role) %>" arial-label="Role: <%= user.admin? ? "Administrator" : "Member" %>">
|
||||
<%= icon_tag "crown" %>
|
||||
<%= form.check_box :role, { data: { action: "form#submit" }, disabled: !Current.user.can_administer?(user), hidden: true, id: dom_id(user, :role) }, "admin", "member" %>
|
||||
@@ -15,7 +15,7 @@
|
||||
<% end %>
|
||||
|
||||
<%# FIXME: Move this Current.user check to a stimulus controller that just checks for admin? or the like we so we can cache user list %>
|
||||
<%= button_to account_user_path(user), method: :delete, class: "btn txt-small btn--negative flex-item-no-shrink",
|
||||
<%= button_to user, method: :delete, class: "btn txt-small btn--negative flex-item-no-shrink",
|
||||
disabled: !Current.user.can_administer?(user),
|
||||
data: { turbo_confirm: "Are you sure you want to permanently remove this person from the account?" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
@@ -16,9 +16,9 @@
|
||||
<% end %>
|
||||
|
||||
<div class="panel borderless center pad fill-shade flex flex-column margin-block">
|
||||
<%= render "accounts/users/invite" %>
|
||||
<%= render "users/invite" %>
|
||||
</div>
|
||||
|
||||
<div class="panel borderless center pad fill-none flex flex-column gap">
|
||||
<%= render partial: "accounts/users/user", collection: @users %>
|
||||
<%= render @users %>
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<%= link_to_back fallback_path: account_users_path %>
|
||||
<%= link_to_back fallback_path: users_path %>
|
||||
|
||||
<span class="btn btn--placeholder"></span>
|
||||
|
||||
|
||||
+5
-5
@@ -2,10 +2,11 @@ Rails.application.routes.draw do
|
||||
resource :first_run
|
||||
|
||||
resource :account do
|
||||
scope module: :accounts do
|
||||
resource :join_code
|
||||
resources :users
|
||||
end
|
||||
resource :join_code, module: :accounts
|
||||
end
|
||||
|
||||
resources :users do
|
||||
resource :role, module: :users
|
||||
end
|
||||
|
||||
resources :collections do
|
||||
@@ -35,7 +36,6 @@ Rails.application.routes.draw do
|
||||
resource :goldness
|
||||
|
||||
resources :assignments
|
||||
resources :boosts
|
||||
resources :stagings
|
||||
resources :taggings
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class DropCardCommentsCount < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_column :cards, :comments_count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class RemoveBoostsCountFromCards < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_column :cards, :boosts_count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class RemoveAccountIds < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_column :closure_reasons, :account_id
|
||||
remove_column :collections, :account_id
|
||||
remove_column :tags, :account_id
|
||||
remove_column :users, :account_id
|
||||
remove_column :workflows, :account_id
|
||||
end
|
||||
end
|
||||
Generated
+1
-16
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2025_04_12_170620) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.integer "collection_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
@@ -113,9 +113,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
t.float "activity_score", default: 0.0, null: false
|
||||
t.datetime "activity_score_at"
|
||||
t.float "activity_score_order", default: 0.0, null: false
|
||||
t.integer "boosts_count", default: 0, null: false
|
||||
t.integer "collection_id", null: false
|
||||
t.integer "comments_count", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.integer "creator_id", null: false
|
||||
t.date "due_on"
|
||||
@@ -131,11 +129,9 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
end
|
||||
|
||||
create_table "closure_reasons", force: :cascade do |t|
|
||||
t.integer "account_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.string "label"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id"], name: "index_closure_reasons_on_account_id"
|
||||
end
|
||||
|
||||
create_table "closures", force: :cascade do |t|
|
||||
@@ -150,14 +146,12 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
end
|
||||
|
||||
create_table "collections", force: :cascade do |t|
|
||||
t.integer "account_id", null: false
|
||||
t.boolean "all_access", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.integer "creator_id", null: false
|
||||
t.string "name", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "workflow_id"
|
||||
t.index ["account_id"], name: "index_collections_on_account_id"
|
||||
t.index ["creator_id"], name: "index_collections_on_creator_id"
|
||||
t.index ["workflow_id"], name: "index_collections_on_workflow_id"
|
||||
end
|
||||
@@ -289,16 +283,12 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
end
|
||||
|
||||
create_table "tags", force: :cascade do |t|
|
||||
t.integer "account_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.string "title"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id", "title"], name: "index_tags_on_account_id_and_title", unique: true
|
||||
t.index ["account_id"], name: "index_tags_on_account_id"
|
||||
end
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.integer "account_id", null: false
|
||||
t.boolean "active", default: true, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.string "email_address"
|
||||
@@ -306,7 +296,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
t.string "password_digest"
|
||||
t.string "role", default: "member", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id"], name: "index_users_on_account_id"
|
||||
t.index ["email_address"], name: "index_users_on_email_address", unique: true
|
||||
t.index ["role"], name: "index_users_on_role"
|
||||
end
|
||||
@@ -331,11 +320,9 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
end
|
||||
|
||||
create_table "workflows", force: :cascade do |t|
|
||||
t.integer "account_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.string "name", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["account_id"], name: "index_workflows_on_account_id"
|
||||
end
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
@@ -356,11 +343,9 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_10_141409) do
|
||||
add_foreign_key "sessions", "users"
|
||||
add_foreign_key "taggings", "cards"
|
||||
add_foreign_key "taggings", "tags"
|
||||
add_foreign_key "users", "accounts"
|
||||
add_foreign_key "watches", "cards"
|
||||
add_foreign_key "watches", "users"
|
||||
add_foreign_key "workflow_stages", "workflows"
|
||||
add_foreign_key "workflows", "accounts"
|
||||
|
||||
# Virtual tables defined in this database.
|
||||
# Note that virtual tables may not work with other database engines. Be careful if changing database.
|
||||
|
||||
+77
-217
@@ -50,26 +50,6 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: involvement
|
||||
cast_type: &7 !ruby/object:ActiveModel::Type::String
|
||||
true: t
|
||||
false: f
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &8 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: varchar
|
||||
type: :string
|
||||
limit:
|
||||
precision:
|
||||
scale:
|
||||
'null': false
|
||||
default: watching
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &9 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: updated_at
|
||||
@@ -90,6 +70,26 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: involvement
|
||||
cast_type: &7 !ruby/object:ActiveModel::Type::String
|
||||
true: t
|
||||
false: f
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &8 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: varchar
|
||||
type: :string
|
||||
limit:
|
||||
precision:
|
||||
scale:
|
||||
'null': false
|
||||
default: watching
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
accounts:
|
||||
- *5
|
||||
- *6
|
||||
@@ -412,27 +412,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: boosts_count
|
||||
cast_type: *1
|
||||
sql_type_metadata: *2
|
||||
'null': false
|
||||
default: 0
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *24
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: comments_count
|
||||
cast_type: *1
|
||||
sql_type_metadata: *2
|
||||
'null': false
|
||||
default: 0
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *6
|
||||
- &25 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -463,16 +443,6 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: last_active_at
|
||||
cast_type: *3
|
||||
sql_type_metadata: *4
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: stage_id
|
||||
@@ -493,7 +463,7 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- &33 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- &32 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: title
|
||||
cast_type: *7
|
||||
@@ -504,19 +474,18 @@ columns:
|
||||
collation:
|
||||
comment:
|
||||
- *9
|
||||
closure_reasons:
|
||||
- *5
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: account_id
|
||||
cast_type: *1
|
||||
sql_type_metadata: *2
|
||||
'null': true
|
||||
name: last_active_at
|
||||
cast_type: *3
|
||||
sql_type_metadata: *4
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *6
|
||||
closure_reasons:
|
||||
- *5
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: label
|
||||
@@ -527,21 +496,12 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *6
|
||||
- *9
|
||||
closures:
|
||||
- *5
|
||||
- *21
|
||||
- *6
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: reason
|
||||
cast_type: *7
|
||||
sql_type_metadata: *8
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
- *9
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
@@ -553,26 +513,26 @@ columns:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
collections:
|
||||
- *5
|
||||
- &32 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: account_id
|
||||
cast_type: *1
|
||||
sql_type_metadata: *2
|
||||
name: reason
|
||||
cast_type: *7
|
||||
sql_type_metadata: *8
|
||||
'null': false
|
||||
default:
|
||||
default_function:
|
||||
collation:
|
||||
comment:
|
||||
collections:
|
||||
- *5
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: all_access
|
||||
cast_type: &34 !ruby/object:ActiveModel::Type::Boolean
|
||||
cast_type: &33 !ruby/object:ActiveModel::Type::Boolean
|
||||
precision:
|
||||
scale:
|
||||
limit:
|
||||
sql_type_metadata: &35 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type_metadata: &34 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
|
||||
sql_type: boolean
|
||||
type: :boolean
|
||||
limit:
|
||||
@@ -880,18 +840,16 @@ columns:
|
||||
- *9
|
||||
tags:
|
||||
- *5
|
||||
- *32
|
||||
- *6
|
||||
- *33
|
||||
- *32
|
||||
- *9
|
||||
users:
|
||||
- *5
|
||||
- *32
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: active
|
||||
cast_type: *34
|
||||
sql_type_metadata: *35
|
||||
cast_type: *33
|
||||
sql_type_metadata: *34
|
||||
'null': false
|
||||
default: true
|
||||
default_function:
|
||||
@@ -939,8 +897,8 @@ columns:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
|
||||
auto_increment:
|
||||
name: watching
|
||||
cast_type: *34
|
||||
sql_type_metadata: *35
|
||||
cast_type: *33
|
||||
sql_type_metadata: *34
|
||||
'null': false
|
||||
default: true
|
||||
default_function:
|
||||
@@ -973,7 +931,6 @@ columns:
|
||||
comment:
|
||||
workflows:
|
||||
- *5
|
||||
- *32
|
||||
- *6
|
||||
- *10
|
||||
- *9
|
||||
@@ -1408,6 +1365,22 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: cards
|
||||
name: index_cards_on_stage_id
|
||||
unique: false
|
||||
columns:
|
||||
- stage_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: cards
|
||||
name: index_cards_on_last_active_at_and_status
|
||||
@@ -1425,56 +1398,8 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: cards
|
||||
name: index_cards_on_stage_id
|
||||
unique: false
|
||||
columns:
|
||||
- stage_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
closure_reasons:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: closure_reasons
|
||||
name: index_closure_reasons_on_account_id
|
||||
unique: false
|
||||
columns:
|
||||
- account_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
closure_reasons: []
|
||||
closures:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: closures
|
||||
name: index_closures_on_card_id
|
||||
unique: true
|
||||
columns:
|
||||
- card_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: closures
|
||||
name: index_closures_on_card_id_and_created_at
|
||||
@@ -1492,6 +1417,22 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: closures
|
||||
name: index_closures_on_card_id
|
||||
unique: true
|
||||
columns:
|
||||
- card_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: closures
|
||||
name: index_closures_on_user_id
|
||||
@@ -1509,22 +1450,6 @@ indexes:
|
||||
comment:
|
||||
valid: true
|
||||
collections:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: collections
|
||||
name: index_collections_on_account_id
|
||||
unique: false
|
||||
columns:
|
||||
- account_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: collections
|
||||
name: index_collections_on_creator_id
|
||||
@@ -2014,40 +1939,7 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
tags:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: tags
|
||||
name: index_tags_on_account_id
|
||||
unique: false
|
||||
columns:
|
||||
- account_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: tags
|
||||
name: index_tags_on_account_id_and_title
|
||||
unique: true
|
||||
columns:
|
||||
- account_id
|
||||
- title
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
tags: []
|
||||
users:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: users
|
||||
@@ -2081,22 +1973,6 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: users
|
||||
name: index_users_on_account_id
|
||||
unique: false
|
||||
columns:
|
||||
- account_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
watches:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: watches
|
||||
@@ -2147,21 +2023,5 @@ indexes:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
workflows:
|
||||
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
|
||||
table: workflows
|
||||
name: index_workflows_on_account_id
|
||||
unique: false
|
||||
columns:
|
||||
- account_id
|
||||
lengths: {}
|
||||
orders: {}
|
||||
opclasses: {}
|
||||
where:
|
||||
type:
|
||||
using:
|
||||
include:
|
||||
nulls_not_distinct:
|
||||
comment:
|
||||
valid: true
|
||||
version: 20250410141409
|
||||
workflows: []
|
||||
version: 20250412170620
|
||||
|
||||
@@ -10,7 +10,7 @@ Current.session = user.sessions.last
|
||||
workflow = account.workflows.first
|
||||
|
||||
COLLECTIONS_COUNT.times do |collection_index|
|
||||
collection = account.collections.create!(name: "Collection #{collection_index}", creator: user, workflow: workflow)
|
||||
collection = Collection.create!(name: "Collection #{collection_index}", creator: user, workflow: workflow)
|
||||
CARDS_PER_COLLECTION.times do |card_index|
|
||||
collection.cards.create!(title: "Card #{card_index}", creator: user, status: :published)
|
||||
end
|
||||
|
||||
@@ -4,9 +4,9 @@ CARDS_COUNT = 200
|
||||
|
||||
ApplicationRecord.current_tenant = "development-tenant"
|
||||
account = Account.first
|
||||
user = account.users.first
|
||||
user = User.first
|
||||
Current.session = user.sessions.last
|
||||
collection = account.collections.first
|
||||
collection = Collection.first
|
||||
|
||||
# Doing
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class Accounts::UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "update" do
|
||||
assert_not users(:david).admin?
|
||||
|
||||
put account_user_url(users(:david)), params: { user: { role: "admin" } }
|
||||
|
||||
assert_redirected_to account_users_path
|
||||
assert users(:david).reload.admin?
|
||||
end
|
||||
|
||||
test "can't promote to special roles" do
|
||||
assert_no_changes -> { users(:david).reload.role } do
|
||||
put account_user_url(users(:david)), params: { user: { role: "system" } }
|
||||
end
|
||||
end
|
||||
|
||||
test "destroy" do
|
||||
assert_difference -> { User.active.count }, -1 do
|
||||
delete account_user_url(users(:david))
|
||||
end
|
||||
|
||||
assert_redirected_to account_users_path
|
||||
assert_nil User.active.find_by(id: users(:david).id)
|
||||
end
|
||||
|
||||
test "non-admins cannot perform actions" do
|
||||
sign_in_as :jz
|
||||
|
||||
put account_user_url(users(:david)), params: { user: { role: "admin" } }
|
||||
assert_response :forbidden
|
||||
|
||||
delete account_user_url(users(:david))
|
||||
assert_response :forbidden
|
||||
end
|
||||
end
|
||||
@@ -6,18 +6,18 @@ class Cards::AssignmentsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test "new" do
|
||||
get new_card_assignment_url(cards(:logo))
|
||||
get new_card_assignment_path(cards(:logo))
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test "create" do
|
||||
assert_changes "cards(:logo).assigned_to?(users(:david))", from: false, to: true do
|
||||
post card_assignments_url(cards(:logo)), params: { assignee_id: users(:david).id }, as: :turbo_stream
|
||||
post card_assignments_path(cards(:logo)), params: { assignee_id: users(:david).id }, as: :turbo_stream
|
||||
end
|
||||
assert_response :success
|
||||
|
||||
assert_changes "cards(:logo).assigned_to?(users(:david))", from: true, to: false do
|
||||
post card_assignments_url(cards(:logo)), params: { assignee_id: users(:david).id }, as: :turbo_stream
|
||||
post card_assignments_path(cards(:logo)), params: { assignee_id: users(:david).id }, as: :turbo_stream
|
||||
end
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class Cards::BoostsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in_as :kevin
|
||||
end
|
||||
|
||||
test "create" do
|
||||
boost_count = cards(:logo).boosts_count
|
||||
|
||||
assert_difference "cards(:logo).reload.boosts_count", +1 do
|
||||
post card_boosts_path(cards(:logo), params: { boost_count: boost_count }, format: :turbo_stream)
|
||||
end
|
||||
|
||||
assert_turbo_stream action: :update, target: dom_id(cards(:logo), :boosts)
|
||||
end
|
||||
|
||||
test "create with value" do
|
||||
boost_count = 10
|
||||
|
||||
assert_changes "cards(:logo).reload.boosts_count", to: boost_count do
|
||||
post card_boosts_path(cards(:logo), params: { boost_count: boost_count }, format: :turbo_stream)
|
||||
end
|
||||
|
||||
assert_turbo_stream action: :update, target: dom_id(cards(:logo), :boosts)
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user