feat(editor): Removing ph-no-capture class from some elements (#6674)

* feat(editor): Remove `.ph-no-capture` class from some of the fields
* ✔️ Updating test snapshots
*  Redacting expressions preview in credentials form
* 🔧 Disable posthog input masking
* 🚨 Testing PostHog iFrame settings
* Reverting iframe test
*  Hiding API key in PostHog recordings
*  Added tests for redacted values
* ✔️ Updating checkbox snapshots after label component update
* ✔️ Updating test snapshots in editor-ui
* 👕 Fix lint errors
This commit is contained in:
Milorad FIlipović 2023-07-19 16:51:49 +02:00 committed by GitHub
parent 250175d066
commit c3455a4ad8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 173 additions and 118 deletions

View file

@ -27,6 +27,7 @@ exports[`components > N8nCheckbox > should render with both child and label 1`]
</strong> </strong>
<div <div
class="container" class="container"
data-test-id="input-label"
> >
<label <label
class="n8n-input-label inputLabel heading medium" class="n8n-input-label inputLabel heading medium"
@ -108,6 +109,7 @@ exports[`components > N8nCheckbox > should render with label 1`] = `
> >
<div <div
class="container" class="container"
data-test-id="input-label"
> >
<label <label
class="n8n-input-label inputLabel heading medium" class="n8n-input-label inputLabel heading medium"

View file

@ -85,11 +85,14 @@ export default defineComponent({
return this.size; return this.size;
}, },
classes(): string[] { classes(): string[] {
const classes = [];
if (this.size === 'xlarge') { if (this.size === 'xlarge') {
return ['xlarge']; classes.push('xlarge');
} }
if (this.type === 'password') {
return []; classes.push('ph-no-capture');
}
return classes;
}, },
}, },
methods: { methods: {

View file

@ -6,4 +6,22 @@ describe('N8nInput', () => {
const wrapper = render(N8nInput); const wrapper = render(N8nInput);
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
}); });
it('should add .ph-no-capture class on password input', () => {
const { container } = render(N8nInput, {
props: {
type: 'password',
},
});
expect(container.firstChild).toHaveClass('ph-no-capture');
});
it('should not add .ph-no-capture class on other input types', () => {
const { container } = render(N8nInput, {
props: {
type: 'number',
},
});
expect(container.firstChild).not.toHaveClass('ph-no-capture');
});
}); });

View file

@ -1,5 +1,5 @@
<template> <template>
<div :class="$style.container" v-on="$listeners"> <div :class="$style.container" v-on="$listeners" data-test-id="input-label">
<label <label
v-if="label || $slots.options" v-if="label || $slots.options"
:for="inputName" :for="inputName"

View file

@ -3,7 +3,6 @@
<div <div
v-if="!loading" v-if="!loading"
ref="editor" ref="editor"
class="ph-no-capture"
:class="$style[theme]" :class="$style[theme]"
v-html="htmlContent" v-html="htmlContent"
@click="onClick" @click="onClick"

View file

@ -17,12 +17,7 @@
@resizestart="onResizeStart" @resizestart="onResizeStart"
> >
<template> <template>
<div <div v-show="!editMode" :class="$style.wrapper" @dblclick.stop="onDoubleClick">
v-show="!editMode"
class="ph-no-capture"
:class="$style.wrapper"
@dblclick.stop="onDoubleClick"
>
<n8n-markdown <n8n-markdown
theme="sticky" theme="sticky"
:content="content" :content="content"
@ -38,8 +33,7 @@
@keydown.esc="onInputBlur" @keydown.esc="onInputBlur"
@keydown.stop @keydown.stop
@wheel.stop @wheel.stop
class="sticky-textarea ph-no-capture" :class="{ 'full-height': !shouldShowFooter, 'sticky-textarea': true }"
:class="{ 'full-height': !shouldShowFooter }"
> >
<n8n-input <n8n-input
:value="content" :value="content"

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="ph-no-capture" :class="classes"> <div :class="classes">
<div :class="$style.avatarContainer"> <div :class="$style.avatarContainer">
<n8n-avatar :firstName="firstName" :lastName="lastName" /> <n8n-avatar :firstName="firstName" :lastName="lastName" />
</div> </div>

View file

@ -3,7 +3,6 @@
<div <div
v-for="(user, i) in sortedUsers" v-for="(user, i) in sortedUsers"
:key="user.id" :key="user.id"
class="ph-no-capture"
:class="i === sortedUsers.length - 1 ? $style.itemContainer : $style.itemWithBorder" :class="i === sortedUsers.length - 1 ? $style.itemContainer : $style.itemWithBorder"
:data-test-id="`user-list-item-${user.email}`" :data-test-id="`user-list-item-${user.email}`"
> >

View file

@ -62,6 +62,10 @@ declare global {
isIdentifiedID?: boolean; isIdentifiedID?: boolean;
featureFlags: FeatureFlags; featureFlags: FeatureFlags;
}; };
session_recording?: {
maskAllInputs?: boolean;
maskInputFn?: ((text: string, element?: HTMLElement) => string) | null;
};
}, },
): void; ): void;
isFeatureEnabled?(flagName: string): boolean; isFeatureEnabled?(flagName: string): boolean;

View file

@ -5,7 +5,7 @@
@mouseout="onMouseOut" @mouseout="onMouseOut"
ref="codeNodeEditorContainer" ref="codeNodeEditorContainer"
> >
<div ref="codeNodeEditor" class="code-node-editor-input ph-no-capture"></div> <div ref="codeNodeEditor" class="code-node-editor-input"></div>
<n8n-button <n8n-button
v-if="aiButtonEnabled && (isEditorHovered || isEditorFocused)" v-if="aiButtonEnabled && (isEditorHovered || isEditorFocused)"
size="small" size="small"

View file

@ -2,7 +2,12 @@
<div> <div>
<n8n-input-label :label="label"> <n8n-input-label :label="label">
<div <div
:class="{ [$style.copyText]: true, [$style[size]]: true, [$style.collapsed]: collapse }" :class="{
[$style.copyText]: true,
[$style[size]]: true,
[$style.collapsed]: collapse,
'ph-no-capture': redactValue,
}"
@click="copy" @click="copy"
data-test-id="copy-input" data-test-id="copy-input"
> >
@ -56,6 +61,10 @@ export default defineComponent({
type: String, type: String,
default: 'large', default: 'large',
}, },
redactValue: {
type: Boolean,
default: false,
},
}, },
setup() { setup() {
return { return {

View file

@ -4,7 +4,7 @@
<credential-icon :credential-type-name="credentialType ? credentialType.name : ''" /> <credential-icon :credential-type-name="credentialType ? credentialType.name : ''" />
</template> </template>
<template #header> <template #header>
<n8n-heading tag="h2" bold class="ph-no-capture" :class="$style['card-heading']"> <n8n-heading tag="h2" bold :class="$style['card-heading']">
{{ data.name }} {{ data.name }}
</n8n-heading> </n8n-heading>
</template> </template>

View file

@ -88,10 +88,11 @@
:toastTitle=" :toastTitle="
$locale.baseText('credentialEdit.credentialConfig.redirectUrlCopiedToClipboard') $locale.baseText('credentialEdit.credentialConfig.redirectUrlCopiedToClipboard')
" "
:redactValue="true"
/> />
</template> </template>
<enterprise-edition v-else :features="[EnterpriseEditionFeature.Sharing]"> <enterprise-edition v-else :features="[EnterpriseEditionFeature.Sharing]">
<div class="ph-no-capture"> <div>
<n8n-info-tip :bold="false"> <n8n-info-tip :bold="false">
{{ {{
$locale.baseText('credentialEdit.credentialEdit.info.sharee', { $locale.baseText('credentialEdit.credentialEdit.info.sharee', {

View file

@ -176,7 +176,7 @@ onBeforeMount(() => {
filterable filterable
data-test-id="executions-filter-workflows-select" data-test-id="executions-filter-workflows-select"
> >
<div class="ph-no-capture"> <div>
<n8n-option <n8n-option
v-for="(item, idx) in props.workflows" v-for="(item, idx) in props.workflows"
:key="idx" :key="idx"

View file

@ -79,7 +79,7 @@
/> />
</td> </td>
<td> <td>
<span class="ph-no-capture" @click.stop="displayExecution(execution)" <span @click.stop="displayExecution(execution)"
><a href="#" :class="$style.link">{{ ><a href="#" :class="$style.link">{{
execution.workflowName || $locale.baseText('executionsList.unsavedWorkflow') execution.workflowName || $locale.baseText('executionsList.unsavedWorkflow')
}}</a></span }}</a></span

View file

@ -20,7 +20,11 @@
</div> </div>
<div class="variable-selector"> <div class="variable-selector">
<variable-selector :path="path" @itemSelected="itemSelected"></variable-selector> <variable-selector
:path="path"
:redactValues="redactValues"
@itemSelected="itemSelected"
></variable-selector>
</div> </div>
</el-col> </el-col>
<el-col :span="16" class="right-side"> <el-col :span="16" class="right-side">
@ -42,11 +46,12 @@
</n8n-link> </n8n-link>
</div> </div>
</div> </div>
<div class="expression-editor ph-no-capture"> <div class="expression-editor">
<ExpressionEditorModalInput <ExpressionEditorModalInput
:value="value" :value="value"
:isReadOnly="isReadOnlyRoute" :isReadOnly="isReadOnlyRoute"
:path="path" :path="path"
:class="{ 'ph-no-capture': redactValues }"
@change="valueChanged" @change="valueChanged"
@close="closeDialog" @close="closeDialog"
ref="inputFieldExpression" ref="inputFieldExpression"
@ -59,7 +64,7 @@
<div class="editor-description"> <div class="editor-description">
{{ $locale.baseText('expressionEdit.resultOfItem1') }} {{ $locale.baseText('expressionEdit.resultOfItem1') }}
</div> </div>
<div class="ph-no-capture"> <div :class="{ 'ph-no-capture': redactValues }">
<ExpressionEditorModalOutput <ExpressionEditorModalOutput
:segments="segments" :segments="segments"
ref="expressionResult" ref="expressionResult"
@ -97,7 +102,7 @@ import type { Segment } from '@/types/expressions';
export default defineComponent({ export default defineComponent({
name: 'ExpressionEdit', name: 'ExpressionEdit',
mixins: [externalHooks, genericHelpers, debounceHelper], mixins: [externalHooks, genericHelpers, debounceHelper],
props: ['dialogVisible', 'parameter', 'path', 'value', 'eventSource'], props: ['dialogVisible', 'parameter', 'path', 'value', 'eventSource', 'redactValues'],
components: { components: {
ExpressionEditorModalInput, ExpressionEditorModalInput,
ExpressionEditorModalOutput, ExpressionEditorModalOutput,

View file

@ -1,5 +1,5 @@
<template> <template>
<div ref="root" class="ph-no-capture" @keydown.stop></div> <div ref="root" @keydown.stop></div>
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -1,5 +1,5 @@
<template> <template>
<div ref="root" class="ph-no-capture"></div> <div ref="root"></div>
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -1,5 +1,5 @@
<template> <template>
<div ref="htmlEditor" class="ph-no-capture"></div> <div ref="htmlEditor"></div>
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -1,5 +1,5 @@
<template> <template>
<div ref="root" class="ph-no-capture" data-test-id="inline-expression-editor-input"></div> <div ref="root" data-test-id="inline-expression-editor-input"></div>
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -4,7 +4,7 @@
{{ $locale.baseText('parameterInput.resultForItem') }} {{ hoveringItemNumber }} {{ $locale.baseText('parameterInput.resultForItem') }} {{ hoveringItemNumber }}
</n8n-text> </n8n-text>
<n8n-text :class="$style.body"> <n8n-text :class="$style.body">
<div ref="root" class="ph-no-capture" data-test-id="inline-expression-editor-output"></div> <div ref="root" data-test-id="inline-expression-editor-output"></div>
</n8n-text> </n8n-text>
<div :class="$style.footer"> <div :class="$style.footer">
<n8n-text size="small" compact> <n8n-text size="small" compact>

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="ph-no-capture" :class="$style.container"> <div :class="$style.container">
<span v-if="readonly" :class="$style.headline"> <span v-if="readonly" :class="$style.headline">
{{ name }} {{ name }}
</span> </span>

View file

@ -45,7 +45,7 @@
:label="`${truncate(node.name)} ${getMultipleNodesText(node.name)}`" :label="`${truncate(node.name)} ${getMultipleNodesText(node.name)}`"
data-test-id="ndv-input-option" data-test-id="ndv-input-option"
> >
<span class="ph-no-capture">{{ truncate(node.name) }}&nbsp;</span> <span>{{ truncate(node.name) }}&nbsp;</span>
<span v-if="getMultipleNodesText(node.name)">{{ <span v-if="getMultipleNodesText(node.name)">{{
getMultipleNodesText(node.name) getMultipleNodesText(node.name)
}}</span> }}</span>

View file

@ -155,7 +155,7 @@
></div> ></div>
</div> </div>
<div class="node-description"> <div class="node-description">
<div class="node-name ph-no-capture" :title="nodeTitle"> <div class="node-name" :title="nodeTitle">
<p data-test-id="canvas-node-box-title"> <p data-test-id="canvas-node-box-title">
{{ nodeTitle }} {{ nodeTitle }}
</p> </p>

View file

@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<template #reference> <template #reference>
<div class="ph-no-capture" :class="{ [$style.title]: true, [$style.hoverable]: editable }"> <div :class="{ [$style.title]: true, [$style.hoverable]: editable }">
{{ value }} {{ value }}
<div :class="$style.editIconContainer"> <div :class="$style.editIconContainer">
<font-awesome-icon :class="$style.editIcon" icon="pencil-alt" v-if="editable" /> <font-awesome-icon :class="$style.editIcon" icon="pencil-alt" v-if="editable" />

View file

@ -9,6 +9,7 @@
:path="path" :path="path"
:eventSource="eventSource || 'ndv'" :eventSource="eventSource || 'ndv'"
:isReadOnly="isReadOnly" :isReadOnly="isReadOnly"
:redactValues="shouldRedactValue"
@closeDialog="closeExpressionEditDialog" @closeDialog="closeExpressionEditDialog"
@valueChanged="expressionUpdated" @valueChanged="expressionUpdated"
></expression-edit> ></expression-edit>
@ -41,6 +42,7 @@
:title="displayTitle" :title="displayTitle"
:isReadOnly="isReadOnly" :isReadOnly="isReadOnly"
:path="path" :path="path"
:class="{ 'ph-no-capture': shouldRedactValue }"
@valueChanged="expressionUpdated" @valueChanged="expressionUpdated"
@modalOpenerClick="openExpressionEditorModal" @modalOpenerClick="openExpressionEditorModal"
@focus="setFocus" @focus="setFocus"
@ -114,11 +116,7 @@
@valueChanged="valueChangedDebounced" @valueChanged="valueChangedDebounced"
/> />
<div <div v-else-if="editorType" class="readonly-code clickable" @click="displayEditDialog()">
v-else-if="editorType"
class="readonly-code clickable ph-no-capture"
@click="displayEditDialog()"
>
<code-node-editor <code-node-editor
v-if="!codeEditDialogVisible" v-if="!codeEditDialogVisible"
:value="value" :value="value"
@ -131,7 +129,7 @@
v-else v-else
v-model="tempValue" v-model="tempValue"
ref="inputField" ref="inputField"
class="input-with-opener" :class="{ 'input-with-opener': true, 'ph-no-capture': shouldRedactValue }"
:size="inputSize" :size="inputSize"
:type="getStringInputType" :type="getStringInputType"
:rows="getArgument('rows')" :rows="getArgument('rows')"
@ -204,6 +202,7 @@
: $locale.baseText('parameterInput.selectDateAndTime') : $locale.baseText('parameterInput.selectDateAndTime')
" "
:picker-options="dateTimePickerOptions" :picker-options="dateTimePickerOptions"
:class="{ 'ph-no-capture': shouldRedactValue }"
@change="valueChanged" @change="valueChanged"
@focus="setFocus" @focus="setFocus"
@blur="onBlur" @blur="onBlur"
@ -220,6 +219,7 @@
:min="getArgument('minValue')" :min="getArgument('minValue')"
:precision="getArgument('numberPrecision')" :precision="getArgument('numberPrecision')"
:disabled="isReadOnly" :disabled="isReadOnly"
:class="{ 'ph-no-capture': shouldRedactValue }"
@change="valueChanged" @change="valueChanged"
@input="onTextInputChange" @input="onTextInputChange"
@focus="setFocus" @focus="setFocus"
@ -274,7 +274,7 @@
> >
<div class="list-option"> <div class="list-option">
<div <div
class="option-headline ph-no-capture" class="option-headline"
:class="{ 'remote-parameter-option': isRemoteParameterOption(option) }" :class="{ 'remote-parameter-option': isRemoteParameterOption(option) }"
> >
{{ getOptionsOptionDisplayName(option) }} {{ getOptionsOptionDisplayName(option) }}
@ -331,7 +331,7 @@
/> />
<el-switch <el-switch
v-else-if="parameter.type === 'boolean'" v-else-if="parameter.type === 'boolean'"
class="switch-input" :class="{ 'switch-input': true, 'ph-no-capture': shouldRedactValue }"
ref="inputField" ref="inputField"
active-color="#13ce66" active-color="#13ce66"
:value="displayValue" :value="displayValue"
@ -830,6 +830,9 @@ export default defineComponent({
remoteParameterOptionsKeys(): string[] { remoteParameterOptionsKeys(): string[] {
return (this.remoteParameterOptions || []).map((o) => o.name); return (this.remoteParameterOptions || []).map((o) => o.name);
}, },
shouldRedactValue(): boolean {
return this.getStringInputType === 'password' || this.isForCredential;
},
}, },
methods: { methods: {
isRemoteParameterOption(option: INodePropertyOptions) { isRemoteParameterOption(option: INodePropertyOptions) {

View file

@ -27,9 +27,8 @@
/> />
<input-hint <input-hint
v-if="expressionOutput" v-if="expressionOutput"
:class="$style.hint" :class="{ [$style.hint]: true, 'ph-no-capture': isForCredential }"
data-test-id="parameter-expression-preview" data-test-id="parameter-expression-preview"
class="ph-no-capture"
:highlight="!!(expressionOutput && targetItem) && isInputParentOfActiveNode" :highlight="!!(expressionOutput && targetItem) && isInputParentOfActiveNode"
:hint="expressionOutput" :hint="expressionOutput"
:singleLine="true" :singleLine="true"

View file

@ -48,7 +48,6 @@
[$style.selected]: result.value === value, [$style.selected]: result.value === value,
[$style.hovering]: hoverIndex === i, [$style.hovering]: hoverIndex === i,
}" }"
class="ph-no-capture"
@click="() => onItemClick(result.value)" @click="() => onItemClick(result.value)"
@mouseenter="() => onItemHover(i)" @mouseenter="() => onItemHover(i)"
@mouseleave="() => onItemHoverLeave()" @mouseleave="() => onItemHoverLeave()"

View file

@ -1,5 +1,5 @@
<template> <template>
<iframe class="__html-display ph-no-capture" :srcdoc="html" /> <iframe class="__html-display" :srcdoc="html" />
</template> </template>
<script lang="ts"> <script lang="ts">

View file

@ -45,9 +45,7 @@
> >
</template> </template>
<template #nodeValue="{ node }"> <template #nodeValue="{ node }">
<span v-if="isNaN(node.index)" class="ph-no-capture">{{ <span v-if="isNaN(node.index)">{{ getContent(node.content) }}</span>
getContent(node.content)
}}</span>
<span <span
v-else v-else
data-target="mappable" data-target="mappable"
@ -59,7 +57,6 @@
[$style.mappable]: mappingEnabled, [$style.mappable]: mappingEnabled,
[$style.dragged]: draggingPath === node.path, [$style.dragged]: draggingPath === node.path,
}" }"
class="ph-no-capture"
>{{ getContent(node.content) }}</span >{{ getContent(node.content) }}</span
> >
</template> </template>

View file

@ -96,7 +96,7 @@ const getIconBySchemaType = (type: Schema['type']): string => {
<span v-if="key" :class="{ [$style.arrayIndex]: isSchemaParentTypeArray }">{{ key }}</span> <span v-if="key" :class="{ [$style.arrayIndex]: isSchemaParentTypeArray }">{{ key }}</span>
</span> </span>
</div> </div>
<span v-if="text" :class="$style.text" class="ph-no-capture">{{ text }}</span> <span v-if="text" :class="$style.text">{{ text }}</span>
<input v-if="level > 0 && isSchemaValueArray" :id="subKey" type="checkbox" checked /> <input v-if="level > 0 && isSchemaValueArray" :id="subKey" type="checkbox" checked />
<label v-if="level > 0 && isSchemaValueArray" :class="$style.toggle" :for="subKey"> <label v-if="level > 0 && isSchemaValueArray" :class="$style.toggle" :for="subKey">
<font-awesome-icon icon="angle-up" /> <font-awesome-icon icon="angle-up" />

View file

@ -121,7 +121,6 @@
<span <span
v-if="isSimple(data)" v-if="isSimple(data)"
:class="{ [$style.value]: true, [$style.empty]: isEmpty(data) }" :class="{ [$style.value]: true, [$style.empty]: isEmpty(data) }"
class="ph-no-capture"
>{{ getValueToRender(data) }}</span >{{ getValueToRender(data) }}</span
> >
<n8n-tree :nodeClass="$style.nodeClass" v-else :value="data"> <n8n-tree :nodeClass="$style.nodeClass" v-else :value="data">
@ -143,11 +142,9 @@
> >
</template> </template>
<template #value="{ value }"> <template #value="{ value }">
<span <span :class="{ [$style.nestedValue]: true, [$style.empty]: isEmpty(value) }">
:class="{ [$style.nestedValue]: true, [$style.empty]: isEmpty(value) }" {{ getValueToRender(value) }}
class="ph-no-capture" </span>
>{{ getValueToRender(value) }}</span
>
</template> </template>
</n8n-tree> </n8n-tree>
</td> </td>

View file

@ -2,7 +2,7 @@
<n8n-card :class="$style.cardLink" data-test-id="destination-card" @click="onClick"> <n8n-card :class="$style.cardLink" data-test-id="destination-card" @click="onClick">
<template #header> <template #header>
<div> <div>
<n8n-heading tag="h2" bold class="ph-no-capture" :class="$style.cardHeading"> <n8n-heading tag="h2" bold :class="$style.cardHeading">
{{ destination.label }} {{ destination.label }}
</n8n-heading> </n8n-heading>
<div :class="$style.cardDescription"> <div :class="$style.cardDescription">

View file

@ -1,6 +1,6 @@
<template> <template>
<div :class="$style.sqlEditor" v-click-outside="onBlur"> <div :class="$style.sqlEditor" v-click-outside="onBlur">
<div ref="sqlEditor" data-test-id="sql-editor-container" class="ph-no-capture"></div> <div ref="sqlEditor" data-test-id="sql-editor-container"></div>
<InlineExpressionEditorOutput <InlineExpressionEditorOutput
:segments="segments" :segments="segments"
:value="query" :value="query"

View file

@ -16,6 +16,7 @@
v-for="option in currentResults" v-for="option in currentResults"
:key="option.key" :key="option.key"
:extendAll="extendAll" :extendAll="extendAll"
:redactValues="redactValues"
@itemSelected="forwardItemSelected" @itemSelected="forwardItemSelected"
></variable-selector-item> ></variable-selector-item>
</div> </div>
@ -59,7 +60,7 @@ export default defineComponent({
components: { components: {
VariableSelectorItem, VariableSelectorItem,
}, },
props: ['path'], props: ['path', 'redactValues'],
data() { data() {
return { return {
variableFilter: '', variableFilter: '',

View file

@ -41,6 +41,7 @@
:key="option.key" :key="option.key"
:extendAll="extendAll" :extendAll="extendAll"
:allowParentSelect="option.allowParentSelect" :allowParentSelect="option.allowParentSelect"
:redactValues="redactValues"
class="sub-level" class="sub-level"
@itemSelected="forwardItemSelected" @itemSelected="forwardItemSelected"
></variable-selector-item> ></variable-selector-item>
@ -51,7 +52,7 @@
{{ item.name }}: {{ item.name }}:
<font-awesome-icon icon="dot-circle" title="Select Item" /> <font-awesome-icon icon="dot-circle" title="Select Item" />
</div> </div>
<div class="item-value ph-no-capture"> <div :class="{ 'ph-no-capture': redactValues, 'item-value': true }">
{{ item.value !== undefined ? item.value : $locale.baseText('variableSelectorItem.empty') }} {{ item.value !== undefined ? item.value : $locale.baseText('variableSelectorItem.empty') }}
</div> </div>
</div> </div>
@ -66,7 +67,7 @@ import { externalHooks } from '@/mixins/externalHooks';
export default defineComponent({ export default defineComponent({
name: 'VariableSelectorItem', name: 'VariableSelectorItem',
mixins: [externalHooks], mixins: [externalHooks],
props: ['allowParentSelect', 'extendAll', 'item'], props: ['allowParentSelect', 'extendAll', 'item', 'redactValues'],
mounted() { mounted() {
if (this.extended) return; if (this.extended) return;

View file

@ -1,13 +1,7 @@
<template> <template>
<n8n-card :class="$style.cardLink" @click="onClick"> <n8n-card :class="$style.cardLink" @click="onClick">
<template #header> <template #header>
<n8n-heading <n8n-heading tag="h2" bold :class="$style.cardHeading" data-test-id="workflow-card-name">
tag="h2"
bold
class="ph-no-capture"
:class="$style.cardHeading"
data-test-id="workflow-card-name"
>
{{ data.name }} {{ data.name }}
</n8n-heading> </n8n-heading>
</template> </template>

View file

@ -0,0 +1,51 @@
import { PiniaVuePlugin } from 'pinia';
import { render } from '@testing-library/vue';
import { merge } from 'lodash-es';
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
import { STORES } from '@/constants';
import { createTestingPinia } from '@pinia/testing';
import CopyInput from '@/components/CopyInput.vue';
const DEFAULT_SETUP = {
pinia: createTestingPinia({
initialState: {
[STORES.SETTINGS]: {
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
},
},
}),
props: {
copyButtonText: 'Click to copy',
label: 'Copy Input test',
},
};
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
render(CopyInput, merge(DEFAULT_SETUP, renderOptions), (vue) => {
vue.use(PiniaVuePlugin);
});
describe('BannerStack', () => {
afterEach(() => {
vi.clearAllMocks();
});
it('should render default configuration', async () => {
const { getByTestId } = renderComponent();
expect(getByTestId('input-label')).toHaveTextContent('Copy Input test');
expect(getByTestId('copy-input')).toHaveTextContent('Click to copy');
});
it('should render redacted version', async () => {
const { container, getByTestId } = renderComponent(
merge(DEFAULT_SETUP, {
props: {
redactValue: true,
},
}),
);
expect(getByTestId('copy-input')).toHaveClass('ph-no-capture');
});
});

View file

@ -65,17 +65,4 @@ describe('RunDataJson.vue', () => {
expect(screen.getByText('null')).toBeInTheDocument(); expect(screen.getByText('null')).toBeInTheDocument();
expect(screen.queryByText('undefined')).not.toBeInTheDocument(); expect(screen.queryByText('undefined')).not.toBeInTheDocument();
}); });
it('sets ph-no-capture class correctly', () => {
render(RunDataJson, DEFAULT_SETUP);
expect(screen.getByText('"list"')).not.toHaveClass('ph-no-capture');
expect(screen.getByText('"record"')).not.toHaveClass('ph-no-capture');
expect(screen.getByText('"myStringNumber"')).not.toHaveClass('ph-no-capture');
expect(screen.getByText('123')).toHaveClass('ph-no-capture');
expect(screen.getByText('"456"')).toHaveClass('ph-no-capture');
expect(screen.getByText('"abc"')).toHaveClass('ph-no-capture');
expect(screen.getByText('null')).toHaveClass('ph-no-capture');
});
}); });

View file

@ -21,7 +21,7 @@ exports[`PersonalizationModal.vue > should render correctly 1`] = `
<div> <div>
<div class=\\"grid\\"> <div class=\\"grid\\">
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"container\\" data-test-id=\\"companyType\\"><label for=\\"companyType\\" class=\\"n8n-input-label inputLabel heading medium\\"> <div data-test-id=\\"companyType\\" class=\\"container\\"><label for=\\"companyType\\" class=\\"n8n-input-label inputLabel heading medium\\">
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> What best describes your company? <!----></span></div> <div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> What best describes your company? <!----></span></div>
<!----> <!---->
<!----> <!---->
@ -71,7 +71,7 @@ exports[`PersonalizationModal.vue > should render correctly 1`] = `
</div> </div>
</div> </div>
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"container\\" data-test-id=\\"role\\"><label for=\\"role\\" class=\\"n8n-input-label inputLabel heading medium\\"> <div data-test-id=\\"role\\" class=\\"container\\"><label for=\\"role\\" class=\\"n8n-input-label inputLabel heading medium\\">
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Which role best describes you? <!----></span></div> <div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Which role best describes you? <!----></span></div>
<!----> <!---->
<!----> <!---->
@ -123,7 +123,7 @@ exports[`PersonalizationModal.vue > should render correctly 1`] = `
</div> </div>
</div> </div>
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"container\\" data-test-id=\\"automationBeneficiary\\"><label for=\\"automationBeneficiary\\" class=\\"n8n-input-label inputLabel heading medium\\"> <div data-test-id=\\"automationBeneficiary\\" class=\\"container\\"><label for=\\"automationBeneficiary\\" class=\\"n8n-input-label inputLabel heading medium\\">
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Who will your automations mainly be for? <!----></span></div> <div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> Who will your automations mainly be for? <!----></span></div>
<!----> <!---->
<!----> <!---->
@ -169,7 +169,7 @@ exports[`PersonalizationModal.vue > should render correctly 1`] = `
</div> </div>
</div> </div>
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"container\\" data-test-id=\\"companySize\\"><label for=\\"companySize\\" class=\\"n8n-input-label inputLabel heading medium\\"> <div data-test-id=\\"companySize\\" class=\\"container\\"><label for=\\"companySize\\" class=\\"n8n-input-label inputLabel heading medium\\">
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How big is your company? <!----></span></div> <div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How big is your company? <!----></span></div>
<!----> <!---->
<!----> <!---->
@ -218,7 +218,7 @@ exports[`PersonalizationModal.vue > should render correctly 1`] = `
</div> </div>
</div> </div>
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"container\\" data-test-id=\\"reportedSource\\"><label for=\\"reportedSource\\" class=\\"n8n-input-label inputLabel heading medium\\"> <div data-test-id=\\"reportedSource\\" class=\\"container\\"><label for=\\"reportedSource\\" class=\\"n8n-input-label inputLabel heading medium\\">
<div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How did you hear about n8n? <!----></span></div> <div class=\\"title\\"><span class=\\"n8n-text size-medium bold\\"> How did you hear about n8n? <!----></span></div>
<!----> <!---->
<!----> <!---->

View file

@ -138,7 +138,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
class="vjs-value vjs-value-number" class="vjs-value vjs-value-number"
> >
<span <span
class="ph-no-capture mappable" class="mappable"
data-depth="3" data-depth="3"
data-name="list[0]" data-name="list[0]"
data-path="[0].list[0]" data-path="[0].list[0]"
@ -180,7 +180,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
class="vjs-value vjs-value-number" class="vjs-value vjs-value-number"
> >
<span <span
class="ph-no-capture mappable" class="mappable"
data-depth="3" data-depth="3"
data-name="list[1]" data-name="list[1]"
data-path="[0].list[1]" data-path="[0].list[1]"
@ -222,7 +222,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
class="vjs-value vjs-value-number" class="vjs-value vjs-value-number"
> >
<span <span
class="ph-no-capture mappable" class="mappable"
data-depth="3" data-depth="3"
data-name="list[2]" data-name="list[2]"
data-path="[0].list[2]" data-path="[0].list[2]"
@ -351,9 +351,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-string" class="vjs-value vjs-value-string"
> >
<span <span>
class="ph-no-capture"
>
"Joe" "Joe"
</span> </span>
</span> </span>
@ -429,9 +427,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-number" class="vjs-value vjs-value-number"
> >
<span <span>
class="ph-no-capture"
>
123 123
</span> </span>
</span> </span>
@ -479,9 +475,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-string" class="vjs-value vjs-value-string"
> >
<span <span>
class="ph-no-capture"
>
"456" "456"
</span> </span>
</span> </span>
@ -529,9 +523,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-string" class="vjs-value vjs-value-string"
> >
<span <span>
class="ph-no-capture"
>
"abc" "abc"
</span> </span>
</span> </span>
@ -579,9 +571,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-null" class="vjs-value vjs-value-null"
> >
<span <span>
class="ph-no-capture"
>
null null
</span> </span>
</span> </span>
@ -629,9 +619,7 @@ exports[`RunDataJson.vue > renders json values properly 1`] = `
<span <span
class="vjs-value vjs-value-undefined" class="vjs-value vjs-value-undefined"
> >
<span <span>
class="ph-no-capture"
>
</span> </span>
</span> </span>

View file

@ -52,7 +52,7 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
John John
</span> </span>
@ -90,7 +90,7 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
22 22
</span> </span>
@ -176,7 +176,7 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
surfing surfing
</span> </span>
@ -216,7 +216,7 @@ exports[`RunDataJsonSchema.vue > renders schema for data 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
traveling traveling
</span> </span>
@ -458,7 +458,7 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
1 1
</span> </span>
@ -498,7 +498,7 @@ exports[`RunDataJsonSchema.vue > renders schema with spaces and dots 1`] = `
</span> </span>
</div> </div>
<span <span
class="ph-no-capture text" class="text"
> >
ignore ignore
</span> </span>

View file

@ -32,7 +32,7 @@ exports[`VariablesRow > should show key and value inputs in edit mode 1`] = `
"<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\"> "<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\">
<td class=\\"variables-key-column\\"> <td class=\\"variables-key-column\\">
<div> <div>
<div class=\\"container\\" data-test-id=\\"variable-row-key-input\\"> <div data-test-id=\\"variable-row-key-input\\" class=\\"container\\">
<!----> <!---->
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"el-input el-input--large n8n-input\\"> <div class=\\"el-input el-input--large n8n-input\\">
@ -49,7 +49,7 @@ exports[`VariablesRow > should show key and value inputs in edit mode 1`] = `
</td> </td>
<td class=\\"variables-value-column\\"> <td class=\\"variables-value-column\\">
<div> <div>
<div class=\\"container\\" data-test-id=\\"variable-row-value-input\\"> <div data-test-id=\\"variable-row-value-input\\" class=\\"container\\">
<!----> <!---->
<div class=\\"\\"> <div class=\\"\\">
<div class=\\"el-input el-input--large n8n-input\\"> <div class=\\"el-input el-input--large n8n-input\\">

View file

@ -118,6 +118,9 @@ export const usePostHog = defineStore('posthog', () => {
autocapture: config.autocapture, autocapture: config.autocapture,
disable_session_recording: config.disableSessionRecording, disable_session_recording: config.disableSessionRecording,
debug: config.debug, debug: config.debug,
session_recording: {
maskAllInputs: false,
},
}; };
window.posthog?.init(config.apiKey, options); window.posthog?.init(config.apiKey, options);

View file

@ -36,12 +36,13 @@
{{ $locale.baseText('generic.delete') }} {{ $locale.baseText('generic.delete') }}
</n8n-link> </n8n-link>
</span> </span>
<div class="ph-no-capture"> <div>
<CopyInput <CopyInput
:label="$locale.baseText('settings.api.view.myKey')" :label="$locale.baseText('settings.api.view.myKey')"
:value="apiKey" :value="apiKey"
:copy-button-text="$locale.baseText('generic.clickToCopy')" :copy-button-text="$locale.baseText('generic.clickToCopy')"
:toast-title="$locale.baseText('settings.api.view.copy.toast')" :toast-title="$locale.baseText('settings.api.view.copy.toast')"
:redactValue="true"
@copy="onCopy" @copy="onCopy"
/> />
</div> </div>

View file

@ -4,7 +4,7 @@
<n8n-heading size="2xlarge">{{ <n8n-heading size="2xlarge">{{
$locale.baseText('settings.personal.personalSettings') $locale.baseText('settings.personal.personalSettings')
}}</n8n-heading> }}</n8n-heading>
<div class="ph-no-capture" :class="$style.user"> <div :class="$style.user">
<span :class="$style.username" data-test-id="current-user-name"> <span :class="$style.username" data-test-id="current-user-name">
<n8n-text color="text-light">{{ currentUser.fullName }}</n8n-text> <n8n-text color="text-light">{{ currentUser.fullName }}</n8n-text>
</span> </span>