Browse Source

chore: Remove tracking (#2722)

* chore: Remove tracking

* process

* rename

* remove

* prod

* Update public/index.html

Co-authored-by: David Luzar <luzar.david@gmail.com>

* Update public/index.html

* eol

* more

* stats

Co-authored-by: David Luzar <luzar.david@gmail.com>
vanilla_orig
Lipis 4 years ago
parent
commit
3aa01ad272
No account linked to committer's email address

+ 1
- 1
.env.production View File

1
-REACT_APP_INCLUDE_GTAG=true
1
+REACT_APP_GOOGLE_ANALYTICS_ID=UA-387204-13

+ 0
- 1
Dockerfile View File

5
 COPY package.json package-lock.json ./
5
 COPY package.json package-lock.json ./
6
 RUN npm i --no-optional
6
 RUN npm i --no-optional
7
 
7
 
8
-ARG REACT_APP_INCLUDE_GTAG=false
9
 ARG NODE_ENV=production
8
 ARG NODE_ENV=production
10
 
9
 
11
 COPY . .
10
 COPY . .

+ 0
- 64
analytics.md View File

1
-| Excalidraw              | Category | Name                               | Label                           | Value     |
2
-| ----------------------- | -------- | ---------------------------------- | ------------------------------- | --------- |
3
-| Shape / Selection       | shape    | selection, rectangle, diamond, etc | `toolbar` or `shortcut`         |
4
-| Text on double click    | shape    | text                               | `double-click`                  |
5
-| Lock selection          | shape    | lock                               | `on` or `off`                   |
6
-| Clear canvas            | action   | clear canvas                       |
7
-| Zoom in                 | action   | zoom                               | in                              | `zoom`    |
8
-| Zoom out                | action   | zoom                               | out                             | `zoom`    |
9
-| Zoom fit                | action   | zoom                               | fit                             | `zoom`    |
10
-| Zoom reset              | action   | zoom                               | reset                           | `zoom`    |
11
-| Scroll back to content  | action   | scroll to content                  |
12
-| Load file               | io       | load                               | `MIME type`                     |
13
-| Import from URL         | io       | import                             |
14
-| Save                    | io       | save                               |
15
-| Save as                 | io       | save as                            |
16
-| Export to backend       | io       | export                             | backend                         |
17
-| Export as SVG           | io       | export                             | `svg` or `clipboard-svg`        |
18
-| Export to PNG           | io       | export                             | `png` or `clipboard-png`        |
19
-| Canvas color            | change   | canvas color                       | `color`                         |
20
-| Background color        | change   | background color                   | `color`                         |
21
-| Stroke color            | change   | stroke color                       | `color`                         |
22
-| Stroke width            | change   | stroke                             | width                           | `width`   |
23
-| Stroke style            | change   | style                              | `solid` or `dashed` or `dotted` |
24
-| Stroke sloppiness       | change   | stroke                             | sloppiness                      | `value`   |
25
-| Fill                    | change   | fill                               | `value`                         |
26
-| Edge                    | change   | edge                               | `value`                         |
27
-| Opacity                 | change   | opacity                            | value                           | `opacity` |
28
-| Project name            | change   | title                              |
29
-| Theme                   | change   | theme                              | `light` or `dark`               |
30
-| Change language         | change   | language                           | `language`                      |
31
-| Send to back            | layer    | move                               | `back`                          |
32
-| Send backward           | layer    | move                               | `down`                          |
33
-| Bring to front          | layer    | move                               | `front`                         |
34
-| Bring forward           | layer    | move                               | `up`                            |
35
-| Align left              | align    | align                              | `left`                          |
36
-| Align right             | align    | align                              | `right`                         |
37
-| Align top               | align    | align                              | `top`                           |
38
-| Align bottom            | align    | align                              | `bottom`                        |
39
-| Center horizontally     | align    | horizontally                       | `center`                        |
40
-| Center vertically       | align    | vertically                         | `center`                        |
41
-| Distribute horizontally | align    | distribute                         | `horizontally`                  |
42
-| Distribute vertically   | align    | distribute                         | `vertically`                    |
43
-| Start session           | share    | session start                      |
44
-| Join session            | share    | session join                       |
45
-| Start end               | share    | session end                        |
46
-| Copy room link          | share    | copy link                          |
47
-| Go to collaborator      | share    | go to collaborator                 |
48
-| Change name             | share    | name                               |
49
-| Add to library          | library  | add                                |
50
-| Remove from library     | library  | remove                             |
51
-| Load library            | library  | load                               |
52
-| Save library            | library  | save                               |
53
-| Import library          | library  | import                             |
54
-| Shortcuts dialog        | dialog   | shortcuts                          |
55
-| Collaboration dialog    | dialog   | collaboration                      |
56
-| Export dialog           | dialog   | export                             |
57
-| Library dialog          | dialog   | library                            |
58
-| E2EE shield             | exit     | e2ee shield                        |
59
-| GitHub corner           | exit     | github                             |
60
-| Excalidraw blog         | exit     | blog                               |
61
-| Excalidraw guides       | exit     | guides                             |
62
-| File issues             | exit     | issues                             |
63
-| First load              | load     | first load                         |
64
-| Load from stroage       | load     | storage                            | size                            | `bytes`   |

+ 2
- 2
package.json View File

81
   "private": true,
81
   "private": true,
82
   "scripts": {
82
   "scripts": {
83
     "build-node": "node ./scripts/build-node.js",
83
     "build-node": "node ./scripts/build-node.js",
84
-    "build:app:docker": "REACT_APP_INCLUDE_GTAG=false REACT_APP_DISABLE_SENTRY=true react-scripts build",
85
-    "build:app": "REACT_APP_INCLUDE_GTAG=true REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build",
84
+    "build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build",
85
+    "build:app": "REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build",
86
     "build:version": "node ./scripts/build-version.js",
86
     "build:version": "node ./scripts/build-version.js",
87
     "build": "npm run build:app && npm run build:version",
87
     "build": "npm run build:app && npm run build:version",
88
     "eject": "react-scripts eject",
88
     "eject": "react-scripts eject",

+ 3
- 3
public/index.html View File

86
 
86
 
87
     <link rel="stylesheet" href="fonts.css" type="text/css" />
87
     <link rel="stylesheet" href="fonts.css" type="text/css" />
88
 
88
 
89
-    <% if (process.env.REACT_APP_INCLUDE_GTAG === 'true') { %>
89
+    <% if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) { %>
90
     <script
90
     <script
91
       async
91
       async
92
-      src="https://www.googletagmanager.com/gtag/js?id=UA-387204-13"
92
+      src="https://www.googletagmanager.com/gtag/js?id=%REACT_APP_GOOGLE_ANALYTICS_ID%"
93
     ></script>
93
     ></script>
94
     <script>
94
     <script>
95
       window.dataLayer = window.dataLayer || [];
95
       window.dataLayer = window.dataLayer || [];
97
         dataLayer.push(arguments);
97
         dataLayer.push(arguments);
98
       }
98
       }
99
       gtag("js", new Date());
99
       gtag("js", new Date());
100
-      gtag("config", "UA-387204-13");
100
+      gtag("config", "%REACT_APP_GOOGLE_ANALYTICS_ID%");
101
     </script>
101
     </script>
102
     <% } %>
102
     <% } %>
103
 
103
 

+ 0
- 2
src/actions/actionAddToLibrary.ts View File

3
 import { getNonDeletedElements } from "../element";
3
 import { getNonDeletedElements } from "../element";
4
 import { deepCopyElement } from "../element/newElement";
4
 import { deepCopyElement } from "../element/newElement";
5
 import { Library } from "../data/library";
5
 import { Library } from "../data/library";
6
-import { EVENT_LIBRARY, trackEvent } from "../analytics";
7
 
6
 
8
 export const actionAddToLibrary = register({
7
 export const actionAddToLibrary = register({
9
   name: "addToLibrary",
8
   name: "addToLibrary",
16
     Library.loadLibrary().then((items) => {
15
     Library.loadLibrary().then((items) => {
17
       Library.saveLibrary([...items, selectedElements.map(deepCopyElement)]);
16
       Library.saveLibrary([...items, selectedElements.map(deepCopyElement)]);
18
     });
17
     });
19
-    trackEvent(EVENT_LIBRARY, "add");
20
     return false;
18
     return false;
21
   },
19
   },
22
   contextMenuOrder: 6,
20
   contextMenuOrder: 6,

+ 6
- 13
src/actions/actionAlign.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { KEYS } from "../keys";
3
-import { t } from "../i18n";
4
-import { register } from "./register";
2
+import { alignElements, Alignment } from "../align";
5
 import {
3
 import {
6
   AlignBottomIcon,
4
   AlignBottomIcon,
7
   AlignLeftIcon,
5
   AlignLeftIcon,
10
   CenterHorizontallyIcon,
8
   CenterHorizontallyIcon,
11
   CenterVerticallyIcon,
9
   CenterVerticallyIcon,
12
 } from "../components/icons";
10
 } from "../components/icons";
13
-import { getSelectedElements, isSomeElementSelected } from "../scene";
14
-import { getElementMap, getNonDeletedElements } from "../element";
15
 import { ToolButton } from "../components/ToolButton";
11
 import { ToolButton } from "../components/ToolButton";
12
+import { getElementMap, getNonDeletedElements } from "../element";
16
 import { ExcalidrawElement } from "../element/types";
13
 import { ExcalidrawElement } from "../element/types";
14
+import { t } from "../i18n";
15
+import { KEYS } from "../keys";
16
+import { getSelectedElements, isSomeElementSelected } from "../scene";
17
 import { AppState } from "../types";
17
 import { AppState } from "../types";
18
-import { alignElements, Alignment } from "../align";
19
 import { getShortcutKey } from "../utils";
18
 import { getShortcutKey } from "../utils";
20
-import { trackEvent, EVENT_ALIGN } from "../analytics";
19
+import { register } from "./register";
21
 
20
 
22
 const enableActionGroup = (
21
 const enableActionGroup = (
23
   elements: readonly ExcalidrawElement[],
22
   elements: readonly ExcalidrawElement[],
44
 export const actionAlignTop = register({
43
 export const actionAlignTop = register({
45
   name: "alignTop",
44
   name: "alignTop",
46
   perform: (elements, appState) => {
45
   perform: (elements, appState) => {
47
-    trackEvent(EVENT_ALIGN, "align", "top");
48
     return {
46
     return {
49
       appState,
47
       appState,
50
       elements: alignSelectedElements(elements, appState, {
48
       elements: alignSelectedElements(elements, appState, {
74
 export const actionAlignBottom = register({
72
 export const actionAlignBottom = register({
75
   name: "alignBottom",
73
   name: "alignBottom",
76
   perform: (elements, appState) => {
74
   perform: (elements, appState) => {
77
-    trackEvent(EVENT_ALIGN, "align", "bottom");
78
     return {
75
     return {
79
       appState,
76
       appState,
80
       elements: alignSelectedElements(elements, appState, {
77
       elements: alignSelectedElements(elements, appState, {
104
 export const actionAlignLeft = register({
101
 export const actionAlignLeft = register({
105
   name: "alignLeft",
102
   name: "alignLeft",
106
   perform: (elements, appState) => {
103
   perform: (elements, appState) => {
107
-    trackEvent(EVENT_ALIGN, "align", "left");
108
     return {
104
     return {
109
       appState,
105
       appState,
110
       elements: alignSelectedElements(elements, appState, {
106
       elements: alignSelectedElements(elements, appState, {
134
 export const actionAlignRight = register({
130
 export const actionAlignRight = register({
135
   name: "alignRight",
131
   name: "alignRight",
136
   perform: (elements, appState) => {
132
   perform: (elements, appState) => {
137
-    trackEvent(EVENT_ALIGN, "align", "right");
138
     return {
133
     return {
139
       appState,
134
       appState,
140
       elements: alignSelectedElements(elements, appState, {
135
       elements: alignSelectedElements(elements, appState, {
164
 export const actionAlignVerticallyCentered = register({
159
 export const actionAlignVerticallyCentered = register({
165
   name: "alignVerticallyCentered",
160
   name: "alignVerticallyCentered",
166
   perform: (elements, appState) => {
161
   perform: (elements, appState) => {
167
-    trackEvent(EVENT_ALIGN, "vertically", "center");
168
     return {
162
     return {
169
       appState,
163
       appState,
170
       elements: alignSelectedElements(elements, appState, {
164
       elements: alignSelectedElements(elements, appState, {
190
 export const actionAlignHorizontallyCentered = register({
184
 export const actionAlignHorizontallyCentered = register({
191
   name: "alignHorizontallyCentered",
185
   name: "alignHorizontallyCentered",
192
   perform: (elements, appState) => {
186
   perform: (elements, appState) => {
193
-    trackEvent(EVENT_ALIGN, "horizontally", "center");
194
     return {
187
     return {
195
       appState,
188
       appState,
196
       elements: alignSelectedElements(elements, appState, {
189
       elements: alignSelectedElements(elements, appState, {

+ 0
- 17
src/actions/actionCanvas.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
3
 import { getDefaultAppState } from "../appState";
2
 import { getDefaultAppState } from "../appState";
4
-import colors from "../colors";
5
 import { ColorPicker } from "../components/ColorPicker";
3
 import { ColorPicker } from "../components/ColorPicker";
6
 import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
4
 import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
7
 import { ToolButton } from "../components/ToolButton";
5
 import { ToolButton } from "../components/ToolButton";
21
 export const actionChangeViewBackgroundColor = register({
19
 export const actionChangeViewBackgroundColor = register({
22
   name: "changeViewBackgroundColor",
20
   name: "changeViewBackgroundColor",
23
   perform: (_, appState, value) => {
21
   perform: (_, appState, value) => {
24
-    if (value !== appState.viewBackgroundColor) {
25
-      trackEvent(
26
-        EVENT_CHANGE,
27
-        "canvas color",
28
-        colors.canvasBackground.includes(value)
29
-          ? `${value} (picker ${colors.canvasBackground.indexOf(value)})`
30
-          : value,
31
-      );
32
-    }
33
     return {
22
     return {
34
       appState: { ...appState, viewBackgroundColor: value },
23
       appState: { ...appState, viewBackgroundColor: value },
35
       commitToHistory: true,
24
       commitToHistory: true,
52
 export const actionClearCanvas = register({
41
 export const actionClearCanvas = register({
53
   name: "clearCanvas",
42
   name: "clearCanvas",
54
   perform: (elements, appState: AppState) => {
43
   perform: (elements, appState: AppState) => {
55
-    trackEvent(EVENT_ACTION, "clear canvas");
56
     return {
44
     return {
57
       elements: elements.map((element) =>
45
       elements: elements.map((element) =>
58
         newElementWith(element, { isDeleted: true }),
46
         newElementWith(element, { isDeleted: true }),
98
       { left: appState.offsetLeft, top: appState.offsetTop },
86
       { left: appState.offsetLeft, top: appState.offsetTop },
99
       { x: appState.width / 2, y: appState.height / 2 },
87
       { x: appState.width / 2, y: appState.height / 2 },
100
     );
88
     );
101
-    trackEvent(EVENT_ACTION, "zoom", "in", zoom.value * 100);
102
     return {
89
     return {
103
       appState: {
90
       appState: {
104
         ...appState,
91
         ...appState,
133
       { x: appState.width / 2, y: appState.height / 2 },
120
       { x: appState.width / 2, y: appState.height / 2 },
134
     );
121
     );
135
 
122
 
136
-    trackEvent(EVENT_ACTION, "zoom", "out", zoom.value * 100);
137
     return {
123
     return {
138
       appState: {
124
       appState: {
139
         ...appState,
125
         ...appState,
161
 export const actionResetZoom = register({
147
 export const actionResetZoom = register({
162
   name: "resetZoom",
148
   name: "resetZoom",
163
   perform: (_elements, appState) => {
149
   perform: (_elements, appState) => {
164
-    trackEvent(EVENT_ACTION, "zoom", "reset", 100);
165
     return {
150
     return {
166
       appState: {
151
       appState: {
167
         ...appState,
152
         ...appState,
234
     left: appState.offsetLeft,
219
     left: appState.offsetLeft,
235
     top: appState.offsetTop,
220
     top: appState.offsetTop,
236
   });
221
   });
237
-  const action = zoomToSelection ? "selection" : "fit";
238
 
222
 
239
   const [x1, y1, x2, y2] = commonBounds;
223
   const [x1, y1, x2, y2] = commonBounds;
240
   const centerX = (x1 + x2) / 2;
224
   const centerX = (x1 + x2) / 2;
241
   const centerY = (y1 + y2) / 2;
225
   const centerY = (y1 + y2) / 2;
242
-  trackEvent(EVENT_ACTION, "zoom", action, newZoom.value * 100);
243
   return {
226
   return {
244
     appState: {
227
     appState: {
245
       ...appState,
228
       ...appState,

+ 6
- 9
src/actions/actionDistribute.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { CODES } from "../keys";
3
-import { t } from "../i18n";
4
-import { register } from "./register";
5
 import {
2
 import {
6
   DistributeHorizontallyIcon,
3
   DistributeHorizontallyIcon,
7
   DistributeVerticallyIcon,
4
   DistributeVerticallyIcon,
8
 } from "../components/icons";
5
 } from "../components/icons";
9
-import { getSelectedElements, isSomeElementSelected } from "../scene";
10
-import { getElementMap, getNonDeletedElements } from "../element";
11
 import { ToolButton } from "../components/ToolButton";
6
 import { ToolButton } from "../components/ToolButton";
7
+import { distributeElements, Distribution } from "../disitrubte";
8
+import { getElementMap, getNonDeletedElements } from "../element";
12
 import { ExcalidrawElement } from "../element/types";
9
 import { ExcalidrawElement } from "../element/types";
10
+import { t } from "../i18n";
11
+import { CODES } from "../keys";
12
+import { getSelectedElements, isSomeElementSelected } from "../scene";
13
 import { AppState } from "../types";
13
 import { AppState } from "../types";
14
-import { distributeElements, Distribution } from "../disitrubte";
15
 import { getShortcutKey } from "../utils";
14
 import { getShortcutKey } from "../utils";
16
-import { EVENT_ALIGN, trackEvent } from "../analytics";
15
+import { register } from "./register";
17
 
16
 
18
 const enableActionGroup = (
17
 const enableActionGroup = (
19
   elements: readonly ExcalidrawElement[],
18
   elements: readonly ExcalidrawElement[],
40
 export const distributeHorizontally = register({
39
 export const distributeHorizontally = register({
41
   name: "distributeHorizontally",
40
   name: "distributeHorizontally",
42
   perform: (elements, appState) => {
41
   perform: (elements, appState) => {
43
-    trackEvent(EVENT_ALIGN, "distribute", "horizontally");
44
     return {
42
     return {
45
       appState,
43
       appState,
46
       elements: distributeSelectedElements(elements, appState, {
44
       elements: distributeSelectedElements(elements, appState, {
69
 export const distributeVertically = register({
67
 export const distributeVertically = register({
70
   name: "distributeVertically",
68
   name: "distributeVertically",
71
   perform: (elements, appState) => {
69
   perform: (elements, appState) => {
72
-    trackEvent(EVENT_ALIGN, "distribute", "vertically");
73
     return {
70
     return {
74
       appState,
71
       appState,
75
       elements: distributeSelectedElements(elements, appState, {
72
       elements: distributeSelectedElements(elements, appState, {

+ 4
- 7
src/actions/actionExport.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { EVENT_CHANGE, EVENT_IO, trackEvent } from "../analytics";
3
-import { load, save, saveAs } from "../components/icons";
2
+import { trackEvent } from "../analytics";
3
+import { load, questionCircle, save, saveAs } from "../components/icons";
4
 import { ProjectName } from "../components/ProjectName";
4
 import { ProjectName } from "../components/ProjectName";
5
 import { ToolButton } from "../components/ToolButton";
5
 import { ToolButton } from "../components/ToolButton";
6
+import "../components/ToolIcon.scss";
6
 import { Tooltip } from "../components/Tooltip";
7
 import { Tooltip } from "../components/Tooltip";
7
-import { questionCircle } from "../components/icons";
8
 import { loadFromJSON, saveAsJSON } from "../data";
8
 import { loadFromJSON, saveAsJSON } from "../data";
9
 import { t } from "../i18n";
9
 import { t } from "../i18n";
10
 import useIsMobile from "../is-mobile";
10
 import useIsMobile from "../is-mobile";
11
 import { KEYS } from "../keys";
11
 import { KEYS } from "../keys";
12
 import { muteFSAbortError } from "../utils";
12
 import { muteFSAbortError } from "../utils";
13
 import { register } from "./register";
13
 import { register } from "./register";
14
-import "../components/ToolIcon.scss";
15
 
14
 
16
 export const actionChangeProjectName = register({
15
 export const actionChangeProjectName = register({
17
   name: "changeProjectName",
16
   name: "changeProjectName",
18
   perform: (_elements, appState, value) => {
17
   perform: (_elements, appState, value) => {
19
-    trackEvent(EVENT_CHANGE, "title");
18
+    trackEvent("change", "title");
20
     return { appState: { ...appState, name: value }, commitToHistory: false };
19
     return { appState: { ...appState, name: value }, commitToHistory: false };
21
   },
20
   },
22
   PanelComponent: ({ appState, updateData }) => (
21
   PanelComponent: ({ appState, updateData }) => (
100
   perform: async (elements, appState, value) => {
99
   perform: async (elements, appState, value) => {
101
     try {
100
     try {
102
       const { fileHandle } = await saveAsJSON(elements, appState);
101
       const { fileHandle } = await saveAsJSON(elements, appState);
103
-      trackEvent(EVENT_IO, "save");
104
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
102
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
105
     } catch (error) {
103
     } catch (error) {
106
       if (error?.name !== "AbortError") {
104
       if (error?.name !== "AbortError") {
131
         ...appState,
129
         ...appState,
132
         fileHandle: null,
130
         fileHandle: null,
133
       });
131
       });
134
-      trackEvent(EVENT_IO, "save as");
135
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
132
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
136
     } catch (error) {
133
     } catch (error) {
137
       if (error?.name !== "AbortError") {
134
       if (error?.name !== "AbortError") {

+ 0
- 2
src/actions/actionMenu.tsx View File

7
 import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils";
7
 import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils";
8
 import { CODES, KEYS } from "../keys";
8
 import { CODES, KEYS } from "../keys";
9
 import { HelpIcon } from "../components/HelpIcon";
9
 import { HelpIcon } from "../components/HelpIcon";
10
-import { EVENT_DIALOG, trackEvent } from "../analytics";
11
 
10
 
12
 export const actionToggleCanvasMenu = register({
11
 export const actionToggleCanvasMenu = register({
13
   name: "toggleCanvasMenu",
12
   name: "toggleCanvasMenu",
72
 export const actionShortcuts = register({
71
 export const actionShortcuts = register({
73
   name: "toggleShortcuts",
72
   name: "toggleShortcuts",
74
   perform: (_elements, appState) => {
73
   perform: (_elements, appState) => {
75
-    trackEvent(EVENT_DIALOG, "shortcuts");
76
     return {
74
     return {
77
       appState: {
75
       appState: {
78
         ...appState,
76
         ...appState,

+ 3
- 5
src/actions/actionNavigate.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { Avatar } from "../components/Avatar";
3
-import { register } from "./register";
4
 import { getClientColors, getClientInitials } from "../clients";
2
 import { getClientColors, getClientInitials } from "../clients";
5
-import { Collaborator } from "../types";
3
+import { Avatar } from "../components/Avatar";
6
 import { centerScrollOn } from "../scene/scroll";
4
 import { centerScrollOn } from "../scene/scroll";
7
-import { EVENT_SHARE, trackEvent } from "../analytics";
5
+import { Collaborator } from "../types";
6
+import { register } from "./register";
8
 
7
 
9
 export const actionGoToCollaborator = register({
8
 export const actionGoToCollaborator = register({
10
   name: "goToCollaborator",
9
   name: "goToCollaborator",
11
   perform: (_elements, appState, value) => {
10
   perform: (_elements, appState, value) => {
12
     const point = value as Collaborator["pointer"];
11
     const point = value as Collaborator["pointer"];
13
-    trackEvent(EVENT_SHARE, "go to collaborator");
14
     if (!point) {
12
     if (!point) {
15
       return { appState, commitToHistory: false };
13
       return { appState, commitToHistory: false };
16
     }
14
     }

+ 39
- 73
src/actions/actionProperties.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { getLanguage } from "../i18n";
2
+import { AppState } from "../../src/types";
3
+import { ButtonIconSelect } from "../components/ButtonIconSelect";
4
+import { ButtonSelect } from "../components/ButtonSelect";
5
+import { ColorPicker } from "../components/ColorPicker";
6
+import { IconPicker } from "../components/IconPicker";
3
 import {
7
 import {
8
+  ArrowheadArrowIcon,
9
+  ArrowheadBarIcon,
10
+  ArrowheadDotIcon,
11
+  ArrowheadNoneIcon,
12
+  EdgeRoundIcon,
13
+  EdgeSharpIcon,
14
+  FillCrossHatchIcon,
15
+  FillHachureIcon,
16
+  FillSolidIcon,
17
+  SloppinessArchitectIcon,
18
+  SloppinessArtistIcon,
19
+  SloppinessCartoonistIcon,
20
+  StrokeStyleDashedIcon,
21
+  StrokeStyleDottedIcon,
22
+  StrokeStyleSolidIcon,
23
+  StrokeWidthIcon,
24
+} from "../components/icons";
25
+import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants";
26
+import {
27
+  getNonDeletedElements,
28
+  isTextElement,
29
+  redrawTextBoundingBox,
30
+} from "../element";
31
+import { newElementWith } from "../element/mutateElement";
32
+import { isLinearElement, isLinearElementType } from "../element/typeChecks";
33
+import {
34
+  Arrowhead,
4
   ExcalidrawElement,
35
   ExcalidrawElement,
36
+  ExcalidrawLinearElement,
5
   ExcalidrawTextElement,
37
   ExcalidrawTextElement,
6
-  TextAlign,
7
   FontFamily,
38
   FontFamily,
8
-  ExcalidrawLinearElement,
9
-  Arrowhead,
39
+  TextAlign,
10
 } from "../element/types";
40
 } from "../element/types";
41
+import { getLanguage, t } from "../i18n";
42
+import { randomInteger } from "../random";
11
 import {
43
 import {
12
-  getCommonAttributeOfSelectedElements,
13
-  isSomeElementSelected,
14
-  getTargetElements,
15
   canChangeSharpness,
44
   canChangeSharpness,
16
   canHaveArrowheads,
45
   canHaveArrowheads,
46
+  getCommonAttributeOfSelectedElements,
47
+  getTargetElements,
48
+  isSomeElementSelected,
17
 } from "../scene";
49
 } from "../scene";
18
-import { ButtonSelect } from "../components/ButtonSelect";
19
-import { ButtonIconSelect } from "../components/ButtonIconSelect";
20
-import { IconPicker } from "../components/IconPicker";
21
-import {
22
-  isTextElement,
23
-  redrawTextBoundingBox,
24
-  getNonDeletedElements,
25
-} from "../element";
26
-import { isLinearElement, isLinearElementType } from "../element/typeChecks";
27
-import { ColorPicker } from "../components/ColorPicker";
28
-import { AppState } from "../../src/types";
29
-import { t } from "../i18n";
30
 import { register } from "./register";
50
 import { register } from "./register";
31
-import { newElementWith } from "../element/mutateElement";
32
-import { DEFAULT_FONT_SIZE, DEFAULT_FONT_FAMILY } from "../constants";
33
-import { randomInteger } from "../random";
34
-import {
35
-  FillHachureIcon,
36
-  FillCrossHatchIcon,
37
-  FillSolidIcon,
38
-  StrokeWidthIcon,
39
-  StrokeStyleSolidIcon,
40
-  StrokeStyleDashedIcon,
41
-  StrokeStyleDottedIcon,
42
-  EdgeSharpIcon,
43
-  EdgeRoundIcon,
44
-  SloppinessArchitectIcon,
45
-  SloppinessArtistIcon,
46
-  SloppinessCartoonistIcon,
47
-  ArrowheadArrowIcon,
48
-  ArrowheadBarIcon,
49
-  ArrowheadDotIcon,
50
-  ArrowheadNoneIcon,
51
-} from "../components/icons";
52
-import { EVENT_CHANGE, trackEvent } from "../analytics";
53
-import colors from "../colors";
54
 
51
 
55
 const changeProperty = (
52
 const changeProperty = (
56
   elements: readonly ExcalidrawElement[],
53
   elements: readonly ExcalidrawElement[],
92
 export const actionChangeStrokeColor = register({
89
 export const actionChangeStrokeColor = register({
93
   name: "changeStrokeColor",
90
   name: "changeStrokeColor",
94
   perform: (elements, appState, value) => {
91
   perform: (elements, appState, value) => {
95
-    if (value !== appState.currentItemStrokeColor) {
96
-      trackEvent(
97
-        EVENT_CHANGE,
98
-        "stroke color",
99
-        colors.elementStroke.includes(value)
100
-          ? `${value} (picker ${colors.elementStroke.indexOf(value)})`
101
-          : value,
102
-      );
103
-    }
104
     return {
92
     return {
105
       elements: changeProperty(elements, appState, (el) =>
93
       elements: changeProperty(elements, appState, (el) =>
106
         newElementWith(el, {
94
         newElementWith(el, {
132
 export const actionChangeBackgroundColor = register({
120
 export const actionChangeBackgroundColor = register({
133
   name: "changeBackgroundColor",
121
   name: "changeBackgroundColor",
134
   perform: (elements, appState, value) => {
122
   perform: (elements, appState, value) => {
135
-    if (value !== appState.currentItemBackgroundColor) {
136
-      trackEvent(
137
-        EVENT_CHANGE,
138
-        "background color",
139
-        colors.elementBackground.includes(value)
140
-          ? `${value} (picker ${colors.elementBackground.indexOf(value)})`
141
-          : value,
142
-      );
143
-    }
144
-
145
     return {
123
     return {
146
       elements: changeProperty(elements, appState, (el) =>
124
       elements: changeProperty(elements, appState, (el) =>
147
         newElementWith(el, {
125
         newElementWith(el, {
173
 export const actionChangeFillStyle = register({
151
 export const actionChangeFillStyle = register({
174
   name: "changeFillStyle",
152
   name: "changeFillStyle",
175
   perform: (elements, appState, value) => {
153
   perform: (elements, appState, value) => {
176
-    trackEvent(EVENT_CHANGE, "fill", value);
177
     return {
154
     return {
178
       elements: changeProperty(elements, appState, (el) =>
155
       elements: changeProperty(elements, appState, (el) =>
179
         newElementWith(el, {
156
         newElementWith(el, {
223
 export const actionChangeStrokeWidth = register({
200
 export const actionChangeStrokeWidth = register({
224
   name: "changeStrokeWidth",
201
   name: "changeStrokeWidth",
225
   perform: (elements, appState, value) => {
202
   perform: (elements, appState, value) => {
226
-    trackEvent(EVENT_CHANGE, "stroke", "width", value);
227
     return {
203
     return {
228
       elements: changeProperty(elements, appState, (el) =>
204
       elements: changeProperty(elements, appState, (el) =>
229
         newElementWith(el, {
205
         newElementWith(el, {
286
 export const actionChangeSloppiness = register({
262
 export const actionChangeSloppiness = register({
287
   name: "changeSloppiness",
263
   name: "changeSloppiness",
288
   perform: (elements, appState, value) => {
264
   perform: (elements, appState, value) => {
289
-    trackEvent(EVENT_CHANGE, "stroke", "sloppiness", value);
290
     return {
265
     return {
291
       elements: changeProperty(elements, appState, (el) =>
266
       elements: changeProperty(elements, appState, (el) =>
292
         newElementWith(el, {
267
         newElementWith(el, {
335
 export const actionChangeStrokeStyle = register({
310
 export const actionChangeStrokeStyle = register({
336
   name: "changeStrokeStyle",
311
   name: "changeStrokeStyle",
337
   perform: (elements, appState, value) => {
312
   perform: (elements, appState, value) => {
338
-    trackEvent(EVENT_CHANGE, "style", value);
339
     return {
313
     return {
340
       elements: changeProperty(elements, appState, (el) =>
314
       elements: changeProperty(elements, appState, (el) =>
341
         newElementWith(el, {
315
         newElementWith(el, {
383
 export const actionChangeOpacity = register({
357
 export const actionChangeOpacity = register({
384
   name: "changeOpacity",
358
   name: "changeOpacity",
385
   perform: (elements, appState, value) => {
359
   perform: (elements, appState, value) => {
386
-    trackEvent(EVENT_CHANGE, "opacity", "value", value);
387
     return {
360
     return {
388
       elements: changeProperty(elements, appState, (el) =>
361
       elements: changeProperty(elements, appState, (el) =>
389
         newElementWith(el, {
362
         newElementWith(el, {
580
     const shouldUpdateForLinearElements = targetElements.length
553
     const shouldUpdateForLinearElements = targetElements.length
581
       ? targetElements.every(isLinearElement)
554
       ? targetElements.every(isLinearElement)
582
       : isLinearElementType(appState.elementType);
555
       : isLinearElementType(appState.elementType);
583
-    trackEvent(EVENT_CHANGE, "edge", value);
584
     return {
556
     return {
585
       elements: changeProperty(elements, appState, (el) =>
557
       elements: changeProperty(elements, appState, (el) =>
586
         newElementWith(el, {
558
         newElementWith(el, {
642
     return {
614
     return {
643
       elements: changeProperty(elements, appState, (el) => {
615
       elements: changeProperty(elements, appState, (el) => {
644
         if (isLinearElement(el)) {
616
         if (isLinearElement(el)) {
645
-          trackEvent(
646
-            EVENT_CHANGE,
647
-            `arrowhead ${value.position}`,
648
-            value.type || "none",
649
-          );
650
-
651
           const { position, type } = value;
617
           const { position, type } = value;
652
 
618
 
653
           if (position === "start") {
619
           if (position === "start") {

+ 5
- 15
src/analytics.ts View File

1
-export const EVENT_ACTION = "action";
2
-export const EVENT_ALIGN = "align";
3
-export const EVENT_CHANGE = "change";
4
-export const EVENT_DIALOG = "dialog";
5
-export const EVENT_EXIT = "exit";
6
-export const EVENT_IO = "io";
7
-export const EVENT_LAYER = "layer";
8
-export const EVENT_LIBRARY = "library";
9
-export const EVENT_LOAD = "load";
10
-export const EVENT_SHAPE = "shape";
11
-export const EVENT_SHARE = "share";
12
-export const EVENT_MAGIC = "magic";
13
-
14
 export const trackEvent =
1
 export const trackEvent =
15
-  typeof window !== "undefined" && window.gtag
2
+  process.env.REACT_APP_GOOGLE_ANALYTICS_ID &&
3
+  typeof window !== "undefined" &&
4
+  window.gtag
16
     ? (category: string, name: string, label?: string, value?: number) => {
5
     ? (category: string, name: string, label?: string, value?: number) => {
17
         window.gtag("event", name, {
6
         window.gtag("event", name, {
18
           event_category: category,
7
           event_category: category,
23
     : typeof process !== "undefined" && process?.env?.JEST_WORKER_ID
12
     : typeof process !== "undefined" && process?.env?.JEST_WORKER_ID
24
     ? (category: string, name: string, label?: string, value?: number) => {}
13
     ? (category: string, name: string, label?: string, value?: number) => {}
25
     : (category: string, name: string, label?: string, value?: number) => {
14
     : (category: string, name: string, label?: string, value?: number) => {
26
-        console.info("Track Event", category, name, label, value);
15
+        // Uncomment the next line to track locally
16
+        // console.info("Track Event", category, name, label, value);
27
       };
17
       };

+ 2
- 2
src/charts.ts View File

1
-import { EVENT_MAGIC, trackEvent } from "./analytics";
1
+import { trackEvent } from "./analytics";
2
 import colors from "./colors";
2
 import colors from "./colors";
3
 import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants";
3
 import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants";
4
 import { newElement, newLinearElement, newTextElement } from "./element";
4
 import { newElement, newLinearElement, newTextElement } from "./element";
473
   x: number,
473
   x: number,
474
   y: number,
474
   y: number,
475
 ): ChartElements => {
475
 ): ChartElements => {
476
-  trackEvent(EVENT_MAGIC, "chart", chartType, spreadsheet.values.length);
476
+  trackEvent("magic", "chart", chartType, spreadsheet.values.length);
477
   if (chartType === "line") {
477
   if (chartType === "line") {
478
     return chartTypeLine(spreadsheet, x, y);
478
     return chartTypeLine(spreadsheet, x, y);
479
   }
479
   }

+ 9
- 14
src/components/Actions.tsx View File

1
 import React from "react";
1
 import React from "react";
2
-import { AppState, Zoom } from "../types";
3
-import { ExcalidrawElement } from "../element/types";
4
 import { ActionManager } from "../actions/manager";
2
 import { ActionManager } from "../actions/manager";
3
+import { getNonDeletedElements } from "../element";
4
+import { ExcalidrawElement } from "../element/types";
5
+import { t } from "../i18n";
6
+import useIsMobile from "../is-mobile";
5
 import {
7
 import {
6
-  hasBackground,
7
-  hasStroke,
8
   canChangeSharpness,
8
   canChangeSharpness,
9
-  hasText,
10
   canHaveArrowheads,
9
   canHaveArrowheads,
11
   getTargetElements,
10
   getTargetElements,
11
+  hasBackground,
12
+  hasStroke,
13
+  hasText,
12
 } from "../scene";
14
 } from "../scene";
13
-import { t } from "../i18n";
14
 import { SHAPES } from "../shapes";
15
 import { SHAPES } from "../shapes";
15
-import { ToolButton } from "./ToolButton";
16
+import { AppState, Zoom } from "../types";
16
 import { capitalizeString, isTransparent, setCursorForShape } from "../utils";
17
 import { capitalizeString, isTransparent, setCursorForShape } from "../utils";
17
 import Stack from "./Stack";
18
 import Stack from "./Stack";
18
-import useIsMobile from "../is-mobile";
19
-import { getNonDeletedElements } from "../element";
20
-import { trackEvent, EVENT_SHAPE, EVENT_DIALOG } from "../analytics";
19
+import { ToolButton } from "./ToolButton";
21
 
20
 
22
 export const SelectedShapeActions = ({
21
 export const SelectedShapeActions = ({
23
   appState,
22
   appState,
181
           aria-keyshortcuts={shortcut}
180
           aria-keyshortcuts={shortcut}
182
           data-testid={value}
181
           data-testid={value}
183
           onChange={() => {
182
           onChange={() => {
184
-            trackEvent(EVENT_SHAPE, value, "toolbar");
185
             setAppState({
183
             setAppState({
186
               elementType: value,
184
               elementType: value,
187
               multiElement: null,
185
               multiElement: null,
203
       title={`${capitalizeString(t("toolBar.library"))} — 9`}
201
       title={`${capitalizeString(t("toolBar.library"))} — 9`}
204
       aria-label={capitalizeString(t("toolBar.library"))}
202
       aria-label={capitalizeString(t("toolBar.library"))}
205
       onClick={() => {
203
       onClick={() => {
206
-        if (!isLibraryOpen) {
207
-          trackEvent(EVENT_DIALOG, "library");
208
-        }
209
         setAppState({ isLibraryOpen: !isLibraryOpen });
204
         setAppState({ isLibraryOpen: !isLibraryOpen });
210
       }}
205
       }}
211
     />
206
     />

+ 3
- 15
src/components/App.tsx View File

8
 import { ActionManager } from "../actions/manager";
8
 import { ActionManager } from "../actions/manager";
9
 import { actions } from "../actions/register";
9
 import { actions } from "../actions/register";
10
 import { ActionResult } from "../actions/types";
10
 import { ActionResult } from "../actions/types";
11
-import {
12
-  EVENT_DIALOG,
13
-  EVENT_LIBRARY,
14
-  EVENT_SHAPE,
15
-  trackEvent,
16
-} from "../analytics";
11
+import { trackEvent } from "../analytics";
17
 import { getDefaultAppState } from "../appState";
12
 import { getDefaultAppState } from "../appState";
18
 import {
13
 import {
19
   copyToClipboard,
14
   copyToClipboard,
111
   selectGroupsForSelectedElements,
106
   selectGroupsForSelectedElements,
112
 } from "../groups";
107
 } from "../groups";
113
 import { createHistory, SceneHistory } from "../history";
108
 import { createHistory, SceneHistory } from "../history";
114
-import { t, getLanguage, setLanguage, languages, defaultLang } from "../i18n";
109
+import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
115
 import {
110
 import {
116
   CODES,
111
   CODES,
117
   getResizeCenterPointKey,
112
   getResizeCenterPointKey,
504
         )
499
         )
505
       ) {
500
       ) {
506
         await Library.importLibrary(blob);
501
         await Library.importLibrary(blob);
507
-        trackEvent(EVENT_LIBRARY, "import");
508
         this.setState({
502
         this.setState({
509
           isLibraryOpen: true,
503
           isLibraryOpen: true,
510
         });
504
         });
1134
 
1128
 
1135
   toggleLock = () => {
1129
   toggleLock = () => {
1136
     this.setState((prevState) => {
1130
     this.setState((prevState) => {
1137
-      trackEvent(EVENT_SHAPE, "lock", !prevState.elementLocked ? "on" : "off");
1138
       return {
1131
       return {
1139
         elementLocked: !prevState.elementLocked,
1132
         elementLocked: !prevState.elementLocked,
1140
         elementType: prevState.elementLocked
1133
         elementType: prevState.elementLocked
1158
 
1151
 
1159
   toggleStats = () => {
1152
   toggleStats = () => {
1160
     if (!this.state.showStats) {
1153
     if (!this.state.showStats) {
1161
-      trackEvent(EVENT_DIALOG, "stats");
1154
+      trackEvent("dialog", "stats");
1162
     }
1155
     }
1163
     this.setState({
1156
     this.setState({
1164
       showStats: !this.state.showStats,
1157
       showStats: !this.state.showStats,
1270
     }
1263
     }
1271
 
1264
 
1272
     if (event.code === CODES.NINE) {
1265
     if (event.code === CODES.NINE) {
1273
-      if (!this.state.isLibraryOpen) {
1274
-        trackEvent(EVENT_DIALOG, "library");
1275
-      }
1276
       this.setState({ isLibraryOpen: !this.state.isLibraryOpen });
1266
       this.setState({ isLibraryOpen: !this.state.isLibraryOpen });
1277
     }
1267
     }
1278
 
1268
 
1357
     ) {
1347
     ) {
1358
       const shape = findShapeByKey(event.key);
1348
       const shape = findShapeByKey(event.key);
1359
       if (shape) {
1349
       if (shape) {
1360
-        trackEvent(EVENT_SHAPE, shape, "shortcut");
1361
         this.selectShapeTool(shape);
1350
         this.selectShapeTool(shape);
1362
       } else if (event.key === KEYS.Q) {
1351
       } else if (event.key === KEYS.Q) {
1363
         this.toggleLock();
1352
         this.toggleLock();
1741
     resetCursor();
1730
     resetCursor();
1742
 
1731
 
1743
     if (!event[KEYS.CTRL_OR_CMD]) {
1732
     if (!event[KEYS.CTRL_OR_CMD]) {
1744
-      trackEvent(EVENT_SHAPE, "text", "double-click");
1745
       this.startTextEditing({
1733
       this.startTextEditing({
1746
         sceneX,
1734
         sceneX,
1747
         sceneY,
1735
         sceneY,

+ 0
- 3
src/components/BackgroundPickerAndDarkModeToggle.tsx View File

1
 import React from "react";
1
 import React from "react";
2
 import { ActionManager } from "../actions/manager";
2
 import { ActionManager } from "../actions/manager";
3
-import { EVENT_CHANGE, trackEvent } from "../analytics";
4
 import { AppState } from "../types";
3
 import { AppState } from "../types";
5
 import { DarkModeToggle } from "./DarkModeToggle";
4
 import { DarkModeToggle } from "./DarkModeToggle";
6
 
5
 
19
       <DarkModeToggle
18
       <DarkModeToggle
20
         value={appState.appearance}
19
         value={appState.appearance}
21
         onChange={(appearance) => {
20
         onChange={(appearance) => {
22
-          // TODO: track the theme on the first load too
23
-          trackEvent(EVENT_CHANGE, "theme", appearance);
24
           setAppState({ appearance });
21
           setAppState({ appearance });
25
         }}
22
         }}
26
       />
23
       />

+ 1
- 5
src/components/CollabButton.tsx View File

6
 import { users } from "./icons";
6
 import { users } from "./icons";
7
 
7
 
8
 import "./CollabButton.scss";
8
 import "./CollabButton.scss";
9
-import { EVENT_DIALOG, trackEvent } from "../analytics";
10
 
9
 
11
 const CollabButton = ({
10
 const CollabButton = ({
12
   isCollaborating,
11
   isCollaborating,
23
         className={clsx("CollabButton", {
22
         className={clsx("CollabButton", {
24
           "is-collaborating": isCollaborating,
23
           "is-collaborating": isCollaborating,
25
         })}
24
         })}
26
-        onClick={() => {
27
-          trackEvent(EVENT_DIALOG, "collaboration");
28
-          onClick();
29
-        }}
25
+        onClick={onClick}
30
         icon={users}
26
         icon={users}
31
         type="button"
27
         type="button"
32
         title={t("buttons.roomDialog")}
28
         title={t("buttons.roomDialog")}

+ 0
- 2
src/components/ExportDialog.tsx View File

1
 import React, { useEffect, useRef, useState } from "react";
1
 import React, { useEffect, useRef, useState } from "react";
2
 import { render, unmountComponentAtNode } from "react-dom";
2
 import { render, unmountComponentAtNode } from "react-dom";
3
 import { ActionsManagerInterface } from "../actions/types";
3
 import { ActionsManagerInterface } from "../actions/types";
4
-import { EVENT_DIALOG, trackEvent } from "../analytics";
5
 import { probablySupportsClipboardBlob } from "../clipboard";
4
 import { probablySupportsClipboardBlob } from "../clipboard";
6
 import { canvasToBlob } from "../data/blob";
5
 import { canvasToBlob } from "../data/blob";
7
 import { NonDeletedExcalidrawElement } from "../element/types";
6
 import { NonDeletedExcalidrawElement } from "../element/types";
251
     <>
250
     <>
252
       <ToolButton
251
       <ToolButton
253
         onClick={() => {
252
         onClick={() => {
254
-          trackEvent(EVENT_DIALOG, "export");
255
           setModalIsShown(true);
253
           setModalIsShown(true);
256
         }}
254
         }}
257
         icon={exportFile}
255
         icon={exportFile}

+ 1
- 5
src/components/GitHubCorner.tsx View File

1
-import React from "react";
2
 import oc from "open-color";
1
 import oc from "open-color";
3
-import { EVENT_EXIT, trackEvent } from "../analytics";
2
+import React from "react";
4
 
3
 
5
 // https://github.com/tholman/github-corners
4
 // https://github.com/tholman/github-corners
6
 export const GitHubCorner = React.memo(
5
 export const GitHubCorner = React.memo(
17
         target="_blank"
16
         target="_blank"
18
         rel="noopener noreferrer"
17
         rel="noopener noreferrer"
19
         aria-label="GitHub repository"
18
         aria-label="GitHub repository"
20
-        onClick={() => {
21
-          trackEvent(EVENT_EXIT, "github");
22
-        }}
23
       >
19
       >
24
         <path
20
         <path
25
           d="M0 0l115 115h15l12 27 108 108V0z"
21
           d="M0 0l115 115h15l12 27 108 108V0z"

+ 29
- 51
src/components/LayerUI.tsx View File

1
+import clsx from "clsx";
1
 import React, {
2
 import React, {
2
-  useRef,
3
-  useState,
4
   RefObject,
3
   RefObject,
5
-  useEffect,
6
   useCallback,
4
   useCallback,
5
+  useEffect,
6
+  useRef,
7
+  useState,
7
 } from "react";
8
 } from "react";
8
-import { showSelectedShapeActions } from "../element";
9
-import { calculateScrollCenter, getSelectedElements } from "../scene";
9
+import { ActionManager } from "../actions/manager";
10
+import { CLASSES } from "../constants";
10
 import { exportCanvas } from "../data";
11
 import { exportCanvas } from "../data";
11
-
12
-import { AppState, LibraryItems, LibraryItem } from "../types";
12
+import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json";
13
+import { Library } from "../data/library";
14
+import { showSelectedShapeActions } from "../element";
13
 import { NonDeletedExcalidrawElement } from "../element/types";
15
 import { NonDeletedExcalidrawElement } from "../element/types";
14
-
15
-import { ActionManager } from "../actions/manager";
16
-import { Island } from "./Island";
17
-import Stack from "./Stack";
18
-import { FixedSideContainer } from "./FixedSideContainer";
19
-import { UserList } from "./UserList";
20
-import { LockIcon } from "./LockIcon";
21
-import { ExportDialog, ExportCB } from "./ExportDialog";
22
 import { Language, t } from "../i18n";
16
 import { Language, t } from "../i18n";
23
-import { HintViewer } from "./HintViewer";
24
 import useIsMobile from "../is-mobile";
17
 import useIsMobile from "../is-mobile";
25
-
18
+import { calculateScrollCenter, getSelectedElements } from "../scene";
26
 import { ExportType } from "../scene/types";
19
 import { ExportType } from "../scene/types";
27
-import { MobileMenu } from "./MobileMenu";
28
-import { ZoomActions, SelectedShapeActions, ShapesSwitcher } from "./Actions";
29
-import { Section } from "./Section";
20
+import { AppState, LibraryItem, LibraryItems } from "../types";
21
+import { muteFSAbortError } from "../utils";
22
+import { SelectedShapeActions, ShapesSwitcher, ZoomActions } from "./Actions";
23
+import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
30
 import CollabButton from "./CollabButton";
24
 import CollabButton from "./CollabButton";
31
 import { ErrorDialog } from "./ErrorDialog";
25
 import { ErrorDialog } from "./ErrorDialog";
32
-import { ShortcutsDialog } from "./ShortcutsDialog";
33
-import { LoadingMessage } from "./LoadingMessage";
34
-import { CLASSES } from "../constants";
35
-import { shield, exportFile, load } from "./icons";
26
+import { ExportCB, ExportDialog } from "./ExportDialog";
27
+import { FixedSideContainer } from "./FixedSideContainer";
36
 import { GitHubCorner } from "./GitHubCorner";
28
 import { GitHubCorner } from "./GitHubCorner";
37
-import { Tooltip } from "./Tooltip";
38
-
29
+import { HintViewer } from "./HintViewer";
30
+import { exportFile, load, shield } from "./icons";
31
+import { Island } from "./Island";
39
 import "./LayerUI.scss";
32
 import "./LayerUI.scss";
40
 import { LibraryUnit } from "./LibraryUnit";
33
 import { LibraryUnit } from "./LibraryUnit";
41
-import { ToolButton } from "./ToolButton";
42
-import { saveLibraryAsJSON, importLibraryFromJSON } from "../data/json";
43
-import { muteFSAbortError } from "../utils";
44
-import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
45
-import clsx from "clsx";
46
-import { Library } from "../data/library";
47
-import {
48
-  EVENT_ACTION,
49
-  EVENT_EXIT,
50
-  EVENT_LIBRARY,
51
-  trackEvent,
52
-} from "../analytics";
34
+import { LoadingMessage } from "./LoadingMessage";
35
+import { LockIcon } from "./LockIcon";
36
+import { MobileMenu } from "./MobileMenu";
53
 import { PasteChartDialog } from "./PasteChartDialog";
37
 import { PasteChartDialog } from "./PasteChartDialog";
38
+import { Section } from "./Section";
39
+import { ShortcutsDialog } from "./ShortcutsDialog";
40
+import Stack from "./Stack";
41
+import { ToolButton } from "./ToolButton";
42
+import { Tooltip } from "./Tooltip";
43
+import { UserList } from "./UserList";
54
 
44
 
55
 interface LayerUIProps {
45
 interface LayerUIProps {
56
   actionManager: ActionManager;
46
   actionManager: ActionManager;
159
         }}
149
         }}
160
       />
150
       />
161
 
151
 
162
-      <a
163
-        href="https://libraries.excalidraw.com"
164
-        target="_excalidraw_libraries"
165
-        onClick={() => {
166
-          trackEvent(EVENT_EXIT, "libraries");
167
-        }}
168
-      >
152
+      <a href="https://libraries.excalidraw.com" target="_excalidraw_libraries">
169
         {t("labels.libraries")}
153
         {t("labels.libraries")}
170
       </a>
154
       </a>
171
     </div>,
155
     </div>,
267
     const items = await Library.loadLibrary();
251
     const items = await Library.loadLibrary();
268
     const nextItems = items.filter((_, index) => index !== indexToRemove);
252
     const nextItems = items.filter((_, index) => index !== indexToRemove);
269
     Library.saveLibrary(nextItems);
253
     Library.saveLibrary(nextItems);
270
-    trackEvent(EVENT_LIBRARY, "remove");
271
     setLibraryItems(nextItems);
254
     setLibraryItems(nextItems);
272
   }, []);
255
   }, []);
273
 
256
 
276
       const items = await Library.loadLibrary();
259
       const items = await Library.loadLibrary();
277
       const nextItems = [...items, elements];
260
       const nextItems = [...items, elements];
278
       onAddToLibrary();
261
       onAddToLibrary();
279
-      trackEvent(EVENT_LIBRARY, "add");
280
       Library.saveLibrary(nextItems);
262
       Library.saveLibrary(nextItems);
281
       setLibraryItems(nextItems);
263
       setLibraryItems(nextItems);
282
     },
264
     },
328
       href="https://blog.excalidraw.com/end-to-end-encryption/"
310
       href="https://blog.excalidraw.com/end-to-end-encryption/"
329
       target="_blank"
311
       target="_blank"
330
       rel="noopener noreferrer"
312
       rel="noopener noreferrer"
331
-      onClick={() => {
332
-        trackEvent(EVENT_EXIT, "e2ee shield");
333
-      }}
334
     >
313
     >
335
       <Tooltip label={t("encrypted.tooltip")} position="above" long={true}>
314
       <Tooltip label={t("encrypted.tooltip")} position="above" long={true}>
336
         {shield}
315
         {shield}
567
         <button
546
         <button
568
           className="scroll-back-to-content"
547
           className="scroll-back-to-content"
569
           onClick={() => {
548
           onClick={() => {
570
-            trackEvent(EVENT_ACTION, "scroll to content");
571
             setAppState({
549
             setAppState({
572
               ...calculateScrollCenter(elements, appState, canvas),
550
               ...calculateScrollCenter(elements, appState, canvas),
573
             });
551
             });

+ 0
- 2
src/components/MobileMenu.tsx View File

16
 import { LockIcon } from "./LockIcon";
16
 import { LockIcon } from "./LockIcon";
17
 import { UserList } from "./UserList";
17
 import { UserList } from "./UserList";
18
 import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
18
 import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
19
-import { EVENT_ACTION, trackEvent } from "../analytics";
20
 
19
 
21
 type MobileMenuProps = {
20
 type MobileMenuProps = {
22
   appState: AppState;
21
   appState: AppState;
149
             <button
148
             <button
150
               className="scroll-back-to-content"
149
               className="scroll-back-to-content"
151
               onClick={() => {
150
               onClick={() => {
152
-                trackEvent(EVENT_ACTION, "scroll to content");
153
                 setAppState({
151
                 setAppState({
154
                   ...calculateScrollCenter(elements, appState, canvas),
152
                   ...calculateScrollCenter(elements, appState, canvas),
155
                 });
153
                 });

+ 0
- 10
src/components/ShortcutsDialog.tsx View File

4
 import { Dialog } from "./Dialog";
4
 import { Dialog } from "./Dialog";
5
 import { getShortcutKey } from "../utils";
5
 import { getShortcutKey } from "../utils";
6
 import "./ShortcutsDialog.scss";
6
 import "./ShortcutsDialog.scss";
7
-import { EVENT_EXIT, trackEvent } from "../analytics";
8
 
7
 
9
 const Columns = (props: { children: React.ReactNode }) => (
8
 const Columns = (props: { children: React.ReactNode }) => (
10
   <div
9
   <div
92
       href="https://blog.excalidraw.com"
91
       href="https://blog.excalidraw.com"
93
       target="_blank"
92
       target="_blank"
94
       rel="noopener noreferrer"
93
       rel="noopener noreferrer"
95
-      onClick={() => {
96
-        trackEvent(EVENT_EXIT, "blog");
97
-      }}
98
     >
94
     >
99
       {t("shortcutsDialog.blog")}
95
       {t("shortcutsDialog.blog")}
100
     </a>
96
     </a>
102
       href="https://howto.excalidraw.com"
98
       href="https://howto.excalidraw.com"
103
       target="_blank"
99
       target="_blank"
104
       rel="noopener noreferrer"
100
       rel="noopener noreferrer"
105
-      onClick={() => {
106
-        trackEvent(EVENT_EXIT, "guides");
107
-      }}
108
     >
101
     >
109
       {t("shortcutsDialog.howto")}
102
       {t("shortcutsDialog.howto")}
110
     </a>
103
     </a>
112
       href="https://github.com/excalidraw/excalidraw/issues"
105
       href="https://github.com/excalidraw/excalidraw/issues"
113
       target="_blank"
106
       target="_blank"
114
       rel="noopener noreferrer"
107
       rel="noopener noreferrer"
115
-      onClick={() => {
116
-        trackEvent(EVENT_EXIT, "issues");
117
-      }}
118
     >
108
     >
119
       {t("shortcutsDialog.github")}
109
       {t("shortcutsDialog.github")}
120
     </a>
110
     </a>

+ 0
- 2
src/data/blob.ts View File

1
-import { EVENT_IO, trackEvent } from "../analytics";
2
 import { cleanAppStateForExport } from "../appState";
1
 import { cleanAppStateForExport } from "../appState";
3
 import { MIME_TYPES } from "../constants";
2
 import { MIME_TYPES } from "../constants";
4
 import { clearElementsForExport } from "../element";
3
 import { clearElementsForExport } from "../element";
111
       localAppState,
110
       localAppState,
112
     );
111
     );
113
 
112
 
114
-    trackEvent(EVENT_IO, "load", getMimeType(blob));
115
     return result;
113
     return result;
116
   } catch (error) {
114
   } catch (error) {
117
     console.error(error.message);
115
     console.error(error.message);

+ 1
- 6
src/data/index.ts View File

1
 import { fileSave } from "browser-nativefs";
1
 import { fileSave } from "browser-nativefs";
2
-import { EVENT_IO, trackEvent } from "../analytics";
3
 import {
2
 import {
4
   copyCanvasToClipboardAsPng,
3
   copyCanvasToClipboardAsPng,
5
   copyTextToSystemClipboard,
4
   copyTextToSystemClipboard,
8
 import { t } from "../i18n";
7
 import { t } from "../i18n";
9
 import { exportToCanvas, exportToSvg } from "../scene/export";
8
 import { exportToCanvas, exportToSvg } from "../scene/export";
10
 import { ExportType } from "../scene/types";
9
 import { ExportType } from "../scene/types";
11
-import { canvasToBlob } from "./blob";
12
 import { AppState } from "../types";
10
 import { AppState } from "../types";
11
+import { canvasToBlob } from "./blob";
13
 import { serializeAsJSON } from "./json";
12
 import { serializeAsJSON } from "./json";
14
 
13
 
15
 export { loadFromBlob } from "./blob";
14
 export { loadFromBlob } from "./blob";
60
         fileName: `${name}.svg`,
59
         fileName: `${name}.svg`,
61
         extensions: [".svg"],
60
         extensions: [".svg"],
62
       });
61
       });
63
-      trackEvent(EVENT_IO, "export", "svg");
64
       return;
62
       return;
65
     } else if (type === "clipboard-svg") {
63
     } else if (type === "clipboard-svg") {
66
-      trackEvent(EVENT_IO, "export", "clipboard-svg");
67
       copyTextToSystemClipboard(tempSvg.outerHTML);
64
       copyTextToSystemClipboard(tempSvg.outerHTML);
68
       return;
65
       return;
69
     }
66
     }
95
       fileName,
92
       fileName,
96
       extensions: [".png"],
93
       extensions: [".png"],
97
     });
94
     });
98
-    trackEvent(EVENT_IO, "export", "png");
99
   } else if (type === "clipboard") {
95
   } else if (type === "clipboard") {
100
     try {
96
     try {
101
       await copyCanvasToClipboardAsPng(tempCanvas);
97
       await copyCanvasToClipboardAsPng(tempCanvas);
102
-      trackEvent(EVENT_IO, "export", "clipboard-png");
103
     } catch (error) {
98
     } catch (error) {
104
       if (error.name === "CANVAS_POSSIBLY_TOO_BIG") {
99
       if (error.name === "CANVAS_POSSIBLY_TOO_BIG") {
105
         throw error;
100
         throw error;

+ 4
- 8
src/data/json.ts View File

1
+import { fileOpen, fileSave } from "browser-nativefs";
2
+import { cleanAppStateForExport } from "../appState";
3
+import { MIME_TYPES } from "../constants";
4
+import { clearElementsForExport } from "../element";
1
 import { ExcalidrawElement } from "../element/types";
5
 import { ExcalidrawElement } from "../element/types";
2
 import { AppState } from "../types";
6
 import { AppState } from "../types";
3
-import { cleanAppStateForExport } from "../appState";
4
-
5
-import { fileOpen, fileSave } from "browser-nativefs";
6
 import { loadFromBlob } from "./blob";
7
 import { loadFromBlob } from "./blob";
7
 import { Library } from "./library";
8
 import { Library } from "./library";
8
-import { MIME_TYPES } from "../constants";
9
-import { clearElementsForExport } from "../element";
10
-import { EVENT_LIBRARY, trackEvent } from "../analytics";
11
 
9
 
12
 export const serializeAsJSON = (
10
 export const serializeAsJSON = (
13
   elements: readonly ExcalidrawElement[],
11
   elements: readonly ExcalidrawElement[],
84
     description: "Excalidraw library file",
82
     description: "Excalidraw library file",
85
     extensions: [".excalidrawlib"],
83
     extensions: [".excalidrawlib"],
86
   });
84
   });
87
-  trackEvent(EVENT_LIBRARY, "save");
88
 };
85
 };
89
 
86
 
90
 export const importLibraryFromJSON = async () => {
87
 export const importLibraryFromJSON = async () => {
93
     extensions: [".json", ".excalidrawlib"],
90
     extensions: [".json", ".excalidrawlib"],
94
     mimeTypes: ["application/json"],
91
     mimeTypes: ["application/json"],
95
   });
92
   });
96
-  trackEvent(EVENT_LIBRARY, "load");
97
   Library.importLibrary(blob);
93
   Library.importLibrary(blob);
98
 };
94
 };

+ 19
- 25
src/excalidraw-app/collab/CollabWrapper.tsx View File

1
-import React, { PureComponent } from "react";
2
 import throttle from "lodash.throttle";
1
 import throttle from "lodash.throttle";
3
-
2
+import React, { PureComponent } from "react";
3
+import { ExcalidrawImperativeAPI } from "../../components/App";
4
+import { ErrorDialog } from "../../components/ErrorDialog";
4
 import { APP_NAME, ENV, EVENT } from "../../constants";
5
 import { APP_NAME, ENV, EVENT } from "../../constants";
5
-
6
+import { ImportedDataState } from "../../data/types";
7
+import { ExcalidrawElement } from "../../element/types";
8
+import {
9
+  getSceneVersion,
10
+  getSyncableElements,
11
+} from "../../packages/excalidraw/index";
12
+import { AppState, Collaborator, Gesture } from "../../types";
13
+import { resolvablePromise, withBatchedUpdates } from "../../utils";
14
+import {
15
+  INITIAL_SCENE_UPDATE_TIMEOUT,
16
+  SCENE,
17
+  SYNC_FULL_SCENE_INTERVAL_MS,
18
+} from "../app_constants";
6
 import {
19
 import {
7
   decryptAESGEM,
20
   decryptAESGEM,
8
-  SocketUpdateDataSource,
9
-  getCollaborationLinkData,
10
   generateCollaborationLink,
21
   generateCollaborationLink,
22
+  getCollaborationLinkData,
23
+  SocketUpdateDataSource,
11
   SOCKET_SERVER,
24
   SOCKET_SERVER,
12
 } from "../data";
25
 } from "../data";
13
 import { isSavedToFirebase, saveToFirebase } from "../data/firebase";
26
 import { isSavedToFirebase, saveToFirebase } from "../data/firebase";
14
-
15
-import Portal from "./Portal";
16
-import { AppState, Collaborator, Gesture } from "../../types";
17
-import { ExcalidrawElement } from "../../element/types";
18
 import {
27
 import {
19
   importUsernameFromLocalStorage,
28
   importUsernameFromLocalStorage,
20
   saveUsernameToLocalStorage,
29
   saveUsernameToLocalStorage,
21
   STORAGE_KEYS,
30
   STORAGE_KEYS,
22
 } from "../data/localStorage";
31
 } from "../data/localStorage";
23
-import { resolvablePromise, withBatchedUpdates } from "../../utils";
24
-import {
25
-  getSceneVersion,
26
-  getSyncableElements,
27
-} from "../../packages/excalidraw/index";
32
+import Portal from "./Portal";
28
 import RoomDialog from "./RoomDialog";
33
 import RoomDialog from "./RoomDialog";
29
-import { ErrorDialog } from "../../components/ErrorDialog";
30
-import { ImportedDataState } from "../../data/types";
31
-import { ExcalidrawImperativeAPI } from "../../components/App";
32
-import {
33
-  INITIAL_SCENE_UPDATE_TIMEOUT,
34
-  SCENE,
35
-  SYNC_FULL_SCENE_INTERVAL_MS,
36
-} from "../app_constants";
37
-import { EVENT_SHARE, trackEvent } from "../../analytics";
38
 
34
 
39
 interface CollabState {
35
 interface CollabState {
40
   isCollaborating: boolean;
36
   isCollaborating: boolean;
168
       elements,
164
       elements,
169
       commitToHistory: true,
165
       commitToHistory: true,
170
     });
166
     });
171
-    trackEvent(EVENT_SHARE, "session start");
172
     return this.initializeSocketClient();
167
     return this.initializeSocketClient();
173
   };
168
   };
174
 
169
 
176
     this.saveCollabRoomToFirebase();
171
     this.saveCollabRoomToFirebase();
177
     window.history.pushState({}, APP_NAME, window.location.origin);
172
     window.history.pushState({}, APP_NAME, window.location.origin);
178
     this.destroySocketClient();
173
     this.destroySocketClient();
179
-    trackEvent(EVENT_SHARE, "session end");
180
   };
174
   };
181
 
175
 
182
   private destroySocketClient = () => {
176
   private destroySocketClient = () => {

+ 3
- 7
src/excalidraw-app/collab/RoomDialog.tsx View File

1
 import React, { useRef } from "react";
1
 import React, { useRef } from "react";
2
-import { t } from "../../i18n";
3
-import { Dialog } from "../../components/Dialog";
4
 import { copyTextToSystemClipboard } from "../../clipboard";
2
 import { copyTextToSystemClipboard } from "../../clipboard";
5
-import { ToolButton } from "../../components/ToolButton";
3
+import { Dialog } from "../../components/Dialog";
6
 import { clipboard, start, stop } from "../../components/icons";
4
 import { clipboard, start, stop } from "../../components/icons";
7
-
5
+import { ToolButton } from "../../components/ToolButton";
6
+import { t } from "../../i18n";
8
 import "./RoomDialog.scss";
7
 import "./RoomDialog.scss";
9
-import { EVENT_SHARE, trackEvent } from "../../analytics";
10
 
8
 
11
 const RoomDialog = ({
9
 const RoomDialog = ({
12
   handleClose,
10
   handleClose,
30
   const copyRoomLink = async () => {
28
   const copyRoomLink = async () => {
31
     try {
29
     try {
32
       await copyTextToSystemClipboard(activeRoomLink);
30
       await copyTextToSystemClipboard(activeRoomLink);
33
-      trackEvent(EVENT_SHARE, "copy link");
34
     } catch (error) {
31
     } catch (error) {
35
       setErrorMessage(error.message);
32
       setErrorMessage(error.message);
36
     }
33
     }
95
                 value={username || ""}
92
                 value={username || ""}
96
                 className="RoomDialog-username TextInput"
93
                 className="RoomDialog-username TextInput"
97
                 onChange={(event) => onUsernameChange(event.target.value)}
94
                 onChange={(event) => onUsernameChange(event.target.value)}
98
-                onBlur={() => trackEvent(EVENT_SHARE, "name")}
99
                 onKeyPress={(event) => event.key === "Enter" && handleClose()}
95
                 onKeyPress={(event) => event.key === "Enter" && handleClose()}
100
               />
96
               />
101
             </div>
97
             </div>

+ 4
- 7
src/excalidraw-app/data/index.ts View File

1
-import { t } from "../../i18n";
1
+import { serializeAsJSON } from "../../data/json";
2
+import { restore } from "../../data/restore";
3
+import { ImportedDataState } from "../../data/types";
2
 import { ExcalidrawElement } from "../../element/types";
4
 import { ExcalidrawElement } from "../../element/types";
5
+import { t } from "../../i18n";
3
 import { AppState } from "../../types";
6
 import { AppState } from "../../types";
4
-import { ImportedDataState } from "../../data/types";
5
-import { restore } from "../../data/restore";
6
-import { EVENT_ACTION, EVENT_IO, trackEvent } from "../../analytics";
7
-import { serializeAsJSON } from "../../data/json";
8
 
7
 
9
 const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2);
8
 const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2);
10
 
9
 
192
       data = await response.json();
191
       data = await response.json();
193
     }
192
     }
194
 
193
 
195
-    trackEvent(EVENT_ACTION, "import");
196
     return {
194
     return {
197
       elements: data.elements || null,
195
       elements: data.elements || null,
198
       appState: data.appState || null,
196
       appState: data.appState || null,
276
       url.hash = `json=${json.id},${exportedKey.k!}`;
274
       url.hash = `json=${json.id},${exportedKey.k!}`;
277
       const urlString = url.toString();
275
       const urlString = url.toString();
278
       window.prompt(`🔒${t("alerts.uploadedSecurly")}`, urlString);
276
       window.prompt(`🔒${t("alerts.uploadedSecurly")}`, urlString);
279
-      trackEvent(EVENT_IO, "export", "backend");
280
     } else if (json.error_class === "RequestTooLargeError") {
277
     } else if (json.error_class === "RequestTooLargeError") {
281
       window.alert(t("alerts.couldNotCreateShareableLinkTooBig"));
278
       window.alert(t("alerts.couldNotCreateShareableLinkTooBig"));
282
     } else {
279
     } else {

+ 23
- 37
src/excalidraw-app/index.tsx View File

1
+import LanguageDetector from "i18next-browser-languagedetector";
1
 import React, {
2
 import React, {
2
-  useState,
3
-  useLayoutEffect,
3
+  useCallback,
4
   useEffect,
4
   useEffect,
5
+  useLayoutEffect,
5
   useRef,
6
   useRef,
6
-  useCallback,
7
+  useState,
7
 } from "react";
8
 } from "react";
8
-import LanguageDetector from "i18next-browser-languagedetector";
9
-
9
+import { getDefaultAppState } from "../appState";
10
+import { ExcalidrawImperativeAPI } from "../components/App";
11
+import { ErrorDialog } from "../components/ErrorDialog";
12
+import { TopErrorBoundary } from "../components/TopErrorBoundary";
13
+import { APP_NAME, EVENT, TITLE_TIMEOUT } from "../constants";
14
+import { ImportedDataState } from "../data/types";
15
+import {
16
+  ExcalidrawElement,
17
+  NonDeletedExcalidrawElement,
18
+} from "../element/types";
19
+import { Language, t } from "../i18n";
10
 import Excalidraw, {
20
 import Excalidraw, {
11
-  languages,
12
   defaultLang,
21
   defaultLang,
22
+  languages,
13
 } from "../packages/excalidraw/index";
23
 } from "../packages/excalidraw/index";
14
-
24
+import { AppState, ExcalidrawAPIRefValue } from "../types";
25
+import { debounce, ResolvablePromise, resolvablePromise } from "../utils";
26
+import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants";
27
+import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper";
28
+import { LanguageList } from "./components/LanguageList";
29
+import { exportToBackend, getCollaborationLinkData, loadScene } from "./data";
30
+import { loadFromFirebase } from "./data/firebase";
15
 import {
31
 import {
16
-  getTotalStorageSize,
17
   importFromLocalStorage,
32
   importFromLocalStorage,
18
   saveToLocalStorage,
33
   saveToLocalStorage,
19
   STORAGE_KEYS,
34
   STORAGE_KEYS,
20
 } from "./data/localStorage";
35
 } from "./data/localStorage";
21
 
36
 
22
-import { ImportedDataState } from "../data/types";
23
-import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper";
24
-import { TopErrorBoundary } from "../components/TopErrorBoundary";
25
-import { Language, t } from "../i18n";
26
-import { exportToBackend, loadScene } from "./data";
27
-import { getCollaborationLinkData } from "./data";
28
-import { EVENT } from "../constants";
29
-import { loadFromFirebase } from "./data/firebase";
30
-import { ExcalidrawImperativeAPI } from "../components/App";
31
-import { debounce, ResolvablePromise, resolvablePromise } from "../utils";
32
-import { AppState, ExcalidrawAPIRefValue } from "../types";
33
-import {
34
-  ExcalidrawElement,
35
-  NonDeletedExcalidrawElement,
36
-} from "../element/types";
37
-import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants";
38
-import { EVENT_LOAD, EVENT_SHARE, trackEvent } from "../analytics";
39
-import { ErrorDialog } from "../components/ErrorDialog";
40
-import { getDefaultAppState } from "../appState";
41
-import { APP_NAME, TITLE_TIMEOUT } from "../constants";
42
-import { LanguageList } from "./components/LanguageList";
43
-
44
 const languageDetector = new LanguageDetector();
37
 const languageDetector = new LanguageDetector();
45
 languageDetector.init({
38
 languageDetector.init({
46
   languageUtils: {
39
   languageUtils: {
163
     // into the remote scene
156
     // into the remote scene
164
     opts.resetScene();
157
     opts.resetScene();
165
     const scenePromise = opts.initializeSocketClient();
158
     const scenePromise = opts.initializeSocketClient();
166
-    trackEvent(EVENT_SHARE, "session join");
167
 
159
 
168
     try {
160
     try {
169
       const [, roomId, roomKey] = getCollaborationLinkData(
161
       const [, roomId, roomKey] = getCollaborationLinkData(
231
   const { collab } = props;
223
   const { collab } = props;
232
 
224
 
233
   useEffect(() => {
225
   useEffect(() => {
234
-    const storageSize = getTotalStorageSize();
235
-    if (storageSize) {
236
-      trackEvent(EVENT_LOAD, "storage", "size", storageSize);
237
-    } else {
238
-      trackEvent(EVENT_LOAD, "first time");
239
-    }
240
     excalidrawRef.current!.readyPromise.then((excalidrawApi) => {
226
     excalidrawRef.current!.readyPromise.then((excalidrawApi) => {
241
       initializeScene({
227
       initializeScene({
242
         resetScene: excalidrawApi.resetScene,
228
         resetScene: excalidrawApi.resetScene,

+ 0
- 3
src/i18n.ts View File

1
-import { EVENT_CHANGE, trackEvent } from "./analytics";
2
-
3
 import fallbackLangData from "./locales/en.json";
1
 import fallbackLangData from "./locales/en.json";
4
 import percentages from "./locales/percentages.json";
2
 import percentages from "./locales/percentages.json";
5
 
3
 
67
   currentLangData = await import(
65
   currentLangData = await import(
68
     /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
66
     /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
69
   );
67
   );
70
-  trackEvent(EVENT_CHANGE, "language", currentLang.code);
71
 };
68
 };
72
 
69
 
73
 export const setLanguageFirstTime = async (lang: Language) => {
70
 export const setLanguageFirstTime = async (lang: Language) => {

+ 2
- 5
src/zindex.ts View File

1
-import { AppState } from "./types";
2
 import { ExcalidrawElement } from "./element/types";
1
 import { ExcalidrawElement } from "./element/types";
3
 import { getElementsInGroup } from "./groups";
2
 import { getElementsInGroup } from "./groups";
4
-import { findLastIndex, findIndex } from "./utils";
5
-import { trackEvent, EVENT_LAYER } from "./analytics";
3
+import { AppState } from "./types";
4
+import { findIndex, findLastIndex } from "./utils";
6
 
5
 
7
 /**
6
 /**
8
  * Returns indices of elements to move based on selected elements.
7
  * Returns indices of elements to move based on selected elements.
176
           ];
175
           ];
177
   });
176
   });
178
 
177
 
179
-  trackEvent(EVENT_LAYER, "move", direction === "left" ? "down" : "up");
180
   return elements;
178
   return elements;
181
 };
179
 };
182
 
180
 
234
   const leadingElements = elements.slice(0, leadingIndex);
232
   const leadingElements = elements.slice(0, leadingIndex);
235
   const trailingElements = elements.slice(trailingIndex + 1);
233
   const trailingElements = elements.slice(trailingIndex + 1);
236
 
234
 
237
-  trackEvent(EVENT_LAYER, "move", direction === "left" ? "back" : "front");
238
   return direction === "left"
235
   return direction === "left"
239
     ? [
236
     ? [
240
         ...leadingElements,
237
         ...leadingElements,

Loading…
Cancel
Save