Skip to content
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

fix: webui update metrics to opt-out by default (part of 2074) #2084

Merged
merged 13 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions public/locales/en/status.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"peersCount": "{peersCount, plural, one {Discovered 1 peer} other {Discovered {peersCount} peers}}"
},
"customApiConfig": "Custom JSON configuration",
"AskToEnable": {
"label": "Help improve this app by sending anonymous usage data."
"AnalyticsBanner": {
"label": "We have recently updated our telemetry policy to switch to opt-out metrics. You previously had telemetry collection disabled. You can disable telemetry collection (again) on the settings page."
},
"tour": {
"step1": {
Expand Down
64 changes: 45 additions & 19 deletions src/bundles/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,21 @@ import { ACTIONS as EXP } from './experiments'
* @property {'ANALYTICS_ADD_CONSENT'} type
* @property {{name:string}} payload
*
* @typedef {Object} ToggleShowAnalyticsBanner
* @property {'SET_SHOW_ANALYTICS_BANNER'} type
* @property {{shouldShow:boolean?}} payload
*
* @typedef {ExperimentsToggle|DesktopSettingToggle} Toggle
* @typedef {MakeDir|Write|AddByPath|Move|Delete|DownloadLink} FilesMessage
* @typedef {AnalyticsEnabled|AnalyticsDisabled|RemoveConsent|AddConsent} AnalyticsMessage
* @typedef {AnalyticsEnabled|AnalyticsDisabled|RemoveConsent|AddConsent|ToggleShowAnalyticsBanner} AnalyticsMessage
* @typedef {Init|ConfigSave|Toggle|FilesMessage|AnalyticsMessage} Message
*
* @typedef {Object} Model
* @property {number} lastEnabledAt
* @property {number} lastDisabledAt
* @property {string[]} consent
* @property {boolean?} showAnalyticsBanner
* @property {boolean?} optedOut
*
* @typedef {Object} State
* @property {Model} analytics
Expand All @@ -72,7 +78,8 @@ const ACTIONS = Enum.from([
'ANALYTICS_ENABLED',
'ANALYTICS_DISABLED',
'ANALYTICS_ADD_CONSENT',
'ANALYTICS_REMOVE_CONSENT'
'ANALYTICS_REMOVE_CONSENT',
'SET_SHOW_ANALYTICS_BANNER'
])

// Only record specific actions listed here.
Expand Down Expand Up @@ -149,19 +156,18 @@ const selectors = {
*/
selectAnalyticsEnabled: (state) => state.analytics.consent.length > 0,
/**
* Ask the user if we may enable analytics.
* @param {State} state
*/
selectAnalyticsAskToEnable: (state) => {
const { lastEnabledAt, lastDisabledAt, consent } = state.analytics
// user has not explicitly chosen
if (!lastEnabledAt && !lastDisabledAt && consent.length === 0) {
// ask to enable.
return true
}
// user has already made an explicit choice; dont ask again.
return false
},
selectAnalyticsOptedOutPriorToDefaultOptIn: (state) => !state.analytics.optedOut && state.analytics.consent.length === 0 && state.analytics.lastDisabledAt > state.analytics.lastEnabledAt,
0xDanomite marked this conversation as resolved.
Show resolved Hide resolved
/**
* @param {State} state
*/
selectAnalyticsOptedOut: (state) => state.analytics.optedOut,
/**
* Show or hide the analytics banner.
* @param {State} state
*/
selectShowAnalyticsBanner: (state) => state.analytics.showAnalyticsBanner,

selectAnalyticsActionsToRecord: createSelector(
'selectIsIpfsDesktop',
Expand Down Expand Up @@ -257,6 +263,13 @@ const actions = {
}
addConsent(name, store)
dispatch({ type: 'ANALYTICS_ADD_CONSENT', payload: { name } })
},
/**
* @param {boolean?} shouldShow
* @returns {function(Context):void}
*/
doToggleShowAnalyticsBanner: (shouldShow) => ({ dispatch }) => {
dispatch({ type: 'SET_SHOW_ANALYTICS_BANNER', payload: { shouldShow } })
}
}

Expand All @@ -276,7 +289,8 @@ const createAnalyticsBundle = ({
ACTIONS.ANALYTICS_DISABLED,
ACTIONS.ANALYTICS_DISABLED,
ACTIONS.ANALYTICS_ADD_CONSENT,
ACTIONS.ANALYTICS_REMOVE_CONSENT
ACTIONS.ANALYTICS_REMOVE_CONSENT,
ACTIONS.SET_SHOW_ANALYTICS_BANNER
],

/**
Expand Down Expand Up @@ -310,10 +324,15 @@ const createAnalyticsBundle = ({
// Don't track clicks or links as it can include full url.
// Countly.q.push(['track_clicks'])
// Countly.q.push(['track_links'])
Comment on lines 324 to 326
Copy link
Member

Choose a reason for hiding this comment

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

just a note that we can filter out URLs that have CIDs (for any future readers)


if (store.selectAnalyticsEnabled()) {
const consent = store.selectAnalyticsConsent()
addConsent(consent, store)
SgtPooki marked this conversation as resolved.
Show resolved Hide resolved
} else if (!store.selectAnalyticsOptedOut()) {
if (store.selectAnalyticsOptedOutPriorToDefaultOptIn()) {
store.doToggleShowAnalyticsBanner(true)
}
// add consent/opt in by default
store.doEnableAnalytics()
}

store.subscribeToSelectors(['selectRouteInfo'], ({ routeInfo }) => {
Expand Down Expand Up @@ -371,22 +390,29 @@ const createAnalyticsBundle = ({
state = state || {
lastEnabledAt: 0,
lastDisabledAt: 0,
showAnalyticsBanner: false,
optedOut: false,
consent: []
}

switch (action.type) {
case ACTIONS.ANALYTICS_ENABLED:
return { ...state, lastEnabledAt: Date.now(), consent: action.payload.consent }
return { ...state, lastEnabledAt: Date.now(), consent: action.payload.consent, optedOut: false }
SgtPooki marked this conversation as resolved.
Show resolved Hide resolved
case ACTIONS.ANALYTICS_DISABLED:
return { ...state, lastDisabledAt: Date.now(), consent: action.payload.consent }
return { ...state, lastDisabledAt: Date.now(), consent: action.payload.consent, optedOut: true, showAnalyticsBanner: false }
SgtPooki marked this conversation as resolved.
Show resolved Hide resolved
case ACTIONS.ANALYTICS_ADD_CONSENT: {
const consent = state.consent.filter(item => item !== action.payload.name).concat(action.payload.name)
return { ...state, lastEnabledAt: Date.now(), consent }
return { ...state, lastEnabledAt: Date.now(), consent, optedOut: false }
0xDanomite marked this conversation as resolved.
Show resolved Hide resolved
}
case ACTIONS.ANALYTICS_REMOVE_CONSENT: {
const consent = state.consent.filter(item => item !== action.payload.name)
const lastDisabledAt = (consent.length === 0) ? Date.now() : state.lastDisabledAt
return { ...state, lastDisabledAt, consent }
const didOptOutCompletely = consent.length === 0
Comment on lines 409 to +410
Copy link
Contributor

Choose a reason for hiding this comment

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

you can also do:

const didOptOutCompletely = consent.length === 0
const lastDisabledAt = didOptOutCompletely ? Date.now() : state.lastDisabledAt 

This clears up the intentions, but another question that arises is this value will change every time if consent is not granted, do we want that?

return { ...state, lastDisabledAt, consent, optedOut: didOptOutCompletely, showAnalyticsBanner: false }
}
case ACTIONS.SET_SHOW_ANALYTICS_BANNER: {
const shouldShowAnalyticsBanner = action.payload?.shouldShow || false
return { ...state, showAnalyticsBanner: shouldShowAnalyticsBanner }
}
default: {
// deal with missing consent state from 2.4.0 release.
Expand Down
Loading