feat(editor): Overhaul expression editor modal (#4631)

* feat(editor): Integrate CodeMirror into expression editor modal (#4563)

*  Initial setup

* 👕 Fix lint

*  Extract segments

*  Implement var insertion

* 👕 Ignore `.d.cts`

*  Refactor to simplify

*  Add brace handler

*  Fully replace input and output

* feat(editor): Adjust resolved expression to match parameter input hint (#4600)

*  Initial adjustments

* 🐛 Prevent empty decorations

*  Adjust resolved expression to match param input hint

* ✏️ Improve comment

* 👕 Remove lint rule

* ✏️ Fix typo

* ✏️ Fix closing brace

*  Clean up `displayableSegments()`

* feat(editor): Apply styling to expression editor modal (#4607)

🎨 Apply styling

* feat(core): Improve errors in evaluated expression (#4619)

* 🐛 Fix env var access for FE

* 🔥 Remove excess closing bracket

* 🚧 Set up TODO

* ✏️ Update copy

*  Deny env vars access to FE

* 👕 Remove unneeded lint exception

* 📘 Remove unneeded typing

* feat(editor): Dynamically delay evaluation resolution (#4625)

* ✏️ Update copy

*  Dynamically delay evaluation resolution

* 🔥 Remove unneeded computed property

* refactor(editor): Pre-review cleanup (#4627)

* 🔥 Remove `ExpressionInput` component

* 🔥 Remove Quill

* ✏️ Rename i18n key

* 🎨 Place border on correct element

* 🐛 Handle syntax errors

*  Add sample autocompletions

* 🐛 Fix auto-extending behavior

* feat(editor): Improve escaping behavior (#4641)

* 🎨 Hide hint on small screen

*  Improve escaping

* refactor(editor): Apply styling feedback to expression editor modal (#4660)

* 🎨 Restyle hint

* 🎨 Restyle param input hint

* 🔥 Remove `e.g.`

*  Tweak delay

* 🎨 Restyle output

* 🎨 Tweak theme

* ✏️ Tweak copy

* refactor(editor): Apply feedback 2022.11.22 (#4697)

* 🎨 Change background color

*  Focus on mount

*  Account for preexisting braces on injection

* 🐛 Fix `$workflow` showing as not saved

* ✏️ Tweak copy

* 🐛 Fix readonly focus

*  Focus input on paste

*  Sync inputs with modal

* ✏️ Tweak copy

* refactor(editor): Apply feedback 2022.11.23 (#4705)

*  Allow newlines

*  Set cursor at end of content

*  Do not defocus on paste on Chrome

*  Fix import

* 🧪 Add e2e tests

*  Cleanup

*  Add telemetry

* 🔥 Remove log

*  Expose error properties

* 🧪 Rename test

*  Move `getCurrentWorkflow()` call

*  Revert highlighting removal per feedback

*  Add i18n keys

* 🚚 Move computed property to local state

* 🎨 Use CSS vars

*  Update `pnpm-lock.yaml`

*  Apply readonly state

*  Use prop

*  Complete fix
This commit is contained in:
Iván Ovejero
2022-12-01 13:26:22 +01:00
committed by GitHub
parent 830bda5f55
commit 59771c80ea
33 changed files with 1043 additions and 637 deletions

View File

@@ -289,15 +289,12 @@ export class WorkflowDataProxy {
if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
if (that.workflow.getNode(nodeName)) {
throw new ExpressionError(
`The node "${nodeName}" hasn't been executed yet, so you can't reference its output data`,
{
runIndex: that.runIndex,
itemIndex: that.itemIndex,
},
);
throw new ExpressionError(`no data, execute "${nodeName}" node first`, {
runIndex: that.runIndex,
itemIndex: that.itemIndex,
});
}
throw new ExpressionError(`No node called "${nodeName}" in this workflow`, {
throw new ExpressionError(`"${nodeName}" node doesn't exist`, {
runIndex: that.runIndex,
itemIndex: that.itemIndex,
});
@@ -335,13 +332,10 @@ export class WorkflowDataProxy {
);
if (nodeConnection === undefined) {
throw new ExpressionError(
`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`,
{
runIndex: that.runIndex,
itemIndex: that.itemIndex,
},
);
throw new ExpressionError(`connect ${that.activeNodeName} to ${nodeName}`, {
runIndex: that.runIndex,
itemIndex: that.itemIndex,
});
}
outputIndex = nodeConnection.sourceIndex;
}
@@ -383,16 +377,16 @@ export class WorkflowDataProxy {
const that = this;
const node = this.workflow.nodes[nodeName];
if (!node) {
return undefined;
}
return new Proxy(
{ binary: undefined, data: undefined, json: undefined },
{
get(target, name, receiver) {
name = name.toString();
if (!node) {
throw new ExpressionError(`"${nodeName}" node doesn't exist`);
}
if (['binary', 'data', 'json'].includes(name)) {
const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
if (executionData.length <= that.itemIndex) {
@@ -463,8 +457,11 @@ export class WorkflowDataProxy {
{},
{
get(target, name, receiver) {
if (process.env.N8N_BLOCK_ENV_ACCESS_IN_NODE === 'true') {
throw new ExpressionError('Environment variable access got disabled', {
if (
typeof process === 'undefined' || // env vars are inaccessible to frontend
process.env.N8N_BLOCK_ENV_ACCESS_IN_NODE === 'true'
) {
throw new ExpressionError('access to env vars denied', {
causeDetailed:
'If you need access please contact the administrator to remove the environment variable N8N_BLOCK_ENV_ACCESS_IN_NODE',
runIndex: that.runIndex,
@@ -544,7 +541,7 @@ export class WorkflowDataProxy {
const value = that.workflow[name as keyof typeof target];
if (value === undefined && name === 'id') {
throw new ExpressionError('Workflow is not saved', {
throw new ExpressionError('save workflow to view', {
description: `Please save the workflow first to use $workflow`,
runIndex: that.runIndex,
itemIndex: that.itemIndex,
@@ -906,7 +903,7 @@ export class WorkflowDataProxy {
const referencedNode = that.workflow.getNode(nodeName);
if (referencedNode === null) {
throw createExpressionError(`No node called ${nodeName}`);
throw createExpressionError(`"${nodeName}" node doesn't exist`);
}
return new Proxy(