Skip to content

Commit 8e6b5b5

Browse files
authored
Merge pull request #3041 from input-output-hk/feat/ddw-1125-analytics-prepare-release-backup
[DDW-1125] Analytics
2 parents 8f04188 + ef36d89 commit 8e6b5b5

File tree

70 files changed

+886
-191
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+886
-191
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## vNext
4+
5+
### Features
6+
7+
- Added analytics data collection ([PR 2927](https://github.com/input-output-hk/daedalus/pull/2927), [PR 2989](https://github.com/input-output-hk/daedalus/pull/2989), [PR 3003](https://github.com/input-output-hk/daedalus/pull/3003), [PR 3028](https://github.com/input-output-hk/daedalus/pull/3028))
8+
39
## 5.0.0
410

511
### Features

matomo.docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: "3"
2+
services:
3+
mariadb:
4+
image: docker.io/bitnami/mariadb:10.6
5+
environment:
6+
- ALLOW_EMPTY_PASSWORD=yes
7+
- MARIADB_USER=bn_matomo
8+
- MARIADB_DATABASE=bitnami_matomo
9+
- MARIADB_EXTRA_FLAGS=--max_allowed_packet=64MB
10+
volumes:
11+
- "matomo_db_data:/bitnami/mariadb"
12+
matomo:
13+
image: docker.io/bitnami/matomo:4
14+
ports:
15+
- "8080:8080"
16+
environment:
17+
- MATOMO_DATABASE_HOST=mariadb
18+
- MATOMO_DATABASE_PORT_NUMBER=3306
19+
- MATOMO_DATABASE_USER=bn_matomo
20+
- MATOMO_DATABASE_NAME=bitnami_matomo
21+
- MATOMO_USERNAME=user
22+
- MATOMO_PASSWORD=password
23+
- ALLOW_EMPTY_PASSWORD=yes
24+
volumes:
25+
- "matomo_data:/bitnami/matomo"
26+
depends_on:
27+
- mariadb
28+
volumes:
29+
matomo_db_data:
30+
driver: local
31+
matomo_data:
32+
driver: local

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@
242242
"inquirer": "7.3.3",
243243
"json-bigint": "1.0.0",
244244
"lodash": "4.17.21",
245-
"lodash-es": "4.17.21",
245+
"lodash-es": "4.17.15",
246+
"matomo-tracker": "2.2.4",
246247
"mime-types": "2.1.27",
247248
"mkdirp": "1.0.4",
248249
"mobx": "5.15.7",

source/main/environment.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const isPreview = checkIsPreview(NETWORK);
5050
const isShelleyQA = checkIsShelleyQA(NETWORK);
5151
const isSelfnode = checkIsSelfnode(NETWORK);
5252
const isDevelopment = checkIsDevelopment(NETWORK);
53-
const analyticsFeatureEnabled = isMainnet || isStaging || isTestnet;
53+
const analyticsFeatureEnabled = true;
5454
const keepLocalClusterRunning = process.env.KEEP_LOCAL_CLUSTER_RUNNING;
5555
const API_VERSION = process.env.API_VERSION || 'dev';
5656
const NODE_VERSION = '1.35.3'; // TODO: pick up this value from process.env

source/main/ipc/electronStoreConversation.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,7 @@ const unset = async (key: StorageKey) =>
2525
});
2626

2727
const reset = async () => {
28-
await unset(keys.APP_AUTOMATIC_UPDATE_FAILED);
29-
await unset(keys.APP_UPDATE_COMPLETED);
30-
await unset(keys.CURRENCY_ACTIVE);
31-
await unset(keys.CURRENCY_SELECTED);
32-
await unset(keys.DATA_LAYER_MIGRATION_ACCEPTANCE);
33-
await unset(keys.DISCREET_MODE_ENABLED);
34-
await unset(keys.DOWNLOAD_MANAGER);
35-
await unset(keys.HARDWARE_WALLET_DEVICES);
36-
await unset(keys.HARDWARE_WALLETS);
37-
await unset(keys.READ_NEWS);
38-
await unset(keys.SMASH_SERVER);
39-
await unset(keys.STAKING_INFO_WAS_OPEN);
40-
await unset(keys.STAKE_POOLS_LIST_VIEW_TOOLTIP);
41-
await unset(keys.TERMS_OF_USE_ACCEPTANCE);
42-
await unset(keys.THEME);
43-
await unset(keys.USER_DATE_FORMAT_ENGLISH);
44-
await unset(keys.USER_DATE_FORMAT_JAPANESE);
45-
await unset(keys.USER_LOCALE);
46-
await unset(keys.USER_NUMBER_FORMAT);
47-
await unset(keys.USER_TIME_FORMAT);
48-
await unset(keys.WALLET_MIGRATION_STATUS);
49-
await unset(keys.WALLETS);
50-
await unset(keys.WINDOW_BOUNDS);
28+
await Promise.all(Object.values(keys).map(unset));
5129
};
5230

5331
export const requestElectronStore = (request: ElectronStoreMessage) => {

source/renderer/app/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import NewsFeedContainer from './containers/news/NewsFeedContainer';
2222
import ToggleRTSFlagsDialogContainer from './containers/knownIssues/ToggleRTSFlagsDialogContainer';
2323
import RTSFlagsRecommendationOverlayContainer from './containers/knownIssues/RTSFlagsRecommendationOverlayContainer';
2424
import { MenuUpdater } from './containers/MenuUpdater';
25+
import { AnalyticsProvider } from './components/analytics';
26+
import { AnalyticsTracker } from './analytics';
2527

2628
@observer
2729
class App extends Component<{

source/renderer/app/Routes.tsx

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { Switch, Route, Redirect, withRouter } from 'react-router-dom';
2+
import { Redirect, Route, Switch, withRouter } from 'react-router-dom';
33
import { ROUTES } from './routes-config';
44
// PAGES
55
import Root from './containers/Root';
@@ -35,6 +35,7 @@ import WalletUtxoPage from './containers/wallet/WalletUtxoPage';
3535
import VotingRegistrationPage from './containers/voting/VotingRegistrationPage';
3636
import { IS_STAKING_INFO_PAGE_AVAILABLE } from './config/stakingConfig';
3737
import AnalyticsConsentPage from './containers/profile/AnalyticsConsentPage';
38+
import TrackedRoute from './analytics/TrackedRoute';
3839

3940
export const Routes = withRouter(() => (
4041
<Route path={ROUTES.ROOT}>
@@ -54,37 +55,58 @@ export const Routes = withRouter(() => (
5455
path={ROUTES.PROFILE.ANALYTICS}
5556
component={AnalyticsConsentPage}
5657
/>
57-
<Route
58+
<TrackedRoute
59+
pageTitle="Data Layer Migration Page"
5860
path={ROUTES.PROFILE.DATA_LAYER_MIGRATION}
5961
component={DataLayerMigrationPage}
6062
/>
61-
<Route path={ROUTES.WALLETS.ADD} component={WalletAddPage} />
63+
<TrackedRoute
64+
pageTitle="Add Wallet"
65+
path={ROUTES.WALLETS.ADD}
66+
component={WalletAddPage}
67+
/>
6268
<Route path={ROUTES.WALLETS.ROOT}>
6369
<Wallet>
6470
<Route
6571
exact
6672
path={ROUTES.WALLETS.ROOT}
6773
component={() => <Redirect to={ROUTES.WALLETS.SUMMARY} />}
6874
/>
69-
<Route
75+
<TrackedRoute
76+
pageTitle="Wallet Summary"
7077
path={ROUTES.WALLETS.SUMMARY}
7178
component={WalletSummaryPage}
7279
/>
73-
<Route path={ROUTES.WALLETS.SEND} component={WalletSendPage} />
74-
<Route
80+
<TrackedRoute
81+
pageTitle="Send Screen"
82+
path={ROUTES.WALLETS.SEND}
83+
component={WalletSendPage}
84+
/>
85+
<TrackedRoute
86+
pageTitle="Receive Screen"
7587
path={ROUTES.WALLETS.RECEIVE}
7688
component={WalletReceivePage}
7789
/>
78-
<Route path={ROUTES.WALLETS.TOKENS} component={WalletTokensPage} />
79-
<Route
90+
<TrackedRoute
91+
pageTitle="Tokens"
92+
path={ROUTES.WALLETS.TOKENS}
93+
component={WalletTokensPage}
94+
/>
95+
<TrackedRoute
96+
pageTitle="Transactions"
8097
path={ROUTES.WALLETS.TRANSACTIONS}
8198
component={WalletTransactionsPage}
8299
/>
83-
<Route
100+
<TrackedRoute
101+
pageTitle="Wallet Settings"
84102
path={ROUTES.WALLETS.SETTINGS}
85103
component={WalletSettingsPage}
86104
/>
87-
<Route path={ROUTES.WALLETS.UTXO} component={WalletUtxoPage} />
105+
<TrackedRoute
106+
pageTitle="Wallet UTxO distribution"
107+
path={ROUTES.WALLETS.UTXO}
108+
component={WalletUtxoPage}
109+
/>
88110
</Wallet>
89111
</Route>
90112
<Route path={ROUTES.SETTINGS.ROOT}>
@@ -94,31 +116,38 @@ export const Routes = withRouter(() => (
94116
path={ROUTES.SETTINGS.ROOT}
95117
component={() => <Redirect to={ROUTES.SETTINGS.GENERAL} />}
96118
/>
97-
<Route
119+
<TrackedRoute
120+
pageTitle="General Settings"
98121
path={ROUTES.SETTINGS.GENERAL}
99122
component={GeneralSettingsPage}
100123
/>
101-
<Route
124+
<TrackedRoute
125+
pageTitle="Wallets Settings"
102126
path={ROUTES.SETTINGS.WALLETS}
103127
component={WalletsSettingsPage}
104128
/>
105-
<Route
129+
<TrackedRoute
130+
pageTitle="Stake Pools Settings"
106131
path={ROUTES.SETTINGS.STAKE_POOLS}
107132
component={StakePoolsSettingsPage}
108133
/>
109-
<Route
134+
<TrackedRoute
135+
pageTitle="Terms of Use"
110136
path={ROUTES.SETTINGS.TERMS_OF_USE}
111137
component={TermsOfUseSettingsPage}
112138
/>
113-
<Route
139+
<TrackedRoute
140+
pageTitle="Support"
114141
path={ROUTES.SETTINGS.SUPPORT}
115142
component={SupportSettingsPage}
116143
/>
117-
<Route
144+
<TrackedRoute
145+
pageTitle="Display Settings"
118146
path={ROUTES.SETTINGS.DISPLAY}
119147
component={DisplaySettingsPage}
120148
/>
121-
<Route
149+
<TrackedRoute
150+
pageTitle="Security Settings"
122151
path={ROUTES.SETTINGS.SECURITY}
123152
component={SecuritySettingsPage}
124153
/>
@@ -137,33 +166,47 @@ export const Routes = withRouter(() => (
137166
<Redirect to={ROUTES.STAKING.DELEGATION_CENTER} />
138167
)}
139168
/>
140-
<Route
169+
<TrackedRoute
170+
pageTitle="Staking Countdown"
141171
path={ROUTES.STAKING.COUNTDOWN}
142172
component={StakingCountdownPage}
143173
/>
144-
<Route
174+
<TrackedRoute
175+
pageTitle="Delegation Center"
145176
path={ROUTES.STAKING.DELEGATION_CENTER}
146177
component={DelegationCenterPage}
147178
/>
148-
<Route
179+
<TrackedRoute
180+
pageTitle="Stake Pools List"
149181
path={ROUTES.STAKING.STAKE_POOLS}
150182
component={StakePoolsListPage}
151183
/>
152-
<Route
184+
<TrackedRoute
185+
pageTitle="Staking Rewards"
153186
path={ROUTES.STAKING.REWARDS}
154187
component={StakingRewardsPage}
155188
/>
156-
<Route path={ROUTES.STAKING.EPOCHS} component={StakingEpochsPage} />
189+
<TrackedRoute
190+
pageTitle="Staking Epochs"
191+
path={ROUTES.STAKING.EPOCHS}
192+
component={StakingEpochsPage}
193+
/>
157194
{IS_STAKING_INFO_PAGE_AVAILABLE && (
158-
<Route path={ROUTES.STAKING.INFO} component={StakingInfoPage} />
195+
<TrackedRoute
196+
pageTitle="Staking info"
197+
path={ROUTES.STAKING.INFO}
198+
component={StakingInfoPage}
199+
/>
159200
)}
160201
</Staking>
161-
<Route
202+
<TrackedRoute
203+
pageTitle="Redeem ITN rewards"
162204
path={ROUTES.REDEEM_ITN_REWARDS}
163205
component={RedeemItnRewardsContainer}
164206
/>
165207
</Route>
166-
<Route
208+
<TrackedRoute
209+
pageTitle="Voting Registration"
167210
path={ROUTES.VOTING.REGISTRATION}
168211
component={VotingRegistrationPage}
169212
/>

source/renderer/app/actions/wallets-actions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
import type { CsvFileContent } from '../../../common/types/csv-request.types';
88
import type { QuitStakePoolRequest } from '../api/staking/types';
99
import type { AssetToken } from '../api/assets/types';
10+
import Wallet from '../domains/Wallet';
1011

1112
export type WalletImportFromFileParams = {
1213
filePath: string;
@@ -76,13 +77,15 @@ export default class WalletsActions {
7677
note: string;
7778
address: string;
7879
filePath: string;
80+
wallet: Wallet;
7981
}> = new Action();
8082
generateAddressPDFSuccess: Action<{
8183
walletAddress: string;
8284
}> = new Action();
8385
saveQRCodeImage: Action<{
8486
address: string;
8587
filePath: string;
88+
wallet: Wallet;
8689
}> = new Action();
8790
saveQRCodeImageSuccess: Action<{
8891
walletAddress: string;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { AnalyticsAcceptanceStatus, AnalyticsTracker } from '.';
2+
import { AnalyticsClient } from './types';
3+
import { Environment } from '../../../common/types/environment.types';
4+
import LocalStorageApi from '../api/utils/localStorage';
5+
import { MatomoClient } from './MatomoClient';
6+
import { NoopAnalyticsClient } from './noopAnalyticsClient';
7+
8+
export class MatomoAnalyticsTracker implements AnalyticsTracker {
9+
#analyticsClient: AnalyticsClient;
10+
11+
constructor(
12+
private environment: Environment,
13+
private localStorageApi: LocalStorageApi
14+
) {
15+
this.#analyticsClient = NoopAnalyticsClient;
16+
this.#enableTrackingIfAccepted();
17+
}
18+
19+
async enableTracking() {
20+
this.#analyticsClient = new MatomoClient(
21+
this.environment,
22+
await this.localStorageApi.getUserID()
23+
);
24+
}
25+
26+
disableTracking() {
27+
this.#analyticsClient = NoopAnalyticsClient;
28+
}
29+
30+
sendPageNavigationEvent(pageTitle: string) {
31+
return this.#analyticsClient.sendPageNavigationEvent(pageTitle);
32+
}
33+
34+
sendEvent(category: string, name: string, action?: string) {
35+
return this.#analyticsClient.sendEvent(category, name, action);
36+
}
37+
38+
async #enableTrackingIfAccepted() {
39+
const analyticsAccepted =
40+
(await this.localStorageApi.getAnalyticsAcceptance()) ===
41+
AnalyticsAcceptanceStatus.ACCEPTED;
42+
43+
if (this.environment.analyticsFeatureEnabled && analyticsAccepted) {
44+
this.enableTracking();
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)