feat: send events saved before users opt-in#472
Conversation
There was a problem hiding this comment.
I think we don't need to check the type of value anymore, I fixed it last week and will return either true or false
There was a problem hiding this comment.
I'm removing this part. 👍
Just to confirm, Is it going to return false if a user has not opt-in/opt-out yet?
There was a problem hiding this comment.
For the initial start of the app(first time running app) it will not return false
Because there won't be any stored Redux state, this is the reason we've introduced defaultValue property to this method.
But on the second time when user execute the app, it will definitely return false
There was a problem hiding this comment.
Amazing that is exactly what we will need.
There was a problem hiding this comment.
Would it be better if we also set stored events to the empty array?
this.store.set('eventsBeforeMetricsOptIn', []);
It could get overloaded if the user switch back and forth
There was a problem hiding this comment.
100% I'm changing it now.
9eb0ca7 to
a6dbdc8
Compare
8ebb535 to
f59367f
Compare
There was a problem hiding this comment.
Would this be more useful after constructing eventToTrack as it would contain more info?
There was a problem hiding this comment.
Given we explicitly want to use the three states here, I think this is a little dangerous as we have to be exact with all our conditions despite it returning a boolean.
Perhaps it would be safer and more obvious if we return an enum such as MetricsDecision with values like ENABLED, DISABLED, and PENDING?
There was a problem hiding this comment.
Great point, I'm pushing the changes you suggested for this method.
There was a problem hiding this comment.
Do we not need the inverse condition here also to clear the array if we get a confirmed negative? Otherwise the pending events will just sit in memory until the app is restarted?
There was a problem hiding this comment.
yeap, I just changed it while I was refactoring this method. 💜
There was a problem hiding this comment.
Why are we saving every event? Is this part of the first time checks? Won't we only need to save unique event names?
There was a problem hiding this comment.
This was actually one of the behaviours that I've mimed from the extensions. Initially, I thought would be complementary to the first-time check solution but turns out it end up being much more simple the solution PR I can remove it for simplicity in the PR 483.
packages/app/src/app/ui/preload.ts
Outdated
There was a problem hiding this comment.
Will we ever have more than one analytics method or are we just matching the format of the store bridges?
If so, shall we push for simplicity and just have a track method directly on the electronBridge?
There was a problem hiding this comment.
In the PR to track first-time events I'm including identify. There are also page and screen that the extension uses and we might need to integrate them depending on how we move further with the metrics.
There was a problem hiding this comment.
If we think of the UI as purely a display of the background state, then we don't want to couple our metrics to the UI, but to the underlying background logic whenever possible. This ensures we're tracking events as low as possible in case we remove it from the UI and forget, or the UI failures for whatever reason.
This invalid OTP event for example should be fired from: packages/app/src/app/pairing.ts.
There was a problem hiding this comment.
Totally, I'm removing it from the UI this was more to test the bridge.
abb6d50 to
919ced6
Compare
bb2db6c to
544efea
Compare
There was a problem hiding this comment.
Doesn't analytics.identify also send a request to Segment?
If so, shouldn't we also maintain an array of these identify requests while pending to be sent later?
There was a problem hiding this comment.
Yes, It sends to Segment but only when users agree. In the PR infrastructure for the first time event I'm saving the traits locally because traits are attached whenever we send an event using track method. Currently, that is the important part for us, but we still need to discuss the usage of identity with the Data & Analytics team.
There was a problem hiding this comment.
Sorry if i'm missing something but won't the current code send requests to Segment if the decision is still pending?
There was a problem hiding this comment.
@vinistevam what @matthewwalsh0 is saying is that even on that PR we are sending an identity event to Segment even if the MetricsDecision.PENDING.. we should only send when MetricsDecision.ENABLED.
There was a problem hiding this comment.
Sorry guys, totally my fault. I pushed a fix for that only allowing identify to send to segment when MetricsDecision.ENABLED
There was a problem hiding this comment.
We should validate right at the top of this method. There's no point in setting a desktopMetricsId, or building the context on the event to track, if the user does not want to be tracked.
Plus having early returns makes the code much easier to read.
if (metricsDecision === MetricsDecision.DISABLED) {
return;
}
... code ...
if (metricsDecision === MetricsDecision.PENDING) {
this.eventsSavedBeforeMetricsDecision.push(eventToTrack);
return;
}
...There was a problem hiding this comment.
Great point, I'm pushing this change.
There was a problem hiding this comment.
This seems overly complex and has some side effects. getMetricsDecision should not be responsible for sendPendingEvents or cleanPendingEvents..
Those are consequences of the decision. We should move those out of this method (probably to the place where the desktopMetricsOptIn value is stored.. like when user opts in/out we should get an event on the main process notifying it to send or clean pending events.. Probably the event is already getting to the main process on ipcMain.handle(${name}-store-set`. Not sure if reusing that would be the best though or if we should add another specific event for it.)
Removing those would also make this method much much simpler. Could be something like this
const defaultValue = undefined;
...
if (desktopMetricsOptIn === defaultValue) {
return MetricsDecision.PENDING;
}
return desktopMetricsOptIn === true ? MetricsDecision.ENABLED : MetricsDecision.DISABLED;There was a problem hiding this comment.
Agree, I created a new event in the electron bridge to be invoked when users take the metrics decision and that will be responsible to send or clean the events saved before the user's decision.
32df9e1 to
634f27c
Compare
634f27c to
0bbaf10
Compare
| const metricsDecision = this.getMetricsDecision(); | ||
| if (metricsDecision === MetricsDecision.DISABLED) { | ||
| return; | ||
| } else if (metricsDecision === MetricsDecision.PENDING) { |
There was a problem hiding this comment.
Remove else if return. We want to enable no-else-return (https://eslint.org/docs/latest/rules/no-else-return). (I though that we had it enabled.. but apparently not).
if (...) {
return;
}
if (...) {
return
}
returnThere was a problem hiding this comment.
thanks for pointing that out.
Just to keep documented here as well, it was fixed on commit: dc0c381
Overview
The aim of this PR is to implement a method to flush events saved before users opt-in/opt-out and as a prerequisite of this ticket a mechanism to get the option chosen by the users on the metrics page.
Changes
trackmethod on the electron bridge and handle it in the main process.participateInDesktopMetricsinmetrics-service.tsand usedreadPersistedSettingFromAppStateto getmetametricsOptIn.sendPendingEvents()to send events saved before the user opt-in.Others
Issues
resolves: #455 and #464