Minor optimizations

This commit is contained in:
Iván Ovejero 2021-11-20 18:28:05 +01:00
parent d379d7ecf3
commit b4399a1c63
19 changed files with 144 additions and 99 deletions

View file

@ -41,10 +41,9 @@ class NodeTypesClass implements INodeTypes {
}
/**
* Variant of `getByNameAndVersion` that includes the node's source path,
* to be used for locating the node's `/translations` dir.
* Variant of `getByNameAndVersion` that includes the node's source path, used to locate a node's translations.
*/
getWithPath(
getWithSourcePath(
nodeTypeName: string,
version: number,
): { description: INodeTypeDescription } & { sourcePath: string } {

View file

@ -25,6 +25,8 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable import/no-dynamic-require */
/* eslint-disable no-await-in-loop */
import * as express from 'express';
import { readFileSync, existsSync } from 'fs';
import { dirname as pathDirname, join as pathJoin, resolve as pathResolve } from 'path';
@ -145,7 +147,7 @@ import { InternalHooksManager } from './InternalHooksManager';
import { TagEntity } from './databases/entities/TagEntity';
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
import { NameRequest } from './WorkflowHelpers';
import { getExpectedNodeTranslationPath } from './TranslationHelpers';
import { getNodeTranslationPath } from './TranslationHelpers';
require('body-parser-xml')(bodyParser);
@ -1179,33 +1181,28 @@ class App {
ResponseHelper.send(
async (req: express.Request, res: express.Response): Promise<INodeTypeDescription[]> => {
const nodeInfos = _.get(req, 'body.nodeInfos', []) as INodeTypeNameVersion[];
const nodeTypes = NodeTypes();
const language = config.get('defaultLocale') ?? req.headers['accept-language'] ?? 'en';
if (language === 'en') {
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
const { description } = nodeTypes.getByNameAndVersion(name, version);
const { description } = NodeTypes().getByNameAndVersion(name, version);
acc.push(description);
return acc;
}, []);
}
const nodeTypesWithTranslations: INodeTypeDescription[] = [];
const nodeTypes: INodeTypeDescription[] = [];
for (const { name, version } of nodeInfos) {
const { description, sourcePath } = nodeTypes.getWithPath(name, version);
// eslint-disable-next-line no-await-in-loop
const nodeTranslationPath = await getExpectedNodeTranslationPath(sourcePath, language);
if (existsSync(nodeTranslationPath)) {
description.translation = require(nodeTranslationPath);
const { description, sourcePath } = NodeTypes().getWithSourcePath(name, version);
const translationPath = await getNodeTranslationPath(sourcePath, language);
if (existsSync(translationPath)) {
description.translation = require(translationPath);
}
nodeTypesWithTranslations.push(description);
nodeTypes.push(description);
}
return nodeTypesWithTranslations;
return nodeTypes;
},
),
);
@ -2896,6 +2893,12 @@ export async function start(): Promise<void> {
console.log(`n8n ready on ${ADDRESS}, port ${PORT}`);
console.log(`Version: ${versions.cli}`);
const defaultLocale = config.get('defaultLocale');
if (!defaultLocale || defaultLocale !== 'en') {
console.log(`Locale: ${config.get('defaultLocale')}`);
}
await app.externalHooks.run('n8n.ready', [app]);
const cpus = os.cpus();
const diagnosticInfo: IDiagnosticInfo = {

View file

@ -26,7 +26,7 @@ async function getMaxVersion(from: string) {
return Math.max(...dirnames.map((d) => parseInt(d.charAt(1), 10)));
}
export async function getExpectedNodeTranslationPath(
export async function getNodeTranslationPath(
nodeSourcePath: string,
language: string,
): Promise<string> {

View file

@ -203,17 +203,12 @@ export default mixins(renderText, restApi).extend({
},
/**
* Add to the translation object the node translation
* for the credential being viewed.
* Add to the translation object the node translation for the credential in the modal.
*/
async addNodeTranslationForCredential() {
// TODO i18n: Check if node translation has already been added (via NodeView)
const { nodeType }: { nodeType: string } = this.$store.getters.credentialTextRenderKeys;
const version = await this.getCurrentNodeVersion(nodeType);
const nodeToBeFetched = [{ name: nodeType, version }];
const nodesInfo = await this.restApi().getNodesInformation(nodeToBeFetched);
const nodeInfo = nodesInfo.pop();

View file

@ -78,7 +78,7 @@ export default mixins(renderText).extend({
});
},
shortNodeType(nodeType: INodeTypeDescription) {
return nodeType.name.replace('n8n-nodes-base.', '');
return this.$shortNodeType(nodeType.name);
},
},
});

View file

@ -34,7 +34,7 @@ export default mixins(genericHelpers).extend({
};
if (this.keyName === 'name' && this.node.type.startsWith('n8n-nodes-base.')) {
const shortNodeType = this.node.type.replace('n8n-nodes-base.', '');
const shortNodeType = this.$shortNodeType(this.node.type);
return this.$headerText({
key: `headers.${shortNodeType}.displayName`,

View file

@ -115,10 +115,9 @@
</template>
</el-table-column>
<el-table-column property="mode" :label="$baseText('executionsList.mode')" width="100" align="center">
<!-- TODO i18n <template slot-scope="scope">
{{convertToDisplayDate(scope.row.startedAt)}}<br />
<small v-if="scope.row.id">ID: {{scope.row.id}}</small>
</template> -->
<template slot-scope="scope">
{{ $baseText(`executionsList.modes.${scope.row.mode}`) }}
</template>
</el-table-column>
<el-table-column :label="$baseText('executionsList.runningTime')" width="150" align="center">
<template slot-scope="scope">
@ -256,14 +255,6 @@ export default mixins(
},
];
},
modes () {
return {
error: this.$baseText('executionsList.modes.error'),
retry: this.$baseText('executionsList.modes.retry'),
manual: this.$baseText('executionsList.modes.manual'),
trigger: this.$baseText('executionsList.modes.trigger'),
};
},
activeExecutions (): IExecutionsCurrentSummaryExtended[] {
return this.$store.getters.getActiveExecutions;
},
@ -542,7 +533,7 @@ export default mixins(
this.finishedExecutions = data.results.map((execution) => {
// @ts-ignore
return { ...execution, mode: this.modes[execution.mode] };
return { ...execution, mode: execution.mode };
});
this.finishedExecutionsCount = data.count;
this.finishedExecutionsCountEstimated = data.estimated;
@ -577,7 +568,7 @@ export default mixins(
data.results = data.results.map((execution) => {
// @ts-ignore
return { ...execution, mode: this.modes[execution.mode] };
return { ...execution, mode: execution.mode };
});
this.finishedExecutions.push.apply(this.finishedExecutions, data.results);

View file

@ -469,8 +469,8 @@ export default mixins(
this.$baseText('mainSidebar.confirmMessage.workflowNew.message'),
this.$baseText('mainSidebar.confirmMessage.workflowNew.headline'),
'warning',
this.$baseText('mainSidebar.confirmMessage.workflowNew.confirmButton'),
this.$baseText('mainSidebar.confirmMessage.workflowNew.cancelButton'),
this.$baseText('mainSidebar.confirmMessage.workflowNew.confirmButtonText'),
this.$baseText('mainSidebar.confirmMessage.workflowNew.cancelButtonText'),
);
if (importConfirm === true) {
this.$store.commit('setStateDirty', false);

View file

@ -162,7 +162,7 @@ export default mixins(externalHooks, nodeBase, nodeHelpers, renderText, workflow
return returnStyles;
},
shortNodeType (): string {
return this.data.type.replace('n8n-nodes-base.', '');
return this.$shortNodeType(this.data.type);
},
waiting (): string | undefined {
const workflowExecution = this.$store.getters.getWorkflowExecution;

View file

@ -49,7 +49,7 @@ export default mixins(renderText).extend({
],
computed: {
shortNodeType() {
return this.nodeType.name.replace('n8n-nodes-base.', '');
return this.$shortNodeType(this.nodeType.name);
},
},
// @ts-ignore

View file

@ -97,7 +97,7 @@ export default mixins(
},
nodeTypeName(): string {
if (this.nodeType) {
const shortNodeType = this.nodeType.name.replace('n8n-nodes-base.', '');
const shortNodeType = this.$shortNodeType(this.nodeType.name);
return this.$headerText({
key: `headers.${shortNodeType}.displayName`,
@ -109,7 +109,7 @@ export default mixins(
},
nodeTypeDescription (): string {
if (this.nodeType && this.nodeType.description) {
const shortNodeType = this.nodeType.name.replace('n8n-nodes-base.', '');
const shortNodeType = this.$shortNodeType(this.nodeType.name);
return this.$headerText({
key: `headers.${shortNodeType}.description`,

View file

@ -1,7 +1,7 @@
<template>
<div @keydown.stop class="variable-selector-wrapper">
<div class="input-wrapper">
<n8n-input placeholder="Variable filter..." v-model="variableFilter" ref="inputField" size="small" type="text"></n8n-input>
<n8n-input :placeholder="$baseText('variableSelector.variableFilter')" v-model="variableFilter" ref="inputField" size="small" type="text"></n8n-input>
</div>
<div class="result-wrapper">
@ -525,14 +525,14 @@ export default mixins(
currentNodeData.push(
{
name: 'Parameters',
name: this.$baseText('variableSelector.parameters'),
options: this.sortOptions(this.getNodeParameters(activeNode.name, initialPath, skipParameter, filterText) as IVariableSelectorOption[]),
},
);
returnData.push(
{
name: 'Current Node',
name: this.$baseText('variableSelector.currentNode'),
options: this.sortOptions(currentNodeData),
},
);
@ -546,7 +546,7 @@ export default mixins(
let nodeOptions: IVariableSelectorOption[];
const upstreamNodes = this.workflow.getParentNodes(activeNode.name, inputName);
for (const nodeName of Object.keys(this.workflow.nodes)) {
for (const [nodeName, node] of Object.entries(this.workflow.nodes)) {
// Add the parameters of all nodes
// TODO: Later have to make sure that no parameters can be referenced which have expression which use input-data (for nodes which are not parent nodes)
@ -557,7 +557,7 @@ export default mixins(
nodeOptions = [
{
name: 'Parameters',
name: this.$baseText('variableSelector.parameters'),
options: this.sortOptions(this.getNodeParameters(nodeName, `$node["${nodeName}"].parameter`, undefined, filterText)),
} as IVariableSelectorOption,
];
@ -570,7 +570,7 @@ export default mixins(
if (tempOptions.length) {
nodeOptions = [
{
name: 'Context',
name: this.$baseText('variableSelector.context'),
options: this.sortOptions(tempOptions),
} as IVariableSelectorOption,
];
@ -583,16 +583,21 @@ export default mixins(
if (tempOutputData) {
nodeOptions.push(
{
name: 'Output Data',
name: this.$baseText('variableSelector.outputData'),
options: this.sortOptions(tempOutputData),
} as IVariableSelectorOption,
);
}
}
const shortNodeType = this.$shortNodeType(node.type);
allNodesData.push(
{
name: nodeName,
name: this.$headerText({
key: `headers.${shortNodeType}.displayName`,
fallback: nodeName,
}),
options: this.sortOptions(nodeOptions),
},
);
@ -600,7 +605,7 @@ export default mixins(
returnData.push(
{
name: 'Nodes',
name: this.$baseText('variableSelector.nodes'),
options: this.sortOptions(allNodesData),
},
);

View file

@ -23,17 +23,16 @@ export const genericHelpers = mixins(showMessage, renderText).extend({
displayTimer (msPassed: number, showMs = false): string {
if (msPassed < 60000) {
if (showMs === false) {
return `${Math.floor(msPassed / 1000)} ${this.$baseText('genericHelpers.sec')}`;
return `${this.$n(Math.floor(msPassed / 1000), 'decimal')} ${this.$baseText('genericHelpers.sec')}`;
}
return `${msPassed / 1000} ${this.$baseText('genericHelpers.sec')}`;
return `${this.$n(msPassed / 1000, 'decimal')} ${this.$baseText('genericHelpers.sec')}`;
}
const secondsPassed = Math.floor(msPassed / 1000);
const minutesPassed = Math.floor(secondsPassed / 60);
const secondsLeft = (secondsPassed - (minutesPassed * 60)).toString().padStart(2, '0');
return `${minutesPassed}:${secondsLeft} min.`;
return `${this.$n(minutesPassed, 'decimal')}:${this.$n(secondsPassed, 'decimal')} ${this.$baseText('genericHelpers.min')}`;
},
editAllowedCheck (): boolean {
if (this.isReadOnly) {

View file

@ -1,14 +1,16 @@
/* tslint:disable: variable-name */
// import { TranslationPath } from '@/Interface';
import Vue from 'vue';
const REUSABLE_TEXT_KEY = 'reusableText';
const REUSABLE_DYNAMIC_TEXT_KEY = 'reusableDynamicText';
const CREDENTIALS_MODAL_KEY = 'credentialsModal';
const NODE_VIEW_KEY = 'nodeView';
export const renderText = Vue.extend({
methods: {
$shortNodeType(longNodeType: string) {
return longNodeType.replace('n8n-nodes-base.', '');
},
/**
* Render a string of base text, i.e. a string with a fixed path to the localized value in the base text object. Optionally allows for [interpolation](https://kazupon.github.io/vue-i18n/guide/formatting.html#named-formatting) when the localized value contains a string between curly braces.
*/
@ -55,7 +57,7 @@ export const renderText = Vue.extend({
) {
if (['clientId', 'clientSecret'].includes(parameterName)) {
return context.__render({
key: `${REUSABLE_TEXT_KEY}.oauth2.${parameterName}`,
key: `${REUSABLE_DYNAMIC_TEXT_KEY}.oauth2.${parameterName}`,
fallback: displayName,
});
}

View file

@ -40,8 +40,14 @@ export async function loadLanguage(language?: string) {
return Promise.resolve(setLanguage(language));
}
const baseText = require(`./locales/${language}`).default;
i18n.setLocaleMessage(language, baseText);
const { numberFormats, ...rest } = require(`./locales/${language}`).default;
i18n.setLocaleMessage(language, rest);
if (numberFormats) {
i18n.setNumberFormat(language, numberFormats);
}
loadedLanguages.push(language);
setLanguage(language);

View file

@ -1,5 +1,15 @@
export default {
reusableText: {
numberFormats: {
decimal: {
style: 'decimal',
},
},
reusableBaseText: {
cancel: '🇩🇪 Cancel',
save: '🇩🇪 Save',
name: '🇩🇪 Name',
},
reusableDynamicText: {
oauth2: {
clientId: '🇩🇪 Client ID',
clientSecret: '🇩🇪 Client Secret',
@ -120,7 +130,7 @@ export default {
noProperties: '🇩🇪 No properties',
},
credentialsList: {
name: '🇩🇪 Name',
name: '@:reusableBaseText.name',
type: '🇩🇪 Type',
credentials: '🇩🇪 Credentials',
addNew: '🇩🇪 Add New',
@ -165,11 +175,11 @@ export default {
setValue: '🇩🇪 Set Value',
},
duplicateWorkflowDialog: {
cancel: '🇩🇪 Cancel',
cancel: '@:reusableBaseText.cancel',
chooseOrCreateATag: '🇩🇪 Choose or create a tag',
duplicateWorkflow: '🇩🇪 Duplicate Workflow',
enterWorkflowName: '🇩🇪 Enter workflow name',
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
showMessage: {
message: '🇩🇪 Please enter a name.',
title: '🇩🇪 Name missing',
@ -292,7 +302,7 @@ export default {
filters: '🇩🇪 Filters',
loadMore: '🇩🇪 Load More',
mode: '🇩🇪 Mode',
name: '🇩🇪 Name',
name: '@:reusableBaseText.name',
openPastExecution: '🇩🇪 Open Past Execution',
retryExecution: '🇩🇪 Retry execution',
retryOf: '🇩🇪 Retry of',
@ -373,6 +383,14 @@ export default {
result: '🇩🇪 Result',
variableSelector: '🇩🇪 Variable Selector',
},
variableSelector: {
variableFilter: '🇩🇪 Variable filter...',
currentNode: '🇩🇪 Current Node',
parameters: '🇩🇪 Parameters',
nodes: '🇩🇪 Nodes',
outputData: '🇩🇪 Output Data',
context: '🇩🇪 Context',
},
fixedCollectionParameter: {
choose: '🇩🇪 Choose...',
currentlyNoItemsExist: '🇩🇪 Currently no items exist',
@ -384,6 +402,7 @@ export default {
},
loading: '🇩🇪 Loading',
sec: '🇩🇪 sec.',
min: '🇩🇪 min.',
},
mainSidebar: {
aboutN8n: '🇩🇪 About n8n',
@ -409,7 +428,7 @@ export default {
help: '🇩🇪 Help',
helpMenuItems: {
documentation: '🇩🇪 Documentation',
forum: '🇩🇪 Forum',
forum: '🇩🇪 Forum @:mainSidebar.helpMenuItems.documentation',
workflows: '🇩🇪 Workflows',
},
importFromFile: '🇩🇪 Import from File',
@ -417,13 +436,13 @@ export default {
new: '🇩🇪 New',
open: '🇩🇪 Open',
prompt: {
cancel: '🇩🇪 Cancel',
cancel: '@:reusableBaseText.cancel',
import: '🇩🇪 Import',
importWorkflowFromUrl: '🇩🇪 Import Workflow from URL',
invalidUrl: '🇩🇪 Invalid URL',
workflowUrl: '🇩🇪 Workflow URL',
},
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
settings: '🇩🇪 Settings',
showError: {
stopExecution: {
@ -584,7 +603,7 @@ export default {
workflowWithIdCouldNotBeFound: '🇩🇪 Workflow with id "{workflowId}" could not be found!',
executesTheWorkflowFromTheStartOrWebhookNode: '🇩🇪 Executes the Workflow from the Start or Webhook Node.',
prompt: {
cancel: '🇩🇪 Cancel',
cancel: '@:reusableBaseText.cancel',
invalidName: '🇩🇪 Invalid Name',
newName: '🇩🇪 New Name',
rename: '🇩🇪 Rename',
@ -739,7 +758,7 @@ export default {
showMessage: {
showDetails: '🇩🇪 Show Details',
ok: '🇩🇪 OK',
cancel: '🇩🇪 Cancel',
cancel: '@:reusableBaseText.cancel',
},
pushConnection: {
showMessage: {
@ -781,7 +800,7 @@ export default {
theNodeContains: '🇩🇪 The node contains {numberOfKb} KB of data.<br />Displaying it could cause problems!<br /><br />If you do decide to display it, avoid the JSON view!',
},
saveButton: {
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
saving: '🇩🇪 Saving',
saved: '🇩🇪 Saved',
},
@ -830,11 +849,11 @@ export default {
noMatchingTagsExist: '🇩🇪 No matching tags exist',
saveChanges: '🇩🇪 Save changes?',
areYouSureYouWantToDeleteThisTag: '🇩🇪 Are you sure you want to delete this tag?',
cancel: '🇩🇪 Cancel',
cancel: '@:reusableBaseText.cancel',
createTag: '🇩🇪 Create tag',
deleteTag: '🇩🇪 Delete tag',
editTag: '🇩🇪 Edit Tag',
name: '🇩🇪 Name',
name: '@:reusableBaseText.name',
usage: '🇩🇪 Usage',
},
tagsTableHeader: {
@ -908,7 +927,7 @@ export default {
message: '🇩🇪 When you switch workflows your current workflow changes will be lost.',
},
created: '🇩🇪 Created',
name: '🇩🇪 Name',
name: '@:reusableBaseText.name',
openWorkflow: '🇩🇪 Open Workflow',
searchWorkflows: '🇩🇪 Search workflows...',
showError: {
@ -950,18 +969,18 @@ export default {
hours: '🇩🇪 hours',
minutes: '🇩🇪 minutes',
noWorkflow: '🇩🇪 - No Workflow -',
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
saveDataErrorExecution: '🇩🇪 Save Data Error Execution',
saveDataErrorExecutionOptions: {
defaultSave: '🇩🇪 Default - ({defaultValue})',
doNotSave: '🇩🇪 Do not save',
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
},
saveDataSuccessExecution: '🇩🇪 Save Data Success Execution',
saveDataSuccessExecutionOptions: {
defaultSave: '🇩🇪 Default - ({defaultValue})',
doNotSave: '🇩🇪 Do not save',
save: '🇩🇪 Save',
save: '@:reusableBaseText.save',
},
saveExecutionProgress: '🇩🇪 Save Execution Progress',
saveExecutionProgressOptions: {

View file

@ -1,4 +1,15 @@
export default {
reusableBaseText: {
cancel: 'Cancel',
save: 'Save',
name: 'Name',
},
reusableDynamicText: {
oauth2: {
clientId: 'Client ID',
clientSecret: 'Client Secret',
},
},
nodeCreator: {
categoryNames: {
coreNodes: 'Core Nodes',
@ -114,7 +125,7 @@ export default {
noProperties: 'No properties',
},
credentialsList: {
name: 'Name',
name: '@:reusableBaseText.name',
type: 'Type',
credentials: 'Credentials',
addNew: 'Add New',
@ -159,11 +170,11 @@ export default {
setValue: 'Set Value',
},
duplicateWorkflowDialog: {
cancel: 'Cancel',
cancel: '@:reusableBaseText.cancel',
chooseOrCreateATag: 'Choose or create a tag',
duplicateWorkflow: 'Duplicate Workflow',
enterWorkflowName: 'Enter workflow name',
save: 'Save',
save: '@:reusableBaseText.save',
showMessage: {
message: 'Please enter a name.',
title: 'Name missing',
@ -286,7 +297,7 @@ export default {
filters: 'Filters',
loadMore: 'Load More',
mode: 'Mode',
name: 'Name',
name: '@:reusableBaseText.name',
openPastExecution: 'Open Past Execution',
retryExecution: 'Retry execution',
retryOf: 'Retry of',
@ -367,6 +378,14 @@ export default {
result: 'Result',
variableSelector: 'Variable Selector',
},
variableSelector: {
variableFilter: 'Variable filter...',
currentNode: 'Current Node',
parameters: 'Parameters',
nodes: 'Nodes',
outputData: 'Output Data',
context: 'Context',
},
fixedCollectionParameter: {
choose: 'Choose...',
currentlyNoItemsExist: 'Currently no items exist',
@ -378,6 +397,7 @@ export default {
},
loading: 'Loading',
sec: 'sec.',
min: 'min.',
},
mainSidebar: {
aboutN8n: 'About n8n',
@ -411,13 +431,13 @@ export default {
new: 'New',
open: 'Open',
prompt: {
cancel: 'Cancel',
cancel: '@:reusableBaseText.cancel',
import: 'Import',
importWorkflowFromUrl: 'Import Workflow from URL',
invalidUrl: 'Invalid URL',
workflowUrl: 'Workflow URL',
},
save: 'Save',
save: '@:reusableBaseText.save',
settings: 'Settings',
showError: {
stopExecution: {
@ -578,7 +598,7 @@ export default {
workflowWithIdCouldNotBeFound: 'Workflow with id "{workflowId}" could not be found!',
executesTheWorkflowFromTheStartOrWebhookNode: 'Executes the Workflow from the Start or Webhook Node.',
prompt: {
cancel: 'Cancel',
cancel: '@:reusableBaseText.cancel',
invalidName: 'Invalid Name',
newName: 'New Name',
rename: 'Rename',
@ -733,7 +753,7 @@ export default {
showMessage: {
showDetails: 'Show Details',
ok: 'OK',
cancel: 'Cancel',
cancel: '@:reusableBaseText.cancel',
},
pushConnection: {
showMessage: {
@ -775,7 +795,7 @@ export default {
theNodeContains: 'The node contains {numberOfKb} KB of data.<br />Displaying it could cause problems!<br /><br />If you do decide to display it, avoid the JSON view!',
},
saveButton: {
save: 'Save',
save: '@:reusableBaseText.save',
saving: 'Saving',
saved: 'Saved',
},
@ -824,11 +844,11 @@ export default {
noMatchingTagsExist: 'No matching tags exist',
saveChanges: 'Save changes?',
areYouSureYouWantToDeleteThisTag: 'Are you sure you want to delete this tag?',
cancel: 'Cancel',
cancel: '@:reusableBaseText.cancel',
createTag: 'Create tag',
deleteTag: 'Delete tag',
editTag: 'Edit Tag',
name: 'Name',
name: '@:reusableBaseText.name',
usage: 'Usage',
},
tagsTableHeader: {
@ -902,7 +922,7 @@ export default {
message: 'When you switch workflows your current workflow changes will be lost.',
},
created: 'Created',
name: 'Name',
name: '@:reusableBaseText.name',
openWorkflow: 'Open Workflow',
searchWorkflows: 'Search workflows...',
showError: {
@ -944,18 +964,18 @@ export default {
hours: 'hours',
minutes: 'minutes',
noWorkflow: '- No Workflow -',
save: 'Save',
save: '@:reusableBaseText.save',
saveDataErrorExecution: 'Save Data Error Execution',
saveDataErrorExecutionOptions: {
defaultSave: 'Default - ({defaultValue})',
doNotSave: 'Do not save',
save: 'Save',
save: '@:reusableBaseText.save',
},
saveDataSuccessExecution: 'Save Data Success Execution',
saveDataSuccessExecutionOptions: {
defaultSave: 'Default - ({defaultValue})',
doNotSave: 'Do not save',
save: 'Save',
save: '@:reusableBaseText.save',
},
saveExecutionProgress: 'Save Execution Progress',
saveExecutionProgressOptions: {

View file

@ -458,8 +458,7 @@ export default mixins(
data.workflow.nodes.forEach((node) => {
if (!this.$store.getters.nodeType(node.type)) {
const name = node.type.replace('n8n-nodes-base.', '');
throw new Error(`The ${name} node is not supported`);
throw new Error(`The ${this.$shortNodeType(node.type)} node is not supported`);
}
});
} catch (error) {

View file

@ -0,0 +1,7 @@
module.exports = {
github: {
header: {
displayName: '🇩🇪 Start',
},
},
};