n8n/packages/editor-ui/src/utils/telemetryUtils.ts

81 lines
2.2 KiB
TypeScript
Raw Normal View History

feat(editor): Inline expression editor (#4814) * WIP * :fire: Remove unneeded watch * :zap: Further setup * :zap: Fix import * :zap: Minor tweaks * :fire: Remove logging * :art: Add some styling * :art: More styling changes * :bug: Fix wrong marking of stale data * :art: Prevent fx on dragging * :fire: Remove logging * :zap: Refine draggable target offsets * refactor(editor): Consolidate expression management logic (#4836) * :zap: Extract `ExpressionFunctionIcon` * :zap: Simplify syntax * :zap: Move to mixin * :art: Format * :blue_book: Unify types * :zap: Dedup double brace handler * :zap: Consolidate resolvable highlighter * :art: Format * :zap: Consolidate language pack * :pencil2: Add comment * :zap: Move completions to plugins * :zap: Partially deduplicate themes * refactor(editor): Apply styling feedback to inline expression editor (#4846) * :art: Adjust styling for expression parameter input * :art: Style outputs differently * :zap: Set single line for RLC * :art: Style both openers identically * :bug: Prevent defocus on resize * :zap: Adjust line height * :art: Adjust border with for expression input * :zap: Fix font family for inline output * :zap: Set up telemetry * :zap: Complete telemetry * :zap: Simplify event source * :zap: Set monospaced font for inline output * :art: Hide cursor on schema pill drop * :test_tube: Update snapshots * :zap: Consolidate editor styles * :pencil2: Add tech debt comments * :zap: Improve naming * :zap: Improve inside resolvable detection * :zap: Improve var naming * :fire: Remove outdated comment * :truck: Move constant to data * :pencil2: Clarify comments * :fire: Remove outdated comments * :fire: Remove unneeded try-catch * :fire: Remove unneeded method * :fire: Remove unneeded check * :fire: Remove `openExpression` check * :fire: Remove unused timeout * :fire: Remove commented out sections * :zap: Use Pinia naming convention * :zap: Re-evaluate on change of `ndvInputData` * :bug: Fix handling of `0` in number-type input * :bug: Surface focus and blur for mapping hints * :fire: Remove logging * :pencil2: Reword error * :zap: Change kebab-case to PascalCase * :zap: Refactor state fields for clarity * :zap: Support double bracing on selection * :art: More styling * :zap: Miscellaneous cleanup * :zap: Disregard error on drop * :art: Fix schema pill styling * :art: More `background` to `background-color` fixes * :test_tube: Update snapshots * :art: Replace non-existing var with white * :test_tube: Update snapshot * :package: Integrate `codemirror-lang-n8n-expression` * :art: Fix formatting * :test_tube: Re-update test snapshots * :test_tube: Update selectors for inline editor * :fire: Remove unused test ID * :blue_book: Add type for `currentNodePaneType` * :zap: Refactor mixin to util * :zap: Use `:global` * :fire: Remove comment * :zap: Add watch * :zap: Change import style * :shirt: Fix lint * :zap: Refactor preventing blur on resize * :fire: Remove comment * :test_tube: Re-update snapshots * :art: Prettify * :shirt: Fix lint * :fire: Remove comment Co-authored-by: Mutasem <mutdmour@gmail.com>
2022-12-14 05:43:02 -08:00
import { hasExpressionMapping } from '@/utils';
import type { Resolvable, Segment } from '@/types/expressions';
export function createExpressionTelemetryPayload(
segments: Segment[],
value: string,
workflowId: string,
sessionId: string,
activeNodeType: string,
eventSource = 'ndv',
) {
const resolvables = segments.filter((s): s is Resolvable => s.kind === 'resolvable');
const erroringResolvables = resolvables.filter((r) => r.error);
return {
empty_expression: value === '=' || value === '={{}}' || !value,
workflow_id: workflowId,
source: eventSource,
session_id: sessionId,
is_transforming_data: resolvables.some((r) => isTransformingData(r.resolvable)),
has_parameter: value.includes('$parameter'),
has_mapping: hasExpressionMapping(value),
node_type: activeNodeType,
handlebar_count: resolvables.length,
handlebar_error_count: erroringResolvables.length,
short_errors: erroringResolvables.map((r) => r.resolved ?? null),
full_errors: erroringResolvables.map((erroringResolvable) => {
if (!erroringResolvable.fullError) return null;
return {
...exposeErrorProperties(erroringResolvable.fullError),
stack: erroringResolvable.fullError.stack,
};
}),
};
}
/**
* Whether the resolvable is transforming data from another node,
* i.e. operating on `$input()`, `$json`, `$()` or `$node[]`.
*
* ```
* $input.all().
* $input.first().
* $input.last().
*
* $json['field'].
* $json["field"].
* $json.field'.
*
* $('nodeName').all().
* $('nodeName').first().
* $('nodeName').last().
*
* $("nodeName").all().
* $("nodeName").first().
* $("nodeName").last().
*
* $node['nodeName'].all().
* $node['nodeName'].first().
* $node['nodeName'].last().
*
* $node["nodeName"].all().
* $node["nodeName"].first().
* $node["nodeName"].last().
* ```
*/
function isTransformingData(resolvable: string) {
const regex =
/(\$input\.\w+\(\)\.|\$json(\[('|")|\.)\w+('|")]?\.|\$\(('|")\w+('|")\)\.\w+\(\)\.|\$node\[('|")\w+('|")\]\.\w+\(\)\.)/;
return regex.test(resolvable);
}
function exposeErrorProperties(error: Error) {
return Object.getOwnPropertyNames(error).reduce<Record<string, unknown>>((acc, key) => {
return (acc[key] = error[key as keyof Error]), acc;
}, {});
}