-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#55581] popover for user information on hover #17255
Merged
EinLama
merged 79 commits into
dev
from
feature/55581-popover-for-user-information-on-hover
Dec 4, 2024
+786
−82
Merged
Changes from all commits
Commits
Show all changes
79 commits
Select commit
Hold shift + click to select a range
3249503
[#55581] enforce hover card in project member list for now
EinLama b1e38ec
[#55581] unwrap quotes for angular components
EinLama 7e72f62
[#55581] return early
EinLama fe106c3
[#55581] Users::HoverCardComponent
EinLama 89587fd
[#55581] prefer flex layout
EinLama e7c16e7
WIP
EinLama 8354574
[#55581] offer hover card trigger switch in avatar helper
EinLama ef22234
[#55581] first draft for triangle pointing at hover source
EinLama 3f2ab1d
[#55581] construct project membership string, link to profile
EinLama ca90dbe
avatar details
EinLama 277b9dc
[#55581] show email if allowed to do so
EinLama 1f554f2
[#55581] link project names to projects
EinLama 4f6fd0d
[#55581] attach hover card attributes to avatar image
EinLama 8aff877
[#55581] copyright notices
EinLama 928ab41
[#55581] clear timeout for closing hover card
EinLama 811fbd3
return as soon as possible
EinLama b096073
[#55581] set position & close delay of card by data-attr
EinLama c37731e
[#55581] do not show the same modal twice
EinLama 8ef3486
[#55581] link to groups instead of projects
EinLama 869636e
[#55581] link the end of the sentence to users#show
EinLama 3bef3eb
[#55581] allow hovercards in auto completer and share dialog
EinLama d334568
[#55581] only show hovercard if set active
EinLama ceb96aa
[#55581] do not attempt to show hover cards for groups
EinLama 3246793
[#55581] ensure hover card is rendered in front of modals
EinLama 792e1dd
[#55581] show hover card in member list
EinLama eb7bd5a
WIP
EinLama 3a9b424
[#55581] make portal target customizable
EinLama 87eeae3
default should be default
EinLama 3e7d857
[#55581] provide hover card in news module
EinLama da077fa
[#55581] hover card on boards
EinLama 450f2cb
[#55581] hover card in wp activities
EinLama 3dc40b5
[#55581] hover card in meetings
EinLama ed0ff7f
[#55581] hover card on project overview page (members widget)
EinLama f1ebb2e
[#55581] fix z-index on top of auto completers
EinLama d83fb1a
[#55581] small polishing fixes
EinLama baf07d4
[#55581] do not set top alignment by default
EinLama dc77227
[#55581] add necessary translation for hover card permission
EinLama 4269e4a
[#55581] remove redundant comments, provide 404 locale
EinLama 8f54110
frozen_string_literal
EinLama e6d893e
[#55581] explain missing urls in some cases
EinLama af3b720
[#55581] remove unneeded permission
EinLama 458bea9
mv project group
EinLama 81df01e
[#55581] do not show hover card for placeholder users
EinLama 9a9e7b2
[#55581] reduce ABC in avatar helper
EinLama ec9ffdf
[#55581] spec for user hover cards on member page
EinLama 30a4481
[#55581] reduce email font size
EinLama f7d6d83
[#55581] do not let very long names/mails overflow
EinLama 9e98465
[#55581] wait for one second before displaying a hover card
EinLama e5e8f60
[#55581] remove superfluous styling
EinLama b9d4fa5
[#55581] link to edit profile, localize button string
EinLama 575a5c0
[#55581] use text-shortener mixin
EinLama 2501760
[#55581] remove alignment and close delay options
EinLama 52cdcdd
[#55581] make user hover card opt-out
EinLama 90acc21
fix indentation
EinLama 52f64f8
[#55581] allow disabling the hover card
EinLama 4b5eba5
[#55581] disable hover card on hover card
EinLama 3f22bd3
[#55581] only show visible groups within the hover card
EinLama 5d18642
[#55581] hover cards only in project share, not wp share
EinLama c3d8532
[#55581] fix bug where hover cards are sometimes directly dismissed
EinLama 2ad5f34
[#55581] do not try to show a modal twice at the same time
EinLama 9d9faba
[#55581] use test selectors in spec
EinLama b063953
[#55581] specs for Users::HoverCardComponent
EinLama b1f0004
[#55581] fix avatar_helper specs
EinLama 8fe734b
[#55581] do not show the hover card within the log time dialog
EinLama 3db68a4
[#55581] ensure the URL is a string
EinLama 5496530
[#55581] disable hover cards in global search
EinLama 69a2eee
[#55581] lookbook proposal
EinLama b4fed15
[#55581] add exemplary user hover card to lookbook
EinLama 7661b57
[#55581] reduce filesize of wp hover card image by 45%
EinLama f60f744
[#55581] user generic error message for missing users
EinLama ba84c3f
[#55581] do not try to access non-existent field
EinLama 3c20a5f
[#55581] make hover card work with avatar fallbacks
EinLama 8a1f7b9
[#55581] animate hover card slightly to make it feel less awkward
EinLama 01d9bde
[#55581] deal with multiple hover triggers next to each other
EinLama ab9ea70
[#55581] prevent background layer from darkening in multi nested dialogs
EinLama f6ddf7f
Merge branch 'dev' into feature/55581-popover-for-user-information-on…
EinLama 2462494
[#55581] use BEM style class definitions
EinLama 4c17609
[#55581] use PathHelperService to construct hover card url
EinLama 818876a
[#55581] remove unneede clean up of angular double quotes
EinLama File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<%#-- copyright | ||
OpenProject is an open source project management software. | ||
Copyright (C) the OpenProject GmbH | ||
|
||
This program is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU General Public License version 3. | ||
|
||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: | ||
Copyright (C) 2006-2013 Jean-Philippe Lang | ||
Copyright (C) 2010-2013 the ChiliProject Team | ||
|
||
This program is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU General Public License | ||
as published by the Free Software Foundation; either version 2 | ||
of the License, or (at your option) any later version. | ||
|
||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
|
||
You should have received a copy of the GNU General Public License | ||
along with this program; if not, write to the Free Software | ||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
|
||
See COPYRIGHT and LICENSE files for more details. | ||
|
||
++#%> | ||
|
||
<%= | ||
if @user.present? | ||
flex_layout(classes: 'op-user-hover-card', data: { test_selector: "user-hover-card-#{@user.id}" }) do |flex| | ||
flex.with_row do | ||
render(Users::AvatarComponent.new(user: @user, show_name: false, link: false, hover_card: { active: false })) | ||
end | ||
|
||
flex.with_row do | ||
flex_layout(classes: 'op-user-hover-card--info') do |f| | ||
f.with_column(classes: 'op-user-hover-card--name') do | ||
render(Primer::Beta::Text.new(font_weight: :semibold, data: { test_selector: 'user-hover-card-name' })) do | ||
@user.name | ||
end | ||
end | ||
|
||
if show_email? | ||
f.with_column(classes: 'op-user-hover-card--email') do | ||
render(Primer::Beta::Text.new(font_size: :small, | ||
color: :muted, | ||
data: { test_selector: 'user-hover-card-email' })) do | ||
@user.mail | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
flex.with_row do | ||
flex_layout(classes: 'op-user-hover-card--group-list') do |f| | ||
f.with_column do | ||
render(Primer::Beta::Octicon.new(icon: :people)) | ||
end | ||
|
||
f.with_column do | ||
render(Primer::Beta::Text.new(color: :muted, data: { test_selector: 'user-hover-card-groups' })) do | ||
group_membership_summary | ||
end | ||
end | ||
end | ||
end | ||
|
||
flex.with_row do | ||
render(Primer::Beta::Button.new(tag: :a, | ||
href: helpers.allowed_management_user_profile_path(@user), | ||
data: { test_selector: 'user-hover-card-profile-btn' })) do | ||
I18n.t("users.open_profile") | ||
end | ||
end | ||
end | ||
else | ||
render Primer::Beta::Blankslate.new(border: false, narrow: true) do |component| | ||
component.with_visual_icon(icon: "x-circle") | ||
# Show a generic error message to avoid leaking information | ||
component.with_heading(tag: :h3).with_content(I18n.t("http.response.unexpected")) | ||
end | ||
end | ||
%> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# frozen_string_literal: true | ||
|
||
#-- copyright | ||
# OpenProject is an open source project management software. | ||
# Copyright (C) the OpenProject GmbH | ||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License version 3. | ||
# | ||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: | ||
# Copyright (C) 2006-2013 Jean-Philippe Lang | ||
# Copyright (C) 2010-2013 the ChiliProject Team | ||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
# | ||
# See COPYRIGHT and LICENSE files for more details. | ||
#++ | ||
|
||
class Users::HoverCardComponent < ApplicationComponent | ||
include OpPrimer::ComponentHelpers | ||
|
||
def initialize(id:) | ||
super | ||
|
||
@id = id | ||
@user = User.find_by(id: @id) | ||
end | ||
|
||
def show_email? | ||
(@user == User.current) || User.current.allowed_globally?(:view_user_email) | ||
end | ||
|
||
# Constructs a string in the form of: | ||
# "Member of group4, group5" | ||
# or | ||
# "Member of group1, group2 and 3 more" | ||
# The latter string is cut off since the complete list of group names would exceed the allowed `max_length`. | ||
def group_membership_summary(max_length = 40) | ||
groups = @user.groups.visible | ||
return no_group_text if groups.empty? | ||
|
||
group_links = linked_group_names(groups) | ||
|
||
cutoff_index = calculate_cutoff_index(groups.map(&:name), max_length) | ||
build_summary(group_links, cutoff_index) | ||
end | ||
|
||
private | ||
|
||
def linked_group_names(groups) | ||
groups.map { |group| link_to(h(group.name), show_group_path(group)) } | ||
end | ||
|
||
def no_group_text | ||
t("users.groups.no_results_title_text") | ||
end | ||
|
||
# Calculate the index at which to cut off the group names, based on plain text length | ||
def calculate_cutoff_index(names, max_length) | ||
current_length = 0 | ||
|
||
names.each_with_index do |name, index| | ||
new_length = current_length + name.length + (index > 0 ? 2 : 0) # 2 for ", " separator | ||
return index if new_length > max_length | ||
|
||
current_length = new_length | ||
end | ||
|
||
names.size # No cutoff needed -> return the total size | ||
end | ||
|
||
def build_summary(links, cutoff_index) | ||
summary_links = safe_join(links[0...cutoff_index], ", ") | ||
remaining_count = links.size - cutoff_index | ||
remaining_count_link = link_to(t("users.groups.more", count: remaining_count), user_path(@user)) | ||
|
||
if remaining_count > 0 | ||
t("users.groups.summary_with_more", names: summary_links, count_link: remaining_count_link).html_safe | ||
else | ||
t("users.groups.summary", names: summary_links).html_safe | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Correct the z-index of the regular hover card container so that it is above the dropdown of user auto completers | ||
.spot-modal-overlay:has(.op-user-hover-card) | ||
z-index: 9600 | ||
|
||
// On the project list page, there is a bug when a hover card is invoked within the share dialog. The global spot | ||
// modal overlay will darken the background while the hover card is active, since its semi-transparent bg shading is | ||
// added on top of the other dialog background shaders. We don't want an additional spot modal background here, | ||
// so we disable it for this edge case. | ||
.controller-projects.action-index | ||
.spot-modal-overlay:not(:has(.op-user-hover-card)) | ||
background: transparent | ||
|
||
.op-user-hover-card | ||
gap: 1rem | ||
overflow: hidden | ||
|
||
&--info | ||
gap: 0.5rem | ||
|
||
&--name, &--email | ||
@include text-shortener() | ||
|
||
&--group-list | ||
gap: 0.5rem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# frozen_string_literal: true | ||
|
||
#-- copyright | ||
# OpenProject is an open source project management software. | ||
# Copyright (C) the OpenProject GmbH | ||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License version 3. | ||
# | ||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: | ||
# Copyright (C) 2006-2013 Jean-Philippe Lang | ||
# Copyright (C) 2010-2013 the ChiliProject Team | ||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
# | ||
# See COPYRIGHT and LICENSE files for more details. | ||
#++ | ||
class Users::HoverCardController < ApplicationController | ||
no_authorization_required! :show | ||
|
||
def show | ||
@id = params[:id] | ||
render layout: nil | ||
end | ||
end |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the value 40 coming from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A true magic number 🔮🧙🏻♂️ found by, uh... guessing and trying it out! 🪄
Seemed sensible when used with the English translation and should look okay with most other languages. The caveat is that only the group names are considered when deciding where to shorten the list. To make it perfect, we'd have to load the translation first, factor it's length into the calculation and THEN decide where to cut off the group list. I figured the value
40
is good enough in most cases and strikes a balance between pleasant looks and code complexity :)