-
Notifications
You must be signed in to change notification settings - Fork 39
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
Allow different rules and action for delete user #2714
Conversation
4e32c32
to
7d06f11
Compare
1418886
to
79a937d
Compare
79a937d
to
ed7793f
Compare
02ce262
to
4dfd455
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2714 +/- ##
==========================================
+ Coverage 91.22% 91.25% +0.03%
==========================================
Files 333 335 +2
Lines 11869 11933 +64
==========================================
+ Hits 10828 10890 +62
- Misses 1041 1043 +2 ☔ View full report in Codecov by Sentry. |
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.
Hey @jyeshe, this is really a great piece of work. I learnt a lot while reviewing it, thank you. I left few comments (my reactions and curiosity questions), I would appreciate to hear your thoughts on em.
@@ -0,0 +1,90 @@ | |||
defmodule LightningWeb.ProfileLive.CommonComponents do |
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.
@jyeshe CommonComponents
is really a great name and I like it. But we usually name these modules as Common
or Components
, I am wondering if we shouldn't keep that naming for consistency ?
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.
done
def action_cards(assigns) do | ||
~H""" | ||
<div id={"user-#{@current_user.id}"} class="md:col-span-2"> | ||
<.live_component | ||
:if={@live_action == :delete} | ||
module={@user_deletion_modal} | ||
id={@current_user.id} | ||
user={@current_user} | ||
logout={true} | ||
return_to={~p"/profile"} | ||
/> | ||
<.live_component | ||
module={LightningWeb.ProfileLive.FormComponent} | ||
id={@current_user.id} | ||
title={@page_title} | ||
action={@live_action} | ||
user={@current_user} | ||
return_to={~p"/profile"} | ||
/> | ||
<.live_component | ||
module={LightningWeb.ProfileLive.MfaComponent} | ||
id={"#{@current_user.id}_mfa_section"} | ||
user={@current_user} | ||
/> | ||
<.live_component | ||
module={LightningWeb.ProfileLive.GithubComponent} | ||
id={"#{@current_user.id}_github_section"} | ||
user={@current_user} | ||
/> | ||
<.delete_user_card url={@delete_user_url} /> | ||
</div> | ||
""" | ||
end |
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.
Nice
@@ -0,0 +1,113 @@ | |||
defmodule LightningWeb.UserLive.CommonComponents do |
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.
Same question for the naming here ? Again, I really think that CommonComponents
is a great name, I am just wondering about module naming consistency.
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.
done
attr :users, :list, required: true | ||
attr :live_action, :atom, required: true | ||
|
||
attr :user_deletion_modal, :atom, |
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.
:atom
? You maybe mean :any
(or :map
) ?
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.
The atom here is the module name
assign(socket, :users, list_users()) | ||
|> assign(:active_menu_item, :users), | ||
layout: {LightningWeb.Layouts, :settings}} | ||
modal = Map.get(socket, :private, %{})[:delete_modal] |
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.
Nice ❤️
@@ -98,7 +98,6 @@ defmodule LightningWeb.UserLive.CommonComponents do | |||
Cancel deletion | |||
</.link> | |||
</span> | |||
| |
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.
👍
20ebc32
to
6528aac
Compare
Changed to use metadata as the private works only on the connection. |
17f55c0
to
a93a560
Compare
918236f
to
5159368
Compare
* There is pre-existing bug that needs to be fixed when clicking outside the modal
3380fa4
to
fc4aba7
Compare
fc4aba7
to
a95852f
Compare
@@ -106,7 +107,7 @@ defmodule LightningWeb.Components.UserDeletionModal do | |||
</:title> | |||
<div class=""> | |||
<p class="text-sm text-gray-500"> | |||
This user cannot be deleted until their auditable activities have also been purged. | |||
<%= if @is_superuser_menu, do: "This user", else: "Your account" %> cannot be deleted until their auditable activities have also been purged. |
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.
Would it not be better to have the comparison based on the current user vs. the user selected for deletion? Then the component (upstream) wouldn't need to know about its location in the component tree?
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.
I have opted to use the page that uses the modal as a direct and more explicit condition to choose the language:
- 3rd person on the users page (accessed via superuser menu)
- 1st person on the user profile
Maybe I should have used the page name instead of the menu as a context.
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.
The condition you propose is valid now that we've blocked the deletion of super users and also referring to the superuser on the 3rd person, when deleting his/her own account wouldn't harm much as well. The main reason was to make the condition as clearer as possible (kind of giving names from user story/business perspective).
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.
But the 3rd and 1st person perspective can be determined by the current user and the selected user, I'm not seeing a good enough reason to bring the layout into the mix when we have the current user available everywhere.
If the @is_superuser_menu
option is purely for the copy, I would suggest an attr that controls it lives outside, like is_current_user
or something. Components really should avoid knowing about the place they are mounted 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.
I get your point of sufficient existing conditions but it is not rare that find components that behave differently according to a context.
On the other hand, is_current_user
is very straightforward and clear as well. Thanks
end | ||
|
||
defp apply_action(socket, :delete, %{"id" => id}) do | ||
socket | ||
|> assign(:page_title, "Users") | ||
|> assign(:user, Accounts.get_user!(id)) | ||
|> assign(:delete_user, Accounts.get_user!(id)) |
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.
Why the change? It's called user
downstream in the table component as well. I could imagine it's because we're wanting to signify that this user is selected for deletion, but the component doesn't really know about that, it's just a 'selected user' in my mind and is only deletable when paired with an action/event.
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.
The renaming was for three reasons:
- It's not used anymore directly neither on the LV nor on the heex, it's passed down to 3rd level component.
- Same idea as you've mentioned the selected user that will be used somewhere for some operation
- Given the 2 above, I wanted to make it easier for the review and maintenance, in a way that it's easy to search and quickly find it by a unique name:
Description
This PR changes the rendering of the
ProfileLive.Edit
andUserLive.Index
(superuser) liveviews to allow them to be customized on three aspects when deleting a user:Its strategy was similar to the Projects customization, where the liveview is injected on the router.
The change consists on making the respective
edit.html.heex
andindex.html.heex
to rely completely on components so that the Saas page can reuse them and implement different rules on the liveview modules.EDIT: As suggested by the LV docs, the metadata
live/4
opt can be used to customize a LiveView which may be invoked from different routes.Refs #2500
Validation steps
ProfileLive.Edit
:UserLive.Index
:A popup shows a message: "This user's account and credential ..."
Additional notes for the reviewer
As a helper note on the refactoring,
LightningWeb.ProfileLive.MfaComponent
andLightningWeb.ProfileLive.GithubComponent
aren't directly related to Delete User and wouldn't need to be extracted from theProfileLive.FormComponent
. However they are not part of the<form>
and their actions/events are handled by their own components themselves (as expected) justifying the extraction to the same level as theProfileLive.FormComponent
(and not inside).AI Usage
Please disclose how you've used AI in this work (it's cool, we just want to know!):
You can read more details in our Responsible AI Policy
Pre-submission checklist
:owner
,:admin
,:editor
,:viewer
)