-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Merge UserDataProvider and UserManagementActionDispatcher into one type #23792
base: fix/self-hosted-site-user-delete
Are you sure you want to change the base?
Merge UserDataProvider and UserManagementActionDispatcher into one type #23792
Conversation
Generated by 🚫 Danger |
📲 You can test the changes from this Pull Request in WordPress Alpha by scanning the QR code below to install the corresponding build.
|
📲 You can test the changes from this Pull Request in Jetpack Alpha by scanning the QR code below to install the corresponding build.
|
|
||
// Remove the deleted user from the cached users list. | ||
if result.deleted { | ||
await MainActor.run { |
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.
(nit) This should be declarative. If fetched
and usersSubject
can only be used form the main thread, perhaps this entire class need to by isolated on the main actor.
final actor UserCache { | ||
var users: [DisplayUser] = [] | ||
private func finishFetchingUsers(_ result: Result<[DisplayUser], Error>) { | ||
fetchUserslock.lock() |
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.
Similar to the other comment – perhaps it would be clearer to simply synchronize this entire class on the main actor. It can still perform expensive work in the background, but I think it's totally fine if the state is syncronized on main since it's going to be called from the UI anyway.
|
||
public protocol UserDataProvider { | ||
public protocol UserServiceProtocol { | ||
var users: AnyPublisher<Result<[DisplayUser], Error>, Never> { get } |
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.
This results in a pretty awkward code on the caller side. I'd suggest modeling it as:
var users: [DisplayUser] { get }
func fetchUsers() async throws -> [DisplayUser]
// If you also need `users` to be observable:
var usersPublisher: AnyPublisher<[DisplayUser], Never> { get }
I wish Swift allowed using property wrappers like @Published
in protocol 😞
If you want to make sure that fetchUsers
doesn't perform more than one operation, I'd suggest taking advantage of the Task
:
private var refreshTask: Task<[DisplayUser], Error>?
func refresh() async throws {
if let task = refreshTask {
try await task.value
}
let task = Task {
try await _refresh()
}
refreshTask = task
return await task.value
}
private func _refresh() async {
error = nil
isRefreshing = true
Note
This PR is built on top of #23791.
Uses one
UserService
for all user management actions.The user list is cached in the type, which fixes the issue where deleted users show in the user list.
I will add unit tests to the service and view model types in a separate PR.I have added some unit tests forUserService
, but not sure what's the best practice/easiest way to testObservableObject
(the view models).Regression Notes
Potential unintended areas of impact
What I did to test those areas of impact (or what existing automated tests I relied on)
What automated tests I added (or what prevented me from doing so)
PR submission checklist:
RELEASE-NOTES.txt
if necessary.Testing checklist: