mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
chore: add ga for most actions (#4829)
This commit is contained in:
parent
e940aeb1a3
commit
f242721f3b
40 changed files with 221 additions and 93 deletions
|
@ -7,6 +7,7 @@ import { t } from "../i18n";
|
|||
|
||||
export const actionAddToLibrary = register({
|
||||
name: "addToLibrary",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState, _, app) => {
|
||||
const selectedElements = getSelectedElements(
|
||||
getNonDeletedElements(elements),
|
||||
|
|
|
@ -43,6 +43,7 @@ const alignSelectedElements = (
|
|||
|
||||
export const actionAlignTop = register({
|
||||
name: "alignTop",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -72,6 +73,7 @@ export const actionAlignTop = register({
|
|||
|
||||
export const actionAlignBottom = register({
|
||||
name: "alignBottom",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -101,6 +103,7 @@ export const actionAlignBottom = register({
|
|||
|
||||
export const actionAlignLeft = register({
|
||||
name: "alignLeft",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -130,6 +133,8 @@ export const actionAlignLeft = register({
|
|||
|
||||
export const actionAlignRight = register({
|
||||
name: "alignRight",
|
||||
trackEvent: { category: "element" },
|
||||
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -159,6 +164,8 @@ export const actionAlignRight = register({
|
|||
|
||||
export const actionAlignVerticallyCentered = register({
|
||||
name: "alignVerticallyCentered",
|
||||
trackEvent: { category: "element" },
|
||||
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -184,6 +191,7 @@ export const actionAlignVerticallyCentered = register({
|
|||
|
||||
export const actionAlignHorizontallyCentered = register({
|
||||
name: "alignHorizontallyCentered",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
|
|
@ -21,6 +21,7 @@ import { register } from "./register";
|
|||
export const actionUnbindText = register({
|
||||
name: "unbindText",
|
||||
contextItemLabel: "labels.unbindText",
|
||||
trackEvent: { category: "element" },
|
||||
contextItemPredicate: (elements, appState) => {
|
||||
const selectedElements = getSelectedElements(elements, appState);
|
||||
return selectedElements.some((element) => hasBoundTextElement(element));
|
||||
|
@ -62,6 +63,7 @@ export const actionUnbindText = register({
|
|||
export const actionBindText = register({
|
||||
name: "bindText",
|
||||
contextItemLabel: "labels.bindText",
|
||||
trackEvent: { category: "element" },
|
||||
contextItemPredicate: (elements, appState) => {
|
||||
const selectedElements = getSelectedElements(elements, appState);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import clsx from "clsx";
|
|||
|
||||
export const actionChangeViewBackgroundColor = register({
|
||||
name: "changeViewBackgroundColor",
|
||||
trackEvent: false,
|
||||
perform: (_, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, ...value },
|
||||
|
@ -50,6 +51,7 @@ export const actionChangeViewBackgroundColor = register({
|
|||
|
||||
export const actionClearCanvas = register({
|
||||
name: "clearCanvas",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (elements, appState, _, app) => {
|
||||
app.imageCache.clear();
|
||||
return {
|
||||
|
@ -82,6 +84,7 @@ export const actionClearCanvas = register({
|
|||
|
||||
export const actionZoomIn = register({
|
||||
name: "zoomIn",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (_elements, appState, _, app) => {
|
||||
return {
|
||||
appState: {
|
||||
|
@ -117,6 +120,7 @@ export const actionZoomIn = register({
|
|||
|
||||
export const actionZoomOut = register({
|
||||
name: "zoomOut",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (_elements, appState, _, app) => {
|
||||
return {
|
||||
appState: {
|
||||
|
@ -152,6 +156,7 @@ export const actionZoomOut = register({
|
|||
|
||||
export const actionResetZoom = register({
|
||||
name: "resetZoom",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (_elements, appState, _, app) => {
|
||||
return {
|
||||
appState: {
|
||||
|
@ -250,6 +255,7 @@ const zoomToFitElements = (
|
|||
|
||||
export const actionZoomToSelected = register({
|
||||
name: "zoomToSelection",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (elements, appState) => zoomToFitElements(elements, appState, true),
|
||||
keyTest: (event) =>
|
||||
event.code === CODES.TWO &&
|
||||
|
@ -260,6 +266,7 @@ export const actionZoomToSelected = register({
|
|||
|
||||
export const actionZoomToFit = register({
|
||||
name: "zoomToFit",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (elements, appState) => zoomToFitElements(elements, appState, false),
|
||||
keyTest: (event) =>
|
||||
event.code === CODES.ONE &&
|
||||
|
@ -270,6 +277,7 @@ export const actionZoomToFit = register({
|
|||
|
||||
export const actionToggleTheme = register({
|
||||
name: "toggleTheme",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (_, appState, value) => {
|
||||
return {
|
||||
appState: {
|
||||
|
@ -295,6 +303,7 @@ export const actionToggleTheme = register({
|
|||
|
||||
export const actionErase = register({
|
||||
name: "eraser",
|
||||
trackEvent: { category: "toolbar" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState: {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { t } from "../i18n";
|
|||
|
||||
export const actionCopy = register({
|
||||
name: "copy",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState, _, app) => {
|
||||
copyToClipboard(getNonDeletedElements(elements), appState, app.files);
|
||||
|
||||
|
@ -23,6 +24,7 @@ export const actionCopy = register({
|
|||
|
||||
export const actionCut = register({
|
||||
name: "cut",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState, data, app) => {
|
||||
actionCopy.perform(elements, appState, data, app);
|
||||
return actionDeleteSelected.perform(elements, appState);
|
||||
|
@ -33,6 +35,7 @@ export const actionCut = register({
|
|||
|
||||
export const actionCopyAsSvg = register({
|
||||
name: "copyAsSvg",
|
||||
trackEvent: { category: "element" },
|
||||
perform: async (elements, appState, _data, app) => {
|
||||
if (!app.canvas) {
|
||||
return {
|
||||
|
@ -73,6 +76,7 @@ export const actionCopyAsSvg = register({
|
|||
|
||||
export const actionCopyAsPng = register({
|
||||
name: "copyAsPng",
|
||||
trackEvent: { category: "element" },
|
||||
perform: async (elements, appState, _data, app) => {
|
||||
if (!app.canvas) {
|
||||
return {
|
||||
|
|
|
@ -58,6 +58,7 @@ const handleGroupEditingState = (
|
|||
|
||||
export const actionDeleteSelected = register({
|
||||
name: "deleteSelectedElements",
|
||||
trackEvent: { category: "element", action: "delete" },
|
||||
perform: (elements, appState) => {
|
||||
if (appState.editingLinearElement) {
|
||||
const {
|
||||
|
|
|
@ -39,6 +39,7 @@ const distributeSelectedElements = (
|
|||
|
||||
export const distributeHorizontally = register({
|
||||
name: "distributeHorizontally",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
@ -68,6 +69,7 @@ export const distributeHorizontally = register({
|
|||
|
||||
export const distributeVertically = register({
|
||||
name: "distributeVertically",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
appState,
|
||||
|
|
|
@ -22,6 +22,7 @@ import { isBoundToContainer } from "../element/typeChecks";
|
|||
|
||||
export const actionDuplicateSelection = register({
|
||||
name: "duplicateSelection",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
// duplicate selected point(s) if editing a line
|
||||
if (appState.editingLinearElement) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { trackEvent } from "../analytics";
|
||||
import { load, questionCircle, saveAs } from "../components/icons";
|
||||
import { ProjectName } from "../components/ProjectName";
|
||||
import { ToolButton } from "../components/ToolButton";
|
||||
|
@ -23,8 +22,8 @@ import { Theme } from "../element/types";
|
|||
|
||||
export const actionChangeProjectName = register({
|
||||
name: "changeProjectName",
|
||||
trackEvent: false,
|
||||
perform: (_elements, appState, value) => {
|
||||
trackEvent("change", "title");
|
||||
return { appState: { ...appState, name: value }, commitToHistory: false };
|
||||
},
|
||||
PanelComponent: ({ appState, updateData, appProps }) => (
|
||||
|
@ -41,6 +40,7 @@ export const actionChangeProjectName = register({
|
|||
|
||||
export const actionChangeExportScale = register({
|
||||
name: "changeExportScale",
|
||||
trackEvent: { category: "export", action: "scale" },
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportScale: value },
|
||||
|
@ -89,6 +89,7 @@ export const actionChangeExportScale = register({
|
|||
|
||||
export const actionChangeExportBackground = register({
|
||||
name: "changeExportBackground",
|
||||
trackEvent: { category: "export", action: "toggleBackground" },
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportBackground: value },
|
||||
|
@ -107,6 +108,7 @@ export const actionChangeExportBackground = register({
|
|||
|
||||
export const actionChangeExportEmbedScene = register({
|
||||
name: "changeExportEmbedScene",
|
||||
trackEvent: { category: "export", action: "embedScene" },
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportEmbedScene: value },
|
||||
|
@ -128,6 +130,7 @@ export const actionChangeExportEmbedScene = register({
|
|||
|
||||
export const actionSaveToActiveFile = register({
|
||||
name: "saveToActiveFile",
|
||||
trackEvent: { category: "export" },
|
||||
perform: async (elements, appState, value, app) => {
|
||||
const fileHandleExists = !!appState.fileHandle;
|
||||
|
||||
|
@ -172,6 +175,7 @@ export const actionSaveToActiveFile = register({
|
|||
|
||||
export const actionSaveFileToDisk = register({
|
||||
name: "saveFileToDisk",
|
||||
trackEvent: { category: "export" },
|
||||
perform: async (elements, appState, value, app) => {
|
||||
try {
|
||||
const { fileHandle } = await saveAsJSON(
|
||||
|
@ -210,6 +214,7 @@ export const actionSaveFileToDisk = register({
|
|||
|
||||
export const actionLoadScene = register({
|
||||
name: "loadScene",
|
||||
trackEvent: { category: "export" },
|
||||
perform: async (elements, appState, _, app) => {
|
||||
try {
|
||||
const {
|
||||
|
@ -252,6 +257,7 @@ export const actionLoadScene = register({
|
|||
|
||||
export const actionExportWithDarkMode = register({
|
||||
name: "exportWithDarkMode",
|
||||
trackEvent: { category: "export", action: "toggleTheme" },
|
||||
perform: (_elements, appState, value) => {
|
||||
return {
|
||||
appState: { ...appState, exportWithDarkMode: value },
|
||||
|
|
|
@ -17,6 +17,7 @@ import { isBindingElement } from "../element/typeChecks";
|
|||
|
||||
export const actionFinalize = register({
|
||||
name: "finalize",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, _, { canvas, focusContainer }) => {
|
||||
if (appState.editingLinearElement) {
|
||||
const { elementId, startBindingElement, endBindingElement } =
|
||||
|
|
|
@ -35,6 +35,7 @@ const enableActionFlipVertical = (
|
|||
|
||||
export const actionFlipHorizontal = register({
|
||||
name: "flipHorizontal",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: flipSelectedElements(elements, appState, "horizontal"),
|
||||
|
@ -50,6 +51,7 @@ export const actionFlipHorizontal = register({
|
|||
|
||||
export const actionFlipVertical = register({
|
||||
name: "flipVertical",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: flipSelectedElements(elements, appState, "vertical"),
|
||||
|
|
|
@ -54,6 +54,7 @@ const enableActionGroup = (
|
|||
|
||||
export const actionGroup = register({
|
||||
name: "group",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
const selectedElements = getSelectedElements(
|
||||
getNonDeletedElements(elements),
|
||||
|
@ -147,6 +148,7 @@ export const actionGroup = register({
|
|||
|
||||
export const actionUngroup = register({
|
||||
name: "ungroup",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
const groupIds = getSelectedGroupIds(appState);
|
||||
if (groupIds.length === 0) {
|
||||
|
|
|
@ -62,6 +62,7 @@ type ActionCreator = (history: History) => Action;
|
|||
|
||||
export const createUndoAction: ActionCreator = (history) => ({
|
||||
name: "undo",
|
||||
trackEvent: { category: "history" },
|
||||
perform: (elements, appState) =>
|
||||
writeData(elements, appState, () => history.undoOnce()),
|
||||
keyTest: (event) =>
|
||||
|
@ -82,6 +83,7 @@ export const createUndoAction: ActionCreator = (history) => ({
|
|||
|
||||
export const createRedoAction: ActionCreator = (history) => ({
|
||||
name: "redo",
|
||||
trackEvent: { category: "history" },
|
||||
perform: (elements, appState) =>
|
||||
writeData(elements, appState, () => history.redoOnce()),
|
||||
keyTest: (event) =>
|
||||
|
|
|
@ -9,6 +9,7 @@ import { HelpIcon } from "../components/HelpIcon";
|
|||
|
||||
export const actionToggleCanvasMenu = register({
|
||||
name: "toggleCanvasMenu",
|
||||
trackEvent: { category: "menu" },
|
||||
perform: (_, appState) => ({
|
||||
appState: {
|
||||
...appState,
|
||||
|
@ -29,6 +30,7 @@ export const actionToggleCanvasMenu = register({
|
|||
|
||||
export const actionToggleEditMenu = register({
|
||||
name: "toggleEditMenu",
|
||||
trackEvent: { category: "menu" },
|
||||
perform: (_elements, appState) => ({
|
||||
appState: {
|
||||
...appState,
|
||||
|
@ -53,6 +55,7 @@ export const actionToggleEditMenu = register({
|
|||
|
||||
export const actionFullScreen = register({
|
||||
name: "toggleFullScreen",
|
||||
trackEvent: { category: "canvas", predicate: (appState) => !isFullScreen() },
|
||||
perform: () => {
|
||||
if (!isFullScreen()) {
|
||||
allowFullScreen();
|
||||
|
@ -69,6 +72,7 @@ export const actionFullScreen = register({
|
|||
|
||||
export const actionShortcuts = register({
|
||||
name: "toggleShortcuts",
|
||||
trackEvent: { category: "menu", action: "toggleHelpDialog" },
|
||||
perform: (_elements, appState, _, { focusContainer }) => {
|
||||
if (appState.showHelpDialog) {
|
||||
focusContainer();
|
||||
|
|
|
@ -6,6 +6,7 @@ import { register } from "./register";
|
|||
|
||||
export const actionGoToCollaborator = register({
|
||||
name: "goToCollaborator",
|
||||
trackEvent: { category: "collab" },
|
||||
perform: (_elements, appState, value) => {
|
||||
const point = value as Collaborator["pointer"];
|
||||
if (!point) {
|
||||
|
|
|
@ -194,6 +194,7 @@ const changeFontSize = (
|
|||
|
||||
export const actionChangeStrokeColor = register({
|
||||
name: "changeStrokeColor",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
...(value.currentItemStrokeColor && {
|
||||
|
@ -243,6 +244,7 @@ export const actionChangeStrokeColor = register({
|
|||
|
||||
export const actionChangeBackgroundColor = register({
|
||||
name: "changeBackgroundColor",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
...(value.currentItemBackgroundColor && {
|
||||
|
@ -285,6 +287,7 @@ export const actionChangeBackgroundColor = register({
|
|||
|
||||
export const actionChangeFillStyle = register({
|
||||
name: "changeFillStyle",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(elements, appState, (el) =>
|
||||
|
@ -334,6 +337,7 @@ export const actionChangeFillStyle = register({
|
|||
|
||||
export const actionChangeStrokeWidth = register({
|
||||
name: "changeStrokeWidth",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(elements, appState, (el) =>
|
||||
|
@ -381,6 +385,7 @@ export const actionChangeStrokeWidth = register({
|
|||
|
||||
export const actionChangeSloppiness = register({
|
||||
name: "changeSloppiness",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(elements, appState, (el) =>
|
||||
|
@ -429,6 +434,7 @@ export const actionChangeSloppiness = register({
|
|||
|
||||
export const actionChangeStrokeStyle = register({
|
||||
name: "changeStrokeStyle",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(elements, appState, (el) =>
|
||||
|
@ -476,6 +482,7 @@ export const actionChangeStrokeStyle = register({
|
|||
|
||||
export const actionChangeOpacity = register({
|
||||
name: "changeOpacity",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(elements, appState, (el) =>
|
||||
|
@ -525,6 +532,7 @@ export const actionChangeOpacity = register({
|
|||
|
||||
export const actionChangeFontSize = register({
|
||||
name: "changeFontSize",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return changeFontSize(elements, appState, () => value, value);
|
||||
},
|
||||
|
@ -582,6 +590,7 @@ export const actionChangeFontSize = register({
|
|||
|
||||
export const actionDecreaseFontSize = register({
|
||||
name: "decreaseFontSize",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return changeFontSize(elements, appState, (element) =>
|
||||
Math.round(
|
||||
|
@ -603,6 +612,7 @@ export const actionDecreaseFontSize = register({
|
|||
|
||||
export const actionIncreaseFontSize = register({
|
||||
name: "increaseFontSize",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return changeFontSize(elements, appState, (element) =>
|
||||
Math.round(element.fontSize * (1 + FONT_SIZE_RELATIVE_INCREASE_STEP)),
|
||||
|
@ -620,6 +630,7 @@ export const actionIncreaseFontSize = register({
|
|||
|
||||
export const actionChangeFontFamily = register({
|
||||
name: "changeFontFamily",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(
|
||||
|
@ -701,6 +712,7 @@ export const actionChangeFontFamily = register({
|
|||
|
||||
export const actionChangeTextAlign = register({
|
||||
name: "changeTextAlign",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(
|
||||
|
@ -773,6 +785,7 @@ export const actionChangeTextAlign = register({
|
|||
});
|
||||
export const actionChangeVerticalAlign = register({
|
||||
name: "changeVerticalAlign",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState, value) => {
|
||||
return {
|
||||
elements: changeProperty(
|
||||
|
@ -840,6 +853,7 @@ export const actionChangeVerticalAlign = register({
|
|||
|
||||
export const actionChangeSharpness = register({
|
||||
name: "changeSharpness",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, value) => {
|
||||
const targetElements = getTargetElements(
|
||||
getNonDeletedElements(elements),
|
||||
|
@ -904,6 +918,7 @@ export const actionChangeSharpness = register({
|
|||
|
||||
export const actionChangeArrowhead = register({
|
||||
name: "changeArrowhead",
|
||||
trackEvent: false,
|
||||
perform: (
|
||||
elements,
|
||||
appState,
|
||||
|
|
|
@ -5,6 +5,7 @@ import { getNonDeletedElements, isTextElement } from "../element";
|
|||
|
||||
export const actionSelectAll = register({
|
||||
name: "selectAll",
|
||||
trackEvent: { category: "canvas" },
|
||||
perform: (elements, appState) => {
|
||||
if (appState.editingLinearElement) {
|
||||
return false;
|
||||
|
|
|
@ -19,6 +19,7 @@ export let copiedStyles: string = "{}";
|
|||
|
||||
export const actionCopyStyles = register({
|
||||
name: "copyStyles",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
const element = elements.find((el) => appState.selectedElementIds[el.id]);
|
||||
if (element) {
|
||||
|
@ -39,6 +40,7 @@ export const actionCopyStyles = register({
|
|||
|
||||
export const actionPasteStyles = register({
|
||||
name: "pasteStyles",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
const pastedElement = JSON.parse(copiedStyles);
|
||||
if (!isExcalidrawElement(pastedElement)) {
|
||||
|
|
|
@ -2,12 +2,14 @@ import { CODES, KEYS } from "../keys";
|
|||
import { register } from "./register";
|
||||
import { GRID_SIZE } from "../constants";
|
||||
import { AppState } from "../types";
|
||||
import { trackEvent } from "../analytics";
|
||||
|
||||
export const actionToggleGridMode = register({
|
||||
name: "gridMode",
|
||||
trackEvent: {
|
||||
category: "canvas",
|
||||
predicate: (appState) => !appState.gridSize,
|
||||
},
|
||||
perform(elements, appState) {
|
||||
trackEvent("view", "mode", "grid");
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { CODES, KEYS } from "../keys";
|
|||
|
||||
export const actionToggleStats = register({
|
||||
name: "stats",
|
||||
trackEvent: { category: "menu" },
|
||||
perform(elements, appState) {
|
||||
return {
|
||||
appState: {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { CODES, KEYS } from "../keys";
|
||||
import { register } from "./register";
|
||||
import { trackEvent } from "../analytics";
|
||||
|
||||
export const actionToggleViewMode = register({
|
||||
name: "viewMode",
|
||||
trackEvent: {
|
||||
category: "canvas",
|
||||
predicate: (appState) => !appState.viewModeEnabled,
|
||||
},
|
||||
perform(elements, appState) {
|
||||
trackEvent("view", "mode", "view");
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { CODES, KEYS } from "../keys";
|
||||
import { register } from "./register";
|
||||
import { trackEvent } from "../analytics";
|
||||
|
||||
export const actionToggleZenMode = register({
|
||||
name: "zenMode",
|
||||
trackEvent: {
|
||||
category: "canvas",
|
||||
predicate: (appState) => !appState.zenModeEnabled,
|
||||
},
|
||||
perform(elements, appState) {
|
||||
trackEvent("view", "mode", "zen");
|
||||
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
|
||||
export const actionSendBackward = register({
|
||||
name: "sendBackward",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveOneLeft(elements, appState),
|
||||
|
@ -45,6 +46,7 @@ export const actionSendBackward = register({
|
|||
|
||||
export const actionBringForward = register({
|
||||
name: "bringForward",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveOneRight(elements, appState),
|
||||
|
@ -72,6 +74,7 @@ export const actionBringForward = register({
|
|||
|
||||
export const actionSendToBack = register({
|
||||
name: "sendToBack",
|
||||
trackEvent: { category: "element" },
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveAllLeft(elements, appState),
|
||||
|
@ -106,6 +109,8 @@ export const actionSendToBack = register({
|
|||
|
||||
export const actionBringToFront = register({
|
||||
name: "bringToFront",
|
||||
trackEvent: { category: "element" },
|
||||
|
||||
perform: (elements, appState) => {
|
||||
return {
|
||||
elements: moveAllRight(elements, appState),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Action,
|
||||
ActionsManagerInterface,
|
||||
UpdaterFn,
|
||||
ActionName,
|
||||
ActionResult,
|
||||
PanelComponentProps,
|
||||
ActionSource,
|
||||
} from "./types";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppClassProperties, AppState } from "../types";
|
||||
|
@ -14,21 +14,25 @@ import { trackEvent } from "../analytics";
|
|||
|
||||
const trackAction = (
|
||||
action: Action,
|
||||
source: "ui" | "keyboard" | "api",
|
||||
source: ActionSource,
|
||||
appState: Readonly<AppState>,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
app: AppClassProperties,
|
||||
value: any,
|
||||
) => {
|
||||
if (action.trackEvent !== false) {
|
||||
if (action.trackEvent) {
|
||||
try {
|
||||
if (action.trackEvent === true) {
|
||||
trackEvent(
|
||||
action.name,
|
||||
source,
|
||||
typeof value === "number" || typeof value === "string"
|
||||
? String(value)
|
||||
: undefined,
|
||||
);
|
||||
} else {
|
||||
action.trackEvent?.(action, source, value);
|
||||
if (typeof action.trackEvent === "object") {
|
||||
const shouldTrack = action.trackEvent.predicate
|
||||
? action.trackEvent.predicate(appState, elements, value)
|
||||
: true;
|
||||
if (shouldTrack) {
|
||||
trackEvent(
|
||||
action.trackEvent.category,
|
||||
action.trackEvent.action || action.name,
|
||||
`${source} (${app.deviceType.isMobile ? "mobile" : "desktop"})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("error while logging action:", error);
|
||||
|
@ -36,8 +40,8 @@ const trackAction = (
|
|||
}
|
||||
};
|
||||
|
||||
export class ActionManager implements ActionsManagerInterface {
|
||||
actions = {} as ActionsManagerInterface["actions"];
|
||||
export class ActionManager {
|
||||
actions = {} as Record<ActionName, Action>;
|
||||
|
||||
updater: (actionResult: ActionResult | Promise<ActionResult>) => void;
|
||||
|
||||
|
@ -106,30 +110,25 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
}
|
||||
}
|
||||
|
||||
trackAction(action, "keyboard", null);
|
||||
const elements = this.getElementsIncludingDeleted();
|
||||
const appState = this.getAppState();
|
||||
const value = null;
|
||||
|
||||
trackAction(action, "keyboard", appState, elements, this.app, null);
|
||||
|
||||
event.preventDefault();
|
||||
this.updater(
|
||||
data[0].perform(
|
||||
this.getElementsIncludingDeleted(),
|
||||
this.getAppState(),
|
||||
null,
|
||||
this.app,
|
||||
),
|
||||
);
|
||||
this.updater(data[0].perform(elements, appState, value, this.app));
|
||||
return true;
|
||||
}
|
||||
|
||||
executeAction(action: Action) {
|
||||
this.updater(
|
||||
action.perform(
|
||||
this.getElementsIncludingDeleted(),
|
||||
this.getAppState(),
|
||||
null,
|
||||
this.app,
|
||||
),
|
||||
);
|
||||
trackAction(action, "api", null);
|
||||
executeAction(action: Action, source: ActionSource = "api") {
|
||||
const elements = this.getElementsIncludingDeleted();
|
||||
const appState = this.getAppState();
|
||||
const value = null;
|
||||
|
||||
trackAction(action, source, appState, elements, this.app, value);
|
||||
|
||||
this.updater(action.perform(elements, appState, value, this.app));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,7 +146,11 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
) {
|
||||
const action = this.actions[name];
|
||||
const PanelComponent = action.PanelComponent!;
|
||||
const elements = this.getElementsIncludingDeleted();
|
||||
const appState = this.getAppState();
|
||||
const updateData = (formState?: any) => {
|
||||
trackAction(action, "ui", appState, elements, this.app, formState);
|
||||
|
||||
this.updater(
|
||||
action.perform(
|
||||
this.getElementsIncludingDeleted(),
|
||||
|
@ -156,8 +159,6 @@ export class ActionManager implements ActionsManagerInterface {
|
|||
this.app,
|
||||
),
|
||||
);
|
||||
|
||||
trackAction(action, "ui", formState);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -8,6 +8,8 @@ import {
|
|||
} from "../types";
|
||||
import { ToolButtonSize } from "../components/ToolButton";
|
||||
|
||||
export type ActionSource = "ui" | "keyboard" | "contextMenu" | "api";
|
||||
|
||||
/** if false, the action should be prevented */
|
||||
export type ActionResult =
|
||||
| {
|
||||
|
@ -139,15 +141,23 @@ export interface Action {
|
|||
appState: AppState,
|
||||
) => boolean;
|
||||
checked?: (appState: Readonly<AppState>) => boolean;
|
||||
trackEvent?:
|
||||
| boolean
|
||||
| ((action: Action, type: "ui" | "keyboard" | "api", value: any) => void);
|
||||
}
|
||||
|
||||
export interface ActionsManagerInterface {
|
||||
actions: Record<ActionName, Action>;
|
||||
registerAction: (action: Action) => void;
|
||||
handleKeyDown: (event: React.KeyboardEvent | KeyboardEvent) => boolean;
|
||||
renderAction: (name: ActionName) => React.ReactElement | null;
|
||||
executeAction: (action: Action) => void;
|
||||
trackEvent:
|
||||
| false
|
||||
| {
|
||||
category:
|
||||
| "toolbar"
|
||||
| "element"
|
||||
| "canvas"
|
||||
| "export"
|
||||
| "history"
|
||||
| "menu"
|
||||
| "collab"
|
||||
| "hyperlink";
|
||||
action?: string;
|
||||
predicate?: (
|
||||
appState: Readonly<AppState>,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
value: any,
|
||||
) => boolean;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue