mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-28 14:09:43 -08:00
071e6d6b6e
## Summary <img width="1240" alt="image" src="https://github.com/n8n-io/n8n/assets/8850410/2819f4ce-c343-431a-8a88-a1bc9c4b572a"> <img width="2649" alt="image" src="https://github.com/n8n-io/n8n/assets/8850410/36862aaf-cc4c-4668-bdc8-cf5a6f00babe"> 1. Add code node and open it 3. Click the fullscreen button in the bottom right 4. A fullscreen dialog should appear and allow editing the code 5. Changes made in the fullscreen dialog should be applied to the original code editor when closed It should work the same way for HTML/SQL/JSON editors ⚠️ Modal layout was updated so that modals/dialogs are centered, try to test some modals ## Related tickets and issues https://linear.app/n8n/issue/NODE-1009/add-fullscreen-view-to-code-node ## Review / Merge checklist - [ ] PR title and summary are descriptive. **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** ([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md)) - [ ] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up ticket created. - [ ] Tests included. > A bug is not considered fixed, unless a test is added to prevent it from happening again. > A feature is not complete without tests. --------- Co-authored-by: Giulio Andreini <andreini@netseven.it>
112 lines
3 KiB
TypeScript
112 lines
3 KiB
TypeScript
import type {
|
|
IDataObject,
|
|
IExecuteFunctions,
|
|
INodeExecutionData,
|
|
INodeProperties,
|
|
} from 'n8n-workflow';
|
|
import { NodeOperationError } from 'n8n-workflow';
|
|
|
|
import type { PgpDatabase, QueriesRunner, QueryWithValues } from '../../helpers/interfaces';
|
|
|
|
import { replaceEmptyStringsByNulls } from '../../helpers/utils';
|
|
|
|
import { optionsCollection } from '../common.descriptions';
|
|
import { getResolvables, updateDisplayOptions } from '@utils/utilities';
|
|
|
|
const properties: INodeProperties[] = [
|
|
{
|
|
displayName: 'Query',
|
|
name: 'query',
|
|
type: 'string',
|
|
default: '',
|
|
placeholder: 'e.g. SELECT id, name FROM product WHERE quantity > $1 AND price <= $2',
|
|
noDataExpression: true,
|
|
required: true,
|
|
description:
|
|
"The SQL query to execute. You can use n8n expressions and $1, $2, $3, etc to refer to the 'Query Parameters' set in options below.",
|
|
typeOptions: {
|
|
editor: 'sqlEditor',
|
|
sqlDialect: 'PostgreSQL',
|
|
},
|
|
hint: 'Consider using query parameters to prevent SQL injection attacks. Add them in the options below',
|
|
},
|
|
optionsCollection,
|
|
];
|
|
|
|
const displayOptions = {
|
|
show: {
|
|
resource: ['database'],
|
|
operation: ['executeQuery'],
|
|
},
|
|
};
|
|
|
|
export const description = updateDisplayOptions(displayOptions, properties);
|
|
|
|
export async function execute(
|
|
this: IExecuteFunctions,
|
|
runQueries: QueriesRunner,
|
|
items: INodeExecutionData[],
|
|
nodeOptions: IDataObject,
|
|
_db?: PgpDatabase,
|
|
): Promise<INodeExecutionData[]> {
|
|
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);
|
|
|
|
const queries: QueryWithValues[] = [];
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
let query = this.getNodeParameter('query', i) as string;
|
|
|
|
for (const resolvable of getResolvables(query)) {
|
|
query = query.replace(resolvable, this.evaluateExpression(resolvable, i) as string);
|
|
}
|
|
|
|
let values: Array<IDataObject | string> = [];
|
|
|
|
let queryReplacement = this.getNodeParameter('options.queryReplacement', i, '');
|
|
|
|
if (typeof queryReplacement === 'number') {
|
|
queryReplacement = String(queryReplacement);
|
|
}
|
|
|
|
if (typeof queryReplacement === 'string') {
|
|
const node = this.getNode();
|
|
|
|
const rawReplacements = (node.parameters.options as IDataObject)?.queryReplacement as string;
|
|
|
|
if (rawReplacements) {
|
|
const rawValues = rawReplacements
|
|
.replace(/^=+/, '')
|
|
.split(',')
|
|
.filter((entry) => entry)
|
|
.map((entry) => entry.trim());
|
|
|
|
for (const rawValue of rawValues) {
|
|
const resolvables = getResolvables(rawValue);
|
|
|
|
if (resolvables.length) {
|
|
for (const resolvable of resolvables) {
|
|
values.push(this.evaluateExpression(`${resolvable}`, i) as IDataObject);
|
|
}
|
|
} else {
|
|
values.push(rawValue);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (Array.isArray(queryReplacement)) {
|
|
values = queryReplacement as IDataObject[];
|
|
} else {
|
|
throw new NodeOperationError(
|
|
this.getNode(),
|
|
'Query Parameters must be a string of comma-separated values or an array of values',
|
|
{ itemIndex: i },
|
|
);
|
|
}
|
|
}
|
|
|
|
queries.push({ query, values });
|
|
}
|
|
|
|
return runQueries(queries, items, nodeOptions);
|
|
}
|