Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Have Dashboard politely ask users occasionally if they'll share telemetry #5827

Merged
merged 5 commits into from
Jan 12, 2023

Conversation

cliffoo
Copy link
Contributor

@cliffoo cliffoo commented Jan 10, 2023

Addresses: #4828

Use dashboard to prompt our users to graciously enable analytics.

Behavior on load:

flowchart TD
  A{"Has the user explicitly<br/>opted in/out before?<br />(via the config command,<br />or much less likely, editing<br />the user config manually)"} -->|no| B([Ask to enable analytics])
  A -->|yes| C{Is analytics enabled?}
  C -->|no| D{Has it been a year since<br/>user last said no?}
  C -->|yes| E([OK])
  D -->|no| E
  D -->|yes, ask again| B
Loading

How?

DashboardServer's express server has two new endpoints: POST and GET at /analytics. Their corresponding handlers read and write to the user config object, which in turn modifies the config file on disk. Frontend just interacts with /analytics and manages notifications as needed.

Wording

The prompt content (located at src/utils/notifications/analytics.tsx) mostly follows that of the previous PR (#5290).

Testing instructions

  1. Locate your Truffle user config file (likely at ~/.config/truffle-nodejs/config.json)
  2. Inside this user config file, remove enableAnalytics, analyticsSet, analyticsMessageDateTime for a clean slate, maybe uniqueId also. Continue if these fields are not present.
  3. Start and open dashboard. You will be prompted to enable analytics, click Enable.
  4. Verify that the config file is updated with analytics enabled. Repeat step 1 for clean slate.
  5. Refresh dashboard. This time when you're prompted click Dismiss.
  6. Verify that the config file is updated with analytics disabled. Edit analyticsMessageDateTime to 1 (no quotes!).
  7. Refresh dashboard. You will be prompted to enable analytics, but with slightly different text.

Related:

Co-authored-by: fainashalts <[email protected]>
Co-authored-by: liang liang <[email protected]>
"Telemetry data" => "Telemetry"
Copy link
Contributor

@gnidan gnidan left a comment

Choose a reason for hiding this comment

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

This looks good. Happy to approve tomorrow; just want to give others a chance to take a look first.

Thanks @cliffoo!

packages/dashboard/lib/DashboardServer.ts Outdated Show resolved Hide resolved
packages/dashboard/src/components/composed/Layout.tsx Outdated Show resolved Hide resolved
Comment on lines 40 to 41
Date.now() - analyticsConfig.analyticsMessageDateTime! >
ARBITRARY_ANALYTICS_NEXT_ASK_THRESHOLD;
Copy link
Contributor

@gnidan gnidan Jan 11, 2023

Choose a reason for hiding this comment

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

Note that this kind of math is rife with edge cases around leap years and whatnot. Better if we can do a proper duration check vs. millisecond arithmetic and assuming we know how many milliseconds a year is.

Happy to accept an issue for this instead of fixing it now.

Copy link
Contributor

Choose a reason for hiding this comment

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

(OK, if this triggers a day early, it doesn't really matter. But still... good practice not to assume you can just subtract dates like that)

Copy link
Member

Choose a reason for hiding this comment

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

https://date-fns.org/ may be a viable option

Copy link
Member

Choose a reason for hiding this comment

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

Happy to accept an issue for this instead of fixing it now.

+1

Copy link
Contributor Author

@cliffoo cliffoo Jan 11, 2023

Choose a reason for hiding this comment

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

Good point! I've changed this to compare Date objects instead. The logic is as follows:

const askAfter = new Date(lastAskedInMs);
askAfter.setDate(askAfter.getDate() + 365);

if (new Date() > askAfter) // Ask again!

Note that this is affected by leap years. We can fix it by using the pair setFullYear and getFullYear instead of setDate and getDate, but I figured days are easier to work with if we later want to change this threshold to some other number of days.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we wanted to be super accurate, the way to do this would be to do, like, add(date, thresholdDuration), where thresholdDuration = { years: 1 }, then check against that.

But it's okay. If you say "no" on 2023-12-01 and we ask again on 2024-11-30... kinda trivial.

@gnidan gnidan changed the title Dashboard analytics Have Dashboard politely ask users occasionally if they'll share telemetry Jan 11, 2023
Cliff Zhang added 3 commits January 11, 2023 10:37
To figure out if the user should be prompted again to opt in for analytics
When asking user to re-consider opting in for analytics
@@ -13,6 +13,7 @@ export interface ContextValue {
lifecycle: ReceivedMessageLifecycle<DashboardProviderMessage>
) => any;
toggleNotice: () => void;
updateAnalyticsConfig: (value: boolean) => void;
Copy link
Contributor

Choose a reason for hiding this comment

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

So for this sorta thing, I'll also note that, in situations like this, you might consider getting into the habit of making separate operations for enable vs. disable. It feels a bit more hygienic: enableAnalytics() and disableAnalytics() are more clear and succinct compared to updateAnalyticsConfig(true) and updateAnalyticsConfig(false).

(There are downsides here, of course, like having to pass an extra function around in the context here, but my personal stance is that it's worth it to have operations align with specific user actions)

Copy link
Contributor

@fainashalts fainashalts left a comment

Choose a reason for hiding this comment

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

LGTM! I think the language is very polite and clear! I agree with @gnidan on separating enableAnalytics() and disableAnalytics() but that can be done as follow-on work if desired. :)


type NotificationPropsWithId = NotificationProps & { id: string };

export const analyticsNotificationId = "analytics";
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious, what is this id used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah this is so that an id can be assigned to a specific notification, so we can reference that notification later and make changes to it.

Here the notification with id "analytics" is updated to show hey thanks for enabling telemetry when user clicks enable, and hidden when user click no.

Copy link
Contributor

@eggplantzzz eggplantzzz left a comment

Choose a reason for hiding this comment

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

i like it

@cliffoo cliffoo merged commit 8d2b9f2 into develop Jan 12, 2023
@cliffoo cliffoo deleted the dash-analytics branch January 12, 2023 19:41
@eggplantzzz eggplantzzz mentioned this pull request Jan 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants