Skip to content

Commit 424c79c

Browse files
feat(editor): Add telemetry for focus panel (no-changelog) (n8n-io#17159)
Co-authored-by: Daria Staferova <daria.staferova@n8n.io>
1 parent 49dec19 commit 424c79c

5 files changed

Lines changed: 55 additions & 8 deletions

File tree

packages/frontend/editor-ui/src/components/FocusPanel.vue

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { useDebounce } from '@/composables/useDebounce';
2828
import { htmlEditorEventBus } from '@/event-bus';
2929
import { hasFocusOnInput, isFocusableEl } from '@/utils/typesUtils';
3030
import type { ResizeData, TargetNodeParameterContext } from '@/Interface';
31+
import { useTelemetry } from '@/composables/useTelemetry';
3132
import { useThrottleFn } from '@vueuse/core';
3233
import { useStyles } from '@/composables/useStyles';
3334
import { useExecutionData } from '@/composables/useExecutionData';
@@ -53,6 +54,7 @@ const nodeHelpers = useNodeHelpers();
5354
const focusPanelStore = useFocusPanelStore();
5455
const workflowsStore = useWorkflowsStore();
5556
const nodeTypesStore = useNodeTypesStore();
57+
const telemetry = useTelemetry();
5658
const nodeSettingsParameters = useNodeSettingsParameters();
5759
const environmentsStore = useEnvironmentsStore();
5860
const deviceSupport = useDeviceSupport();
@@ -262,6 +264,22 @@ function optionSelected(command: string) {
262264
}
263265
}
264266
267+
function closeFocusPanel() {
268+
telemetry.track('User closed focus panel', {
269+
source: 'closeIcon',
270+
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat,
271+
});
272+
273+
focusPanelStore.closeFocusPanel();
274+
}
275+
276+
function onExecute() {
277+
telemetry.track(
278+
'User executed node from focus panel',
279+
focusPanelStore.focusedNodeParametersInTelemetryFormat[0],
280+
);
281+
}
282+
265283
const valueChangedDebounced = debounce(valueChanged, { debounceTime: 0 });
266284
267285
// Wait for editor to mount before focusing
@@ -343,13 +361,14 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
343361
:square="true"
344362
:hide-label="true"
345363
telemetry-source="focus"
346-
></NodeExecuteButton>
364+
@execute="onExecute"
365+
/>
347366
<N8nIcon
348367
:class="$style.closeButton"
349368
icon="x"
350369
color="text-base"
351370
size="xlarge"
352-
@click="focusPanelStore.closeFocusPanel"
371+
@click="closeFocusPanel"
353372
/>
354373
</div>
355374
</div>

packages/frontend/editor-ui/src/components/Node/NodeCreation.vue

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { useActions } from './NodeCreator/composables/useActions';
2121
import KeyboardShortcutTooltip from '@/components/KeyboardShortcutTooltip.vue';
2222
import AssistantIcon from '@n8n/design-system/components/AskAssistantIcon/AssistantIcon.vue';
2323
import { useI18n } from '@n8n/i18n';
24+
import { useTelemetry } from '@/composables/useTelemetry';
2425
import { useAssistantStore } from '@/stores/assistant.store';
2526
2627
type Props = {
@@ -46,6 +47,7 @@ const uiStore = useUIStore();
4647
const focusPanelStore = useFocusPanelStore();
4748
const posthogStore = usePostHog();
4849
const i18n = useI18n();
50+
const telemetry = useTelemetry();
4951
const assistantStore = useAssistantStore();
5052
5153
const { getAddedNodesAndConnections } = useActions();
@@ -86,6 +88,15 @@ function nodeTypeSelected(value: NodeTypeSelectedPayload[]) {
8688
closeNodeCreator(true);
8789
}
8890
91+
function toggleFocusPanel() {
92+
focusPanelStore.toggleFocusPanel();
93+
94+
telemetry.track(`User ${focusPanelStore.focusPanelActive ? 'opened' : 'closed'} focus panel`, {
95+
source: 'canvasButton',
96+
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat,
97+
});
98+
}
99+
89100
function onAskAssistantButtonClick() {
90101
if (!assistantStore.chatWindowOpen)
91102
assistantStore.trackUserOpenedAssistant({
@@ -132,12 +143,7 @@ function onAskAssistantButtonClick() {
132143
:shortcut="{ keys: ['f'], shiftKey: true }"
133144
placement="left"
134145
>
135-
<n8n-icon-button
136-
type="tertiary"
137-
size="large"
138-
icon="panel-right"
139-
@click="focusPanelStore.toggleFocusPanel"
140-
/>
146+
<n8n-icon-button type="tertiary" size="large" icon="panel-right" @click="toggleFocusPanel" />
141147
</KeyboardShortcutTooltip>
142148
<n8n-tooltip v-if="assistantStore.canShowAssistantButtonsOnCanvas" placement="left">
143149
<template #content> {{ i18n.baseText('aiAssistant.tooltip') }}</template>

packages/frontend/editor-ui/src/components/ParameterInput.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import { isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
7878
import { hasFocusOnInput, isBlurrableEl, isFocusableEl, isSelectableEl } from '@/utils/typesUtils';
7979
import { completeExpressionSyntax, shouldConvertToExpression } from '@/utils/expressions';
8080
import CssEditor from './CssEditor/CssEditor.vue';
81+
import { useFocusPanelStore } from '@/stores/focusPanel.store';
8182
8283
type Picker = { $emit: (arg0: string, arg1: Date) => void };
8384
@@ -141,6 +142,7 @@ const workflowsStore = useWorkflowsStore();
141142
const settingsStore = useSettingsStore();
142143
const nodeTypesStore = useNodeTypesStore();
143144
const uiStore = useUIStore();
145+
const focusPanelStore = useFocusPanelStore();
144146
145147
// ESLint: false positive
146148
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
@@ -1000,6 +1002,10 @@ async function optionSelected(command: string) {
10001002
10011003
case 'focus':
10021004
nodeSettingsParameters.handleFocus(node.value, props.path, props.parameter);
1005+
telemetry.track('User opened focus panel', {
1006+
source: 'parameterButton',
1007+
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat,
1008+
});
10031009
return;
10041010
}
10051011

packages/frontend/editor-ui/src/stores/focusPanel.store.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ export const useFocusPanelStore = defineStore(STORES.FOCUS_PANEL, () => {
152152
return 'value' in p && 'node' in p;
153153
}
154154

155+
const focusedNodeParametersInTelemetryFormat = computed<
156+
Array<{ parameterPath: string; nodeType: string; nodeId: string }>
157+
>(() =>
158+
focusedNodeParameters.value.map((x) => ({
159+
parameterPath: x.parameterPath,
160+
nodeType: isRichParameter(x) ? x.node.type : 'unresolved',
161+
nodeId: x.nodeId,
162+
})),
163+
);
164+
155165
// Ensure lastFocusTimestamp is set on initial load if panel is already active (e.g. after reload)
156166
watchOnce(
157167
() => currentFocusPanelData.value,
@@ -165,6 +175,7 @@ export const useFocusPanelStore = defineStore(STORES.FOCUS_PANEL, () => {
165175
return {
166176
focusPanelActive,
167177
focusedNodeParameters,
178+
focusedNodeParametersInTelemetryFormat,
168179
lastFocusTimestamp,
169180
focusPanelWidth,
170181
openWithFocusedNodeParameter,

packages/frontend/editor-ui/src/views/NodeView.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,11 @@ function onToggleFocusPanel() {
12331233
}
12341234
12351235
focusPanelStore.toggleFocusPanel();
1236+
telemetry.track(`User ${focusPanelStore.focusPanelActive ? 'opened' : 'closed'} focus panel`, {
1237+
source: 'canvasKeyboardShortcut',
1238+
parameters: focusPanelStore.focusedNodeParametersInTelemetryFormat,
1239+
parameterCount: focusPanelStore.focusedNodeParametersInTelemetryFormat.length,
1240+
});
12361241
}
12371242
12381243
function closeNodeCreator() {

0 commit comments

Comments
 (0)