Make it possible to define if workflow executions should be

saved or not
This commit is contained in:
Jan Oberhauser
2019-07-10 20:53:13 +02:00
parent e00bc83f1b
commit a17a376d13
8 changed files with 168 additions and 11 deletions

View File

@@ -22,6 +22,15 @@ module.exports = {
}, },
executions: { executions: {
// If a workflow executes all the data gets saved by default. This
// could be a problem when a workflow gets executed a lot and processes
// a lot of data. To not write the database full it is possible to
// not save the execution at all.
// Depending on if the execution did succeed or error a different
// save behaviour can be set.
saveDataErrorExecution: 'all', // Available options: all, none
saveDataSuccessExecution: 'all', // Available options: all, none
// If the executions of workflows which got started via the editor // If the executions of workflows which got started via the editor
// should be saved. By default they will not be saved as this runs // should be saved. By default they will not be saved as this runs
// are normally only for testing and debugging. This setting can // are normally only for testing and debugging. This setting can

View File

@@ -189,6 +189,8 @@ export interface IN8nConfigNodes {
export interface IN8nUISettings { export interface IN8nUISettings {
endpointWebhook: string; endpointWebhook: string;
endpointWebhookTest: string; endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean; saveManualExecutions: boolean;
timezone: string; timezone: string;
urlBaseWebhook: string; urlBaseWebhook: string;

View File

@@ -73,6 +73,8 @@ class App {
testWebhooks: TestWebhooks.TestWebhooks; testWebhooks: TestWebhooks.TestWebhooks;
endpointWebhook: string; endpointWebhook: string;
endpointWebhookTest: string; endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean; saveManualExecutions: boolean;
timezone: string; timezone: string;
activeExecutionsInstance: ActiveExecutions.ActiveExecutions; activeExecutionsInstance: ActiveExecutions.ActiveExecutions;
@@ -83,6 +85,8 @@ class App {
this.endpointWebhook = config.get('urls.endpointWebhook') as string; this.endpointWebhook = config.get('urls.endpointWebhook') as string;
this.endpointWebhookTest = config.get('urls.endpointWebhookTest') as string; this.endpointWebhookTest = config.get('urls.endpointWebhookTest') as string;
this.saveDataErrorExecution = config.get('executions.saveDataErrorExecution') as string;
this.saveDataSuccessExecution = config.get('executions.saveDataSuccessExecution') as string;
this.saveManualExecutions = config.get('executions.saveManualExecutions') as boolean; this.saveManualExecutions = config.get('executions.saveManualExecutions') as boolean;
this.timezone = config.get('timezone') as string; this.timezone = config.get('timezone') as string;
@@ -271,6 +275,14 @@ class App {
// Do not save the default timezone // Do not save the default timezone
delete newWorkflowData.settings.timezone; delete newWorkflowData.settings.timezone;
} }
if (newWorkflowData.settings.saveDataErrorExecution === 'DEFAULT') {
// Do not save when default got set
delete newWorkflowData.settings.saveDataErrorExecution;
}
if (newWorkflowData.settings.saveDataSuccessExecution === 'DEFAULT') {
// Do not save when default got set
delete newWorkflowData.settings.saveDataSuccessExecution;
}
if (newWorkflowData.settings.saveManualExecutions === 'DEFAULT') { if (newWorkflowData.settings.saveManualExecutions === 'DEFAULT') {
// Do not save when default got set // Do not save when default got set
delete newWorkflowData.settings.saveManualExecutions; delete newWorkflowData.settings.saveManualExecutions;
@@ -900,6 +912,8 @@ class App {
return { return {
endpointWebhook: this.endpointWebhook, endpointWebhook: this.endpointWebhook,
endpointWebhookTest: this.endpointWebhookTest, endpointWebhookTest: this.endpointWebhookTest,
saveDataErrorExecution: this.saveDataErrorExecution,
saveDataSuccessExecution: this.saveDataSuccessExecution,
saveManualExecutions: this.saveManualExecutions, saveManualExecutions: this.saveManualExecutions,
timezone: this.timezone, timezone: this.timezone,
urlBaseWebhook: WebhookHelpers.getWebhookBaseUrl(), urlBaseWebhook: WebhookHelpers.getWebhookBaseUrl(),

View File

@@ -132,18 +132,26 @@ const hooks = (mode: WorkflowExecuteMode, workflowData: IWorkflowBase, workflowI
await workflowSavePromise; await workflowSavePromise;
} }
// For now do not save manual executions
// TODO: Later that should be configurable. Think about what to do
// with the workflow.id when not saved yet or currently differes from saved version (save diff?!?!)
executeErrorWorkflow(workflowData, fullRunData, mode); executeErrorWorkflow(workflowData, fullRunData, mode);
return; return;
} }
// TODO: Should maybe have different log-modes like // Check config to know if execution should be saved or not
// to save all data, only first input, only last node output, .... let saveDataErrorExecution = config.get('executions.saveDataErrorExecution') as string;
// or depending on success to only save all on error to be let saveDataSuccessExecution = config.get('executions.saveDataSuccessExecution') as string;
// able to start it again where it ended (but would then also have to save active data) if (workflowInstance.settings !== undefined) {
saveDataErrorExecution = (workflowInstance.settings.saveDataErrorExecution as string) || saveDataErrorExecution;
saveDataSuccessExecution = (workflowInstance.settings.saveDataSuccessExecution as string) || saveDataSuccessExecution;
}
const workflowDidSucceed = !fullRunData.data.resultData.error;
if (workflowDidSucceed === true && saveDataSuccessExecution === 'none' ||
workflowDidSucceed === false && saveDataErrorExecution === 'none'
) {
executeErrorWorkflow(workflowData, fullRunData, mode);
return;
}
const fullExecutionData: IExecutionDb = { const fullExecutionData: IExecutionDb = {
data: fullRunData.data, data: fullRunData.data,
mode: fullRunData.mode, mode: fullRunData.mode,

View File

@@ -358,6 +358,8 @@ export interface IPushDataTestWebhook {
export interface IN8nUISettings { export interface IN8nUISettings {
endpointWebhook: string; endpointWebhook: string;
endpointWebhookTest: string; endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean; saveManualExecutions: boolean;
timezone: string; timezone: string;
urlBaseWebhook: string; urlBaseWebhook: string;
@@ -365,6 +367,8 @@ export interface IN8nUISettings {
export interface IWorkflowSettings extends IWorkflowSettingsWorkflow { export interface IWorkflowSettings extends IWorkflowSettingsWorkflow {
errorWorkflow?: string; errorWorkflow?: string;
saveDataErrorExecution?: string;
saveDataSuccessExecution?: string;
saveManualExecutions?: boolean; saveManualExecutions?: boolean;
timezone?: string; timezone?: string;
} }

View File

@@ -40,6 +40,44 @@
</el-select> </el-select>
</el-col> </el-col>
</el-row> </el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Error Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<div slot="content" v-html="helpTexts.saveDataErrorExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataErrorExecution" placeholder="Select Option" size="small" filterable>
<el-option
v-for="option of saveDataErrorExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Success Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<div slot="content" v-html="helpTexts.saveDataSuccessExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataSuccessExecution" placeholder="Select Option" size="small" filterable>
<el-option
v-for="option of saveDataSuccessExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="10" class="setting-name"> <el-col :span="10" class="setting-name">
Save Manual Executions: Save Manual Executions:
@@ -77,8 +115,9 @@ import { restApi } from '@/components/mixins/restApi';
import { genericHelpers } from '@/components/mixins/genericHelpers'; import { genericHelpers } from '@/components/mixins/genericHelpers';
import { showMessage } from '@/components/mixins/showMessage'; import { showMessage } from '@/components/mixins/showMessage';
import { import {
IWorkflowShortResponse,
IWorkflowDataUpdate, IWorkflowDataUpdate,
IWorkflowSettings,
IWorkflowShortResponse,
} from '@/Interface'; } from '@/Interface';
import mixins from 'vue-typed-mixins'; import mixins from 'vue-typed-mixins';
@@ -98,12 +137,18 @@ export default mixins(
helpTexts: { helpTexts: {
errorWorkflow: 'The workflow to run in case the current one fails.<br />To function correctly that workflow has to contain an "Error Trigger" node!', errorWorkflow: 'The workflow to run in case the current one fails.<br />To function correctly that workflow has to contain an "Error Trigger" node!',
timezone: 'The timezone in which the workflow should run. Gets for example used by "Cron" node.', timezone: 'The timezone in which the workflow should run. Gets for example used by "Cron" node.',
saveDataErrorExecution: 'If data data of executions should be saved in case they failed.',
saveDataSuccessExecution: 'If data data of executions should be saved in case they succeed.',
saveManualExecutions: 'If data data of executions should be saved when started manually from the editor.', saveManualExecutions: 'If data data of executions should be saved when started manually from the editor.',
}, },
defaultValues: { defaultValues: {
timezone: 'America/New_York', timezone: 'America/New_York',
saveDataErrorExecution: 'all',
saveDataSuccessExecution: 'all',
saveManualExecutions: false, saveManualExecutions: false,
}, },
saveDataErrorExecutionOptions: [] as Array<{ key: string, value: string }>,
saveDataSuccessExecutionOptions: [] as Array<{ key: string, value: string }>,
saveManualOptions: [] as Array<{ key: string | boolean, value: string }>, saveManualOptions: [] as Array<{ key: string | boolean, value: string }>,
timezones: [] as Array<{ key: string, value: string }>, timezones: [] as Array<{ key: string, value: string }>,
workflowSettings: {}, workflowSettings: {},
@@ -124,11 +169,49 @@ export default mixins(
this.$emit('closeDialog'); this.$emit('closeDialog');
return false; return false;
}, },
async loadSaveDataErrorExecutionOptions () {
this.saveDataErrorExecutionOptions.length = 0;
this.saveDataErrorExecutionOptions.push.apply(
this.saveDataErrorExecutionOptions, [
{
key: 'DEFAULT',
value: 'Default - ' + (this.defaultValues.saveDataErrorExecution === 'all' ? 'Save' : 'Do not save'),
},
{
key: 'all',
value: 'Save',
},
{
key: 'none',
value: 'Do not save',
}
]
);
},
async loadSaveDataSuccessExecutionOptions () {
this.saveDataSuccessExecutionOptions.length = 0;
this.saveDataSuccessExecutionOptions.push.apply(
this.saveDataSuccessExecutionOptions, [
{
key: 'DEFAULT',
value: 'Default - ' + (this.defaultValues.saveDataSuccessExecution === 'all' ? 'Save' : 'Do not save'),
},
{
key: 'all',
value: 'Save',
},
{
key: 'none',
value: 'Do not save',
}
]
);
},
async loadSaveManualOptions () { async loadSaveManualOptions () {
this.saveManualOptions.length = 0; this.saveManualOptions.length = 0;
this.saveManualOptions.push({ this.saveManualOptions.push({
key: 'DEFAULT', key: 'DEFAULT',
value: 'Use default - ' + (this.defaultValues.saveManualExecutions === true ? 'Yes' : 'No'), value: 'Default - ' + (this.defaultValues.saveManualExecutions === true ? 'Yes' : 'No'),
}); });
this.saveManualOptions.push({ this.saveManualOptions.push({
key: true, key: true,
@@ -139,6 +222,7 @@ export default mixins(
value: 'No', value: 'No',
}); });
}, },
async loadTimezones () { async loadTimezones () {
if (this.timezones.length !== 0) { if (this.timezones.length !== 0) {
// Data got already loaded // Data got already loaded
@@ -196,12 +280,16 @@ export default mixins(
return; return;
} }
this.defaultValues.saveDataErrorExecution = this.$store.getters.saveDataErrorExecution;
this.defaultValues.saveDataSuccessExecution = this.$store.getters.saveDataSuccessExecution;
this.defaultValues.saveManualExecutions = this.$store.getters.saveManualExecutions; this.defaultValues.saveManualExecutions = this.$store.getters.saveManualExecutions;
this.defaultValues.timezone = this.$store.getters.timezone; this.defaultValues.timezone = this.$store.getters.timezone;
this.isLoading = true; this.isLoading = true;
const promises = []; const promises = [];
promises.push(this.loadWorkflows()); promises.push(this.loadWorkflows());
promises.push(this.loadSaveDataErrorExecutionOptions());
promises.push(this.loadSaveDataSuccessExecutionOptions());
promises.push(this.loadSaveManualOptions()); promises.push(this.loadSaveManualOptions());
promises.push(this.loadTimezones()); promises.push(this.loadTimezones());
@@ -216,6 +304,12 @@ export default mixins(
if (workflowSettings.timezone === undefined) { if (workflowSettings.timezone === undefined) {
workflowSettings.timezone = 'DEFAULT'; workflowSettings.timezone = 'DEFAULT';
} }
if (workflowSettings.saveDataErrorExecution === undefined) {
workflowSettings.saveDataErrorExecution = 'DEFAULT';
}
if (workflowSettings.saveDataSuccessExecution === undefined) {
workflowSettings.saveDataSuccessExecution = 'DEFAULT';
}
if (workflowSettings.saveManualExecutions === undefined) { if (workflowSettings.saveManualExecutions === undefined) {
workflowSettings.saveManualExecutions = 'DEFAULT'; workflowSettings.saveManualExecutions = 'DEFAULT';
} }
@@ -238,7 +332,16 @@ export default mixins(
this.isLoading = false; this.isLoading = false;
return; return;
} }
this.$store.commit('setWorkflowSettings', this.workflowSettings);
// Get the settings without the defaults set for local workflow settings
const localWorkflowSettings: IWorkflowSettings = {};
for (const key of Object.keys(this.workflowSettings)) {
if (this.workflowSettings[key] !== 'DEFAULT') {
localWorkflowSettings[key] = this.workflowSettings[key];
}
}
this.$store.commit('setWorkflowSettings', localWorkflowSettings);
this.isLoading = false; this.isLoading = false;

View File

@@ -46,6 +46,8 @@ export const store = new Vuex.Store({
executingNode: '' as string | null, executingNode: '' as string | null,
executionWaitingForWebhook: false, executionWaitingForWebhook: false,
pushConnectionActive: false, pushConnectionActive: false,
saveDataErrorExecution: 'all',
saveDataSuccessExecution: 'all',
saveManualExecutions: false, saveManualExecutions: false,
timezone: 'America/New_York', timezone: 'America/New_York',
workflowExecutionData: null as IExecutionResponse | null, workflowExecutionData: null as IExecutionResponse | null,
@@ -458,6 +460,12 @@ export const store = new Vuex.Store({
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest); Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
}, },
setSaveDataErrorExecution(state, newValue: string) {
Vue.set(state, 'saveDataErrorExecution', newValue);
},
setSaveDataSuccessExecution(state, newValue: string) {
Vue.set(state, 'saveDataSuccessExecution', newValue);
},
setSaveManualExecutions (state, saveManualExecutions: boolean) { setSaveManualExecutions (state, saveManualExecutions: boolean) {
Vue.set(state, 'saveManualExecutions', saveManualExecutions); Vue.set(state, 'saveManualExecutions', saveManualExecutions);
}, },
@@ -551,6 +559,12 @@ export const store = new Vuex.Store({
return `${state.urlBaseWebhook}${state.endpointWebhookTest}`; return `${state.urlBaseWebhook}${state.endpointWebhookTest}`;
}, },
saveDataErrorExecution: (state): string => {
return state.saveDataErrorExecution;
},
saveDataSuccessExecution: (state): string => {
return state.saveDataSuccessExecution;
},
saveManualExecutions: (state): boolean => { saveManualExecutions: (state): boolean => {
return state.saveManualExecutions; return state.saveManualExecutions;
}, },

View File

@@ -1674,9 +1674,12 @@ export default mixins(
}, },
async loadSettings (): Promise<void> { async loadSettings (): Promise<void> {
const settings = await this.restApi().getSettings() as IN8nUISettings; const settings = await this.restApi().getSettings() as IN8nUISettings;
this.$store.commit('setUrlBaseWebhook', settings.urlBaseWebhook); this.$store.commit('setUrlBaseWebhook', settings.urlBaseWebhook);
this.$store.commit('setEndpointWebhook', settings.endpointWebhook); this.$store.commit('setEndpointWebhook', settings.endpointWebhook);
this.$store.commit('setEndpointWebhookTest', settings.endpointWebhookTest); this.$store.commit('setEndpointWebhookTest', settings.endpointWebhookTest);
this.$store.commit('setSaveDataErrorExecution', settings.saveDataErrorExecution);
this.$store.commit('setSaveDataSuccessExecution', settings.saveDataSuccessExecution);
this.$store.commit('setSaveManualExecutions', settings.saveManualExecutions); this.$store.commit('setSaveManualExecutions', settings.saveManualExecutions);
this.$store.commit('setTimezone', settings.timezone); this.$store.commit('setTimezone', settings.timezone);
}, },