-
-
Notifications
You must be signed in to change notification settings - Fork 955
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
Add ContainerNode and RiverpodNode to devtool #1471
Add ContainerNode and RiverpodNode to devtool #1471
Conversation
👋 |
yes! Will do! |
} | ||
|
||
extension on ContainerNode { | ||
bool isEqualTo(ContainerNode other) { |
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.
we could use freezed
or equatable
on the actual classes, but I noticed that riverpod
package doesn't depend on these packages.
@@ -1,7 +1,50 @@ | |||
// ignore_for_file: public_member_api_docs | |||
// ignore_for_file: public_member_api_docs, invalid_use_of_visible_for_testing_member |
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.
What is this change for?
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 is related to the other question that you made #1471 (comment) . I can totally remove it if I make it a part
of provider_base.dart.
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.
removed
@@ -70,13 +117,26 @@ class RiverpodBinding { | |||
return binding!; | |||
} | |||
|
|||
|
|||
bool get supportsDevTool => true; |
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.
What is the purpose of this getter?
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 was just to show or not the Riverpod
tab on devtools. But I think I might have a better way of doing that. We could just use a try-catch instead. You can see the implementation here https://github.com/flutter/devtools/pull/4210/files#diff-90638f67ff3222b19bb967f40f76a108841c7a1b6917d8f853d8a04c55d0bb9eR9 .
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.
What about making this the package version?
We'll want to expose the version anyway to know if a feature newly added devtool features are supported or not in the future.
This would of course need a unit test to check that the version is in sync with the pubspec.yaml
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.
yes, I tried adding the version, but couldn't find a consistent way of getting if from the pubspec. But now that you mentioned the test we could just have a test that reads the pubspec and compare the versions. 🤔
Is this OK for you? We will need to also add some documentation for it, I suppose.
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 was thinking here, instead of using the actual package version, why not create a "virtual" versioning for devtools support? Like we could call something like "devtoolsSupportVersion" and start it at 1
, then we just increment the number every time we add a new feature. This way we don't need to always change the version when riverpod
version changes, we would only need to change when we change the devtool implementation.
WDYT?
final String id; | ||
final String containerId; | ||
final String? name; | ||
final Result<dynamic>? state; |
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.
final Result<dynamic>? state; | |
final Result<Object?>? state; |
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.
Perfect, I'll make the change.
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 can't change it to Object
, the element.getState() returns a dynamic, since it is a generic.
@@ -202,6 +202,8 @@ class _ProviderListener<State> implements ProviderSubscription<State> { | |||
State read() => listenedElement.readSelf(); | |||
} | |||
|
|||
var _elementDebugNextId = 0; |
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.
Move this as a static variable of ProviderElementBase
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, just wondering if there is a reason other than keeping the consistency. In the end won't it be the same?
/// | ||
/// Should not be used, only meant for debug purposes | ||
@visibleForTesting | ||
bool get dependencyMayHaveChanged => _dependencyMayHaveChanged; |
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 don't want this to be visible. If necessary, make the devtool file in the same part
as this file
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'll try making it a part, I tried going with part at first but had some issues. I'll try again and let you know.
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've removed the public getter.
/// and [_onRemoveListener] | ||
void _notifyListenersChanged() { | ||
assert(() { | ||
RiverpodBinding.debugInstance.providerChanged( |
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 do we notify that a provider has changed when we add/remove listeners?
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.
to be able to show the alert saying that the provider might be outdated. Like refreshing the list when this event happens.
We could just remove it, it would make the implementation smaller on both sides, but the displayed data would be less realtime.
Maybe adding a "refresh all containers" (I mean only on the devtools side, not refreshing the providers states) button would be better, this way we could refresh the devtools data. WDYT?
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 why "providerChanged"? I would expect a new event for this.
We can create as many events as we want. No need to reuse the same one for multiple things
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.
oh! Got it! Well, in the devtools implementation they would do the same thing, which is to refresh the provider state. That is why I used the same event, but I could change it to something like 'riverpod:provider_listeners_changed'
and listen to both events there on devtools.
}); | ||
|
||
test('should add container to containers map', () { | ||
final firstContainer = ProviderContainer(); |
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.
use the createContainer
utility instead of manually creating ProviderContainers
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.
cool! I'll change that.
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
|
||
expect( | ||
containerNodes, | ||
predicate( |
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.
What is the purpose of the predicate here?
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.
well, this is a creative solution to avoid adding Equatable
or Freezed
to the package.
As I can't compare two objects directly I created the extension functions to make the fields check without the need of changing production code. It is not the prettiest code, I know. Do you have any suggestions?
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.
Feel free to override ==/hashCode for those classes.
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.
perfect! This will be way cleaner hehe
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.
added here 3fe5095
I haven't forgotten about this. I'll continue the work on my own during August. |
cool, so you mean you'll continue this work? I can still work on it if you want, I was just waiting for you comments. Let me know if you need my help. Cheers! |
It'd be great if you could add tests on the devtool PR (not this one, the flutter/devtool repo) |
For sure! I was just waiting to have this API ready to go. I'll add the tests this week. |
Don't worry about this api. I don't mind much what it looks like, since it's not public. What matters is that everything is tested |
@rrousselGit this PR should be ready to be merged, we need to merge it first and create a release since devtools depends on this. |
Don't worry about this. For reference, I don't plan on merging this until the devtool PR is ready to merge. These two PRs are intertined. A problem in one would require a change in the other, so they likely need to be merged at the same time. |
Makes sense! |
This is looking great! A small note about the sidebar listing providers:
More specifically, I could see the rendering of Assuming we have: final myProvider = Provider.family<String, int>((ref, id) => 'Hello $id');
...
ref.watch(myProvider(42)); Then I think the rendering could be:
Also, for the sake of readability, I think that if there's only one root This would remove one level of indentation on the sidebar If there are multiple roots, we'd need to keep the rendering as it is. But that's fairly rare I think |
really great insights! I'll work on them! They should be easy to implement, I'll work on an UI and share with you soon. |
Kapture.2022-08-15.at.11.02.34.mp4I've made some modifications, WDYT? What I've changed: 1 - Don't show the container label if there is only one container. |
Nice! That looks great! Quick note, what is that "StringValue"? Is it a custom class you made as an example? Or is that the object vm_service gives you? Also, we'd need to make sure that there's a text wrap if the family arg toString is too long :) |
Acutally, the video showcases that. Ignore me! That's awesome, nice work! |
Quick note: Family args shouldn't be editable. Is that the case here? |
About the family not being editable: They are, since I'm using the same viewer as the state. I just tested here and you can just edit a value if it is not final 😞. I was looking at the instance_viewer that you've made for provider (which is the same that I'm using) and there is no option to disable editing. I could add a flag to the WDYT? |
Sorry I used the wrong word. Rather than text wrap, I think clipping it is better. As in doing The sidebar can be expanded anyway, and the provider can be selected to see it in full. Especcially considering objects could override |
SGTM |
Epic A nit point would be to rename 'container" into providerContainer to be more specific. But otherwise LGTM |
You mean written like |
And what about the header? Should we keep |
Yes
The header too. |
Perfect. Awesome work |
done flutter/devtools@392f6b9, let me know if you think anything can be improved. |
@adsonpleal do you have a social media or a name that I could share? I'd like you publicly thank you for your work. 😊 |
I'm one of those weird ones that don't use social media haha. I have a linkedin profile, though. I think you could use it hehe. |
@rrousselGit I still didn't have time to update to the new riverpod 2.0 on devtools. It shouldn't be that hard, but I'm full with my work here and couldn't focus on that. Do you know how likely is to get the devtools PR approved? I'm wondering about the changes of that PR getting merged. Do you think is worth investing time making it ready for review? I know that they are having discussions about creating some kind of api to create extensions to devtools. But is this actually happening on a near future? Another alternative would be to have the riverpod inspector as a stand alone program, just like isar does with their isar inspector. With this we would have full control of the inspector, without the need of waiting for devtools approval. I know that having the tool inside devtools is way better, as de developer experience would be fully integrated with the flutter tooling. But maybe is worth going with this route, since we could have way faster releases on the riverpod devtools. WDYT? |
Hey @rrousselGit since the devtools PR was closed and this code is already too outdated I'll be closing this PR. What do you think about the custom dev-tool idea? |
@adsonpleal Sorry I missed your reply. Yeah I'm considering a custom devtool too. Maybe an extension in VScode |
@rrousselGit Let me know if you need some help. I did some explorations here with the Isar idea (stand alone solution), but a VScode extension seems better. Or maybe even both, we could probably render the flutter web version inside a Webview in VSCode and have a stand alone web version as well. We can explore https://github.com/Dart-Code/Dart-Code the official dart extension, they probably render the flutter stuff in VScode. |
This PR adds support for Flutter DevTools by improving the already present file
devtool.dart
.With the changes present here we can more easily get the data needed to present the provider state on Flutter DevTools.
For more information check the discussion here.
The UI that these changes enable is the following:
final.experience.mp4
Soon I will open a PR on devtools with the addition of
RiverpodScreen
.