Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

cache registry reverses, completion in address selector #4066

Merged
merged 16 commits into from
Jan 10, 2017

Conversation

derhuerst
Copy link
Contributor

Address entry selector should autocomplete to names in the Registry (this will require scouring logs and building a cache of all names that have been reverse-registered).

#3991

@derhuerst derhuerst added A0-pleasereview 🤓 Pull request needs code review. M7-ui labels Jan 6, 2017
@coveralls
Copy link

Coverage Status

Changes Unknown when pulling ad3b89d on jr-reverse-caching into ** on master**.

@gavofyork
Copy link
Contributor

test failing.

@gavofyork
Copy link
Contributor

running on mainnet with gavofyork as a reverse-lookup name:

image

i expect to see it autocompleting

@gavofyork
Copy link
Contributor

it would also be nice to get it listed in there.

@derhuerst
Copy link
Contributor Author

running on mainnet with gavofyork as a reverse-lookup name:
i expect to see it autocompleting

it only autocompletes in the reverse direction. this is what reverse entries are for right?

forward (non-reverse) entries don't get autocompleted yet. you should be able to type gavofyork however to get the full address (if you registered gavofyork and set A of course).

@derhuerst
Copy link
Contributor Author

btw: Travis reported a passing test even though Gitlab failed. @General-Beck?

@derhuerst
Copy link
Contributor Author

forward (non-reverse) entries don't get autocompleted yet.

Now part of #3991.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling ba4263e on jr-reverse-caching into ** on master**.

@gavofyork
Copy link
Contributor

it only autocompletes in the reverse direction
wtf?!

the point is to autocomplete gavo -> gavofyork:

Address entry selector should autocomplete to names in the Registry (this will require scouring logs and building a cache of all names that have been reverse-registered).

let me know if there is something not clear about this statement.

@gavofyork gavofyork added A3-inprogress ⏳ Pull request is in progress. No review needed at this stage. and removed A0-pleasereview 🤓 Pull request needs code review. labels Jan 7, 2017
@derhuerst derhuerst added A0-pleasereview 🤓 Pull request needs code review. and removed A3-inprogress ⏳ Pull request is in progress. No review needed at this stage. labels Jan 9, 2017
@coveralls
Copy link

Coverage Status

Coverage increased (+0.05%) to 86.565% when pulling 8c2aa4d on jr-reverse-caching into 4c94878 on master.

export default class RegistryMiddleware {
toMiddleware () {
return (store) => {
const api = Contracts.get()._api;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be better to add api passed as argument to the toMidleware method, or to the constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would actually like to introduce plain functions for middlewares. Having classes really doesn't give any benefit and the benefit of consistency doesn't outweigh the cost in terms of readability & complexity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

confirmedEvents = subscribeToEvent(_contract, 'ReverseConfirmed');
confirmedEvents.on('log', onLog);

removedEvents = subscribeToEvent(_contract, 'ReverseRemoved');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not subscribe to both events in one filter ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a real reason, except that subscribeToEvent uses contract.subscribe(eventName) under the hood, which is a nice abstraction over the low-level filter API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, but could be nice to be able to give an array of events then :) Even better, have one callback per event, and it would call the right one automagically

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So would you change it to use newFilter internally? I guess it would still be limited to one address?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I think you should be able to pass an Array of events, and on the filter's callback you get the matching event signature anyway, so then it would call the right callback, right?

removedEvents.on('log', onLog);

timeout = setTimeout(checkReverses, 5000);
interval = setInterval(checkReverses, 20000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should clear the timeouts and intervals before setting up new ones as a general statement. If they get overwritten even once, then you won't be able to clear them... Might want to use a debounce function though (which can be canceled), would be easier than managing those timers.

Copy link
Contributor Author

@derhuerst derhuerst Jan 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should clear the timeouts and intervals before setting up new ones as a general statement.

Totally agree! Just didn't pay attention to the fact that startCachingReverses might be fired twice. 😛

Might want to use a debounce function though (which can be canceled), would be easier than managing those timers.

How would it be easier?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just to take into account a scenario where this gets called every 2 seconds let's say, thus clearing the timeouts and setting up a new one in 5 seconds, that would never get called

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, why waiting 5 seconds at first ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit this is kind of premature optimisation. It exists to reduce the load when the UI just loaded, as completion in the address selector is async anyway and far less important than say account balances.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay yes. Might be worth remembering this when working on the local storage cache issue :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference: #4096.

const addr = Object
.keys(this.reverse)
.find((addr) => {
if (addr.toLowerCase().slice(0, query.length) === query) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new RegExp('^' + query, 'i').test(addr) ?

}

const name = this.reverse[addr];
return name.toLowerCase().slice(0, query.length) === query;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name might be undefined right?

@ngotchac
Copy link
Contributor

ngotchac commented Jan 9, 2017

One question : why using a middleware here? (except to hook to the initAll call). Might be simpler with reducer + actions...

@ngotchac ngotchac added A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. and removed A0-pleasereview 🤓 Pull request needs code review. labels Jan 9, 2017
@@ -194,6 +239,8 @@ export default class AddressSelectStore {
.filter((result) => result && !ZERO.test(result.address));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might actually want to get rid of this.registryValues = []; line 231, to prevent the flickering when typing an autocompleted name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dangerous, especially when we have (or add in the future) long-running queries, as it will show incorrect values to the users for a while. I'd rather introduce a loading flag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yes that's true. The flickering is a bit odd, but no biggies

.instance
.reverse
.call({}, [ address ])
.then((reverse) => store.dispatch(setReverse(address, reverse)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to make sure that the reversed addressed actually changed ; Redux dispatches can be costly as they might re-render all connected Components.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to make sure that the reversed addressed actually changed;

Agree, keeping the nr of actions low is a nice thing.

Redux dispatches can be costly as they might re-render all connected Components.

It is not the job of Redux to make React performant. I'd rather fix the riffing/update logic in our components.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be another solution to let the reducer return the state directly. A future, less premature optimisation, would then be to use immutable state trees, which check oldState === newState.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Immutables would be really nice actually, not only in Redux. We had some issues with data being modified where it should not have been... And the thing is that at each action dispatch, the mapStateToProps will get called. So even if this returns non-updating results, it would still be nice to keep these calls low.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In private development, I use seamless-immutable, which only Object.freezes in dev mode to stay fast in production mode.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an interesting idea ! Would be worth trying IMO

@coveralls
Copy link

Coverage Status

Coverage increased (+0.06%) to 86.573% when pulling f12937a on jr-reverse-caching into 4c94878 on master.

@@ -36,6 +36,7 @@ export default class AddressSelectStore {
if (query.length === 0 || query === '0x') {
return null;
}
const startsWithQuery = (s) => new RegExp('^' + query, 'i').test(s);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ngotchac
Copy link
Contributor

Looks good to me, except the little flickering when typing a name. What about something like this:

diff --git a/js/src/ui/Form/AddressSelect/addressSelectStore.js b/js/src/ui/Form/AddressSelect/addressSelectStore.js
index 1c93088..50e02ba 100644
--- a/js/src/ui/Form/AddressSelect/addressSelectStore.js
+++ b/js/src/ui/Form/AddressSelect/addressSelectStore.js
@@ -228,10 +228,12 @@ export default class AddressSelectStore {
       });
 
     // Registries Lookup
-    this.registryValues = [];
-
     const lookups = this.regLookups.map((regLookup) => regLookup(value));
 
+    const timeoutId = window.setTimeout(() => {
+      this.registryValues = [];
+    }, 200);
+
     Promise
       .all(lookups)
       .then((results) => {
@@ -241,6 +243,8 @@ export default class AddressSelectStore {
       .then((results) => {
         results = uniqBy(results, (result) => result.address);
 
+        window.clearTimeout(timeoutId);
+
         this.registryValues = results
           .map((result) => {
             const lowercaseAddress = result.address.toLowerCase();

This would remove the values if the results are not fetched after 200ms.

@ngotchac ngotchac added A6-mustntgrumble 💦 Pull request has areas for improvement. The author need not address them before merging. and removed A5-grumble 🔥 Pull request has minor issues that must be addressed before merging. labels Jan 10, 2017
@derhuerst
Copy link
Contributor Author

derhuerst commented Jan 10, 2017

@ngotchac I'm definitely in favour of fixing this flickering, but not in this PR. Created #4103.

@jacogr jacogr added A8-looksgood 🦄 Pull request is reviewed well. and removed A6-mustntgrumble 💦 Pull request has areas for improvement. The author need not address them before merging. labels Jan 10, 2017
@derhuerst derhuerst merged commit 8958603 into master Jan 10, 2017
@derhuerst derhuerst deleted the jr-reverse-caching branch January 10, 2017 11:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants