mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-10 20:37:29 -08:00
dd6a4c956a
* feat: remove vue-fragment (no-changelog)
* feat: partial design-system migration
* feat: migrate info-accordion and info-tip components
* feat: migrate several components to vue 3
* feat: migrated several components
* feat: migrate several components
* feat: migrate several components
* feat: migrate several components
* feat: re-exported all design system components
* fix: fix design for popper components
* fix: editor kind of working, lots of issues to fix
* fix: fix several vue 3 migration issues
* fix: replace @change with @update:modelValue in several places
* fix: fix translation linking
* fix: fix inline-edit input
* fix: fix ndv and dialog design
* fix: update parameter input event bindings
* fix: rename deprecated lifecycle methods
* fix: fix json view mapping
* build: update lock file
* fix(editor): revisit last conflict with master and fix issues
* fix(editor): revisit last conflict with master and fix issues
* fix: fix expression editor bug causing code mirror to no longer be reactive
* fix: fix resource locator bug
* fix: fix vue-agile integration
* fix: remove global import for vue-agile
* fix: replace element-plus buttons with n8n-buttons everywhere
* fix(editor): Fix various element-plus styles (#6571)
* fix(editor): Fix various element-plus styles
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* Remove debugging code
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* Address PR comments
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
---------
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* fix(editor): Fix loading in production mode [Vue 3] (#6578)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* fix(editor): First round of e2e tests fixes with Vue 3 (#6579)
* fix(editor): Fix broken smoke and workflow list e2e tests
* ✔️ Fix failing canvas action tests. Updating some selectors used in credentials and workflow tests
* feat: add vue 3 eslint rules and fix issues
* fix: fix tags-dropdown
* fix: fix white-space issues caused by i18n-t
* fix: rename non-generic click events
* fix: fix search in resources list layout
* fix: fix datatable paginator
* fix: fix popper select caret and dropdown size
* fix: add width to action-dropdown
* fix: fix workflow settings icon not being hidden
* fix: refactor newly added code
* fix: fix merge issue
* fix: fix ndv credentials watcher
* fix: fix workflow saving and grabber notch
* fix: fix nodes list panel transition
* fix: fix node title visibility
* fix: fix data unpinning
* fix: fix value access
* fix: show input panel only if trigger panel enabled or not trigger node
* fix: fix tags dropdown and executions status spcing
* fix(editor): Prevent execution list to load back when leaving the route (#6697)
fix(editor): prevent execution list to load back when leaving the route
* fix: fix drawer visibility
* fix: fix expression toggle padding
* fix: fix expressions editor styling
* chore: prepare for testing
* fix: fix styling for el-button without patching
* test: fix unit tests in design-system
* test: fix most unit tests
* fix: remove import cycle.
* fix: fix personalization modal tests
* fix further resource mapper test adjustments
* fix: fix multiple tests and n8n-route attr duplication
* fix: fix source control tets
* fix: fixed remaining unit tests
* fix: fix workflows and credentials e2e tests
* fix: fix localizeNodeNames
* fix: update ndv e2e tests
* fix: fix popper left placement arrow
* fix: fix 5-ndv e2e tests
* fix: fix 6-code-node e2e tests
* fix(editor): Drop click outside directive from NodeCreator (#6716)
* fix(editor): Drop click outside directive from NodeCreator
* fix(editor): make sure mouseup outside is unbound at least before the component is unmounted
* fix: fix 10-settings-log-streaming e2e tests
* fix: fix node redrawing
* fix: fix tooltip buttons styling
* fix: fix varous e2e suites
* fix: fix 15-scheduler-node e2e suite
* fix: fix route watcher
* fix: fixed param name update and credential edit
* feat: update event names
* refactor: Remove deprecated `$data` (#6576)
Co-authored-by: Alex Grozav <alex@grozav.com>
* fix: fix 17-sharing e2e suite
* fix: fix tags dropdown
* fix: fix tags manager
* fix(editor): move :deep selectors to a separate scoped style block
* fix: fix sticky component and inline text edit
* fix: update e2e tests
* fix: remove button override references
* fix(editor): Adjust spacing in templates for Vue 3 (#6744)
* fix(editor): Adjust spacing in templates
* fix: Undo unneeded change
* fix: Undo unneeded change
* fix(editor): Adjust NDV height for Vue 3 (#6742)
fix(editor): Adjust NDV height
* fix(editor): Restore collapsed sidebar items for Vue 3 (#6743)
fix(editor): Restore collapsed sidebar items
* fix: fix linting issues
* fix: fix design-system deps
* fix: post-merge fixes
* fix: update tests
* fix: increase timeout for executionslist tets
* chore: fix linting issue
* fix: fix 14-mapping e2e tests in ci
* fix: re-enable tests
* fix: fix workflow duplication e2e tests after tags update
* fix(editor): Change component prop to be typed
* fix: fix tags dropdown in duplicate wf modal
* fix: fix focus behaviour in tags selector
* fix: fix tag creation
* fix: fix log streaming e2e race condition
* fix(editor): Fix Vue 3 linting issues (#6748)
* fix(editor): Fix Vue 3 linting issues
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* fix MainSidebar linter issues
* revert pnpm lock
* update pnpm lock file
---------
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Alex Grozav <alex@grozav.com>
* fix(editor): Some css fixes for vue3 branch (#6749)
* ✨ Fixing filter button height
* ✨ Update input modal button position
* ✨ Updating tags styling
* ✨ Fix event logging settings spacing
* 👕 Fixing lint errors
* fix: fix linting issues
* Revert to `// eslint-disable-next-line @typescript-eslint/no-misused-promises` disabling of mixins init
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* fix: fix css issue
* fix(editor): Lint fix
* fix(editor): Fix settings initialisation (#6750)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* fix: fix initial settings loading
* fix: replace realClick with click force
* fix: fix randomly failing mapping e2e tests
* fix(editor): Fix menu item event handling
* fix: fix resource filters dropdown events (#6752)
* fix: fix resource filters dropdown events
* fix: remove teleported:false
* fix: fix event selection event naming (#6753)
* fix: removed console.log (#6754)
* fix: rever await nextTick changes
* fix: redo linting changes
* fix(editor): Redraw node connections if adding more than one node to canvas (#6755)
* fix(editor): Redraw node connections if adding more than one node to canvas
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* Update position before connection two nodes
* Lint fix
---------
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Alex Grozav <alex@grozav.com>
* fix(editor): Fix `ResourceMapper` unit tests (#6758)
* ✔️ Fix matching columns test
* ✔️ Fix multiple matching columns test
* ✔️ Removing `skip` from the last test
* fix: Allow pasting a big workflow (#6760)
* fix: pasting a big workflow
* chore: update comment
* refactor: move try/catch to function
* refactor: move try/catch to function
* fix(editor): Fix modal layer width
* fix: fix position changes
* fix: undo it.only
* fix: make undo/redo multiple steps more verbose
* fix: Fix value survey styles (#6764)
* fix: fix value survey styles
* fix: lint
* Revert "fix: lint"
72869c431f
* fix: lint
* fix(editor): Fix collapsed sub menu
* fix: Fix drawer animation (#6767)
fix: drawer animation
* fix(editor): Fix source control buttons (#6769)
* fix(editor): Fix App loading & auth (#6768)
* fix(editor): Fix App loading & auth
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* Await promises
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
* Fix eslint error
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
---------
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
---------
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Csaba Tuncsik <csaba@n8n.io>
Co-authored-by: OlegIvaniv <me@olegivaniv.com>
Co-authored-by: Milorad FIlipović <milorad@n8n.io>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
918 lines
28 KiB
Vue
918 lines
28 KiB
Vue
<template>
|
|
<Modal
|
|
:name="WORKFLOW_SETTINGS_MODAL_KEY"
|
|
width="65%"
|
|
maxHeight="80%"
|
|
:title="
|
|
$locale.baseText('workflowSettings.settingsFor', {
|
|
interpolate: { workflowName, workflowId },
|
|
})
|
|
"
|
|
:eventBus="modalBus"
|
|
:scrollable="true"
|
|
>
|
|
<template #content>
|
|
<div v-loading="isLoading" class="workflow-settings" data-test-id="workflow-settings-dialog">
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.executionOrder') + ':' }}
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.executionOrder"
|
|
placeholder="Select Execution Order"
|
|
size="medium"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-execution-order"
|
|
>
|
|
<n8n-option
|
|
v-for="option in executionOrderOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.errorWorkflow') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-html="helpTexts.errorWorkflow"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.errorWorkflow"
|
|
placeholder="Select Workflow"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-error-workflow"
|
|
>
|
|
<n8n-option
|
|
v-for="item in workflows"
|
|
:key="item.id"
|
|
:label="item.name"
|
|
:value="item.id"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<div v-if="isSharingEnabled">
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.callerPolicy') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.workflowCallerPolicy"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.callerPolicy"
|
|
:disabled="readOnlyEnv"
|
|
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
|
filterable
|
|
:limit-popper-width="true"
|
|
>
|
|
<n8n-option
|
|
v-for="option of workflowCallerPolicyOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row v-if="workflowSettings.callerPolicy === 'workflowsFromAList'">
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.callerIds') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.workflowCallerIds"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14">
|
|
<n8n-input
|
|
:disabled="readOnlyEnv"
|
|
:placeholder="$locale.baseText('workflowSettings.callerIds.placeholder')"
|
|
type="text"
|
|
v-model="workflowSettings.callerIds"
|
|
@update:modelValue="onCallerIdsInput"
|
|
/>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.timezone') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.timezone"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.timezone"
|
|
placeholder="Select Timezone"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-timezone"
|
|
>
|
|
<n8n-option
|
|
v-for="timezone of timezones"
|
|
:key="timezone.key"
|
|
:label="timezone.value"
|
|
:value="timezone.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.saveDataErrorExecution') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.saveDataErrorExecution"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.saveDataErrorExecution"
|
|
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-save-failed-executions"
|
|
>
|
|
<n8n-option
|
|
v-for="option of saveDataErrorExecutionOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.saveDataSuccessExecution') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.saveDataSuccessExecution"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.saveDataSuccessExecution"
|
|
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-save-success-executions"
|
|
>
|
|
<n8n-option
|
|
v-for="option of saveDataSuccessExecutionOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.saveManualExecutions') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.saveManualExecutions"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.saveManualExecutions"
|
|
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-save-manual-executions"
|
|
>
|
|
<n8n-option
|
|
v-for="option of saveManualOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.saveExecutionProgress') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.saveExecutionProgress"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14" class="ignore-key-press">
|
|
<n8n-select
|
|
v-model="workflowSettings.saveExecutionProgress"
|
|
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
|
filterable
|
|
:disabled="readOnlyEnv"
|
|
:limit-popper-width="true"
|
|
data-test-id="workflow-settings-save-execution-progress"
|
|
>
|
|
<n8n-option
|
|
v-for="option of saveExecutionProgressOptions"
|
|
:key="option.key"
|
|
:label="option.value"
|
|
:value="option.key"
|
|
>
|
|
</n8n-option>
|
|
</n8n-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.timeoutWorkflow') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.executionTimeoutToggle"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="14">
|
|
<div>
|
|
<el-switch
|
|
ref="inputField"
|
|
:disabled="readOnlyEnv"
|
|
:modelValue="workflowSettings.executionTimeout > -1"
|
|
@update:modelValue="toggleTimeout"
|
|
active-color="#13ce66"
|
|
data-test-id="workflow-settings-timeout-workflow"
|
|
></el-switch>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
<div
|
|
v-if="workflowSettings.executionTimeout > -1"
|
|
data-test-id="workflow-settings-timeout-form"
|
|
>
|
|
<el-row>
|
|
<el-col :span="10" class="setting-name">
|
|
{{ $locale.baseText('workflowSettings.timeoutAfter') + ':' }}
|
|
<n8n-tooltip placement="top">
|
|
<template #content>
|
|
<div v-text="helpTexts.executionTimeout"></div>
|
|
</template>
|
|
<font-awesome-icon icon="question-circle" />
|
|
</n8n-tooltip>
|
|
</el-col>
|
|
<el-col :span="4">
|
|
<n8n-input
|
|
:disabled="readOnlyEnv"
|
|
:modelValue="timeoutHMS.hours"
|
|
@update:modelValue="(value) => setTimeout('hours', value)"
|
|
:min="0"
|
|
>
|
|
<template #append>{{ $locale.baseText('workflowSettings.hours') }}</template>
|
|
</n8n-input>
|
|
</el-col>
|
|
<el-col :span="4" class="timeout-input">
|
|
<n8n-input
|
|
:disabled="readOnlyEnv"
|
|
:modelValue="timeoutHMS.minutes"
|
|
:min="0"
|
|
:max="60"
|
|
@update:modelValue="(value) => setTimeout('minutes', value)"
|
|
>
|
|
<template #append>{{ $locale.baseText('workflowSettings.minutes') }}</template>
|
|
</n8n-input>
|
|
</el-col>
|
|
<el-col :span="4" class="timeout-input">
|
|
<n8n-input
|
|
:disabled="readOnlyEnv"
|
|
:modelValue="timeoutHMS.seconds"
|
|
:min="0"
|
|
:max="60"
|
|
@update:modelValue="(value) => setTimeout('seconds', value)"
|
|
>
|
|
<template #append>{{ $locale.baseText('workflowSettings.seconds') }}</template>
|
|
</n8n-input>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template #footer>
|
|
<div class="action-buttons" data-test-id="workflow-settings-save-button">
|
|
<n8n-button
|
|
:disabled="readOnlyEnv"
|
|
:label="$locale.baseText('workflowSettings.save')"
|
|
size="large"
|
|
float="right"
|
|
@click="saveSettings"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</Modal>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent } from 'vue';
|
|
import { mapStores } from 'pinia';
|
|
|
|
import { externalHooks } from '@/mixins/externalHooks';
|
|
import { genericHelpers } from '@/mixins/genericHelpers';
|
|
import { useToast } from '@/composables';
|
|
import type {
|
|
ITimeoutHMS,
|
|
IUser,
|
|
IWorkflowDataUpdate,
|
|
IWorkflowDb,
|
|
IWorkflowSettings,
|
|
IWorkflowShortResponse,
|
|
} from '@/Interface';
|
|
import Modal from '@/components/Modal.vue';
|
|
import {
|
|
EnterpriseEditionFeature,
|
|
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
|
WORKFLOW_SETTINGS_MODAL_KEY,
|
|
} from '@/constants';
|
|
|
|
import type { WorkflowSettings } from 'n8n-workflow';
|
|
import { deepCopy } from 'n8n-workflow';
|
|
import {
|
|
useWorkflowsStore,
|
|
useSettingsStore,
|
|
useRootStore,
|
|
useWorkflowsEEStore,
|
|
useUsersStore,
|
|
} from '@/stores';
|
|
import { createEventBus } from 'n8n-design-system/utils';
|
|
|
|
export default defineComponent({
|
|
name: 'WorkflowSettings',
|
|
mixins: [externalHooks, genericHelpers],
|
|
components: {
|
|
Modal,
|
|
},
|
|
setup() {
|
|
return {
|
|
...useToast(),
|
|
};
|
|
},
|
|
data() {
|
|
return {
|
|
isLoading: true,
|
|
helpTexts: {
|
|
errorWorkflow: this.$locale.baseText('workflowSettings.helpTexts.errorWorkflow'),
|
|
timezone: this.$locale.baseText('workflowSettings.helpTexts.timezone'),
|
|
saveDataErrorExecution: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.saveDataErrorExecution',
|
|
),
|
|
saveDataSuccessExecution: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.saveDataSuccessExecution',
|
|
),
|
|
saveExecutionProgress: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.saveExecutionProgress',
|
|
),
|
|
saveManualExecutions: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.saveManualExecutions',
|
|
),
|
|
executionTimeoutToggle: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.executionTimeoutToggle',
|
|
),
|
|
executionTimeout: this.$locale.baseText('workflowSettings.helpTexts.executionTimeout'),
|
|
workflowCallerPolicy: this.$locale.baseText(
|
|
'workflowSettings.helpTexts.workflowCallerPolicy',
|
|
),
|
|
workflowCallerIds: this.$locale.baseText('workflowSettings.helpTexts.workflowCallerIds'),
|
|
},
|
|
defaultValues: {
|
|
timezone: 'America/New_York',
|
|
saveDataErrorExecution: 'all',
|
|
saveDataSuccessExecution: 'all',
|
|
saveExecutionProgress: false,
|
|
saveManualExecutions: false,
|
|
workflowCallerPolicy: 'workflowsFromSameOwner',
|
|
},
|
|
workflowCallerPolicyOptions: [] as Array<{ key: string; value: string }>,
|
|
saveDataErrorExecutionOptions: [] as Array<{ key: string; value: string }>,
|
|
saveDataSuccessExecutionOptions: [] as Array<{ key: string; value: string }>,
|
|
saveExecutionProgressOptions: [] as Array<{ key: string | boolean; value: string }>,
|
|
saveManualOptions: [] as Array<{ key: string | boolean; value: string }>,
|
|
executionOrderOptions: [
|
|
{ key: 'v0', value: 'v0 (legacy)' },
|
|
{ key: 'v1', value: 'v1 (recommended)' },
|
|
] as Array<{ key: string; value: string }>,
|
|
timezones: [] as Array<{ key: string; value: string }>,
|
|
workflowSettings: {} as IWorkflowSettings,
|
|
workflows: [] as IWorkflowShortResponse[],
|
|
executionOrder: 'v0',
|
|
executionTimeout: 0,
|
|
maxExecutionTimeout: 0,
|
|
timeoutHMS: { hours: 0, minutes: 0, seconds: 0 } as ITimeoutHMS,
|
|
modalBus: createEventBus(),
|
|
WORKFLOW_SETTINGS_MODAL_KEY,
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
...mapStores(
|
|
useRootStore,
|
|
useUsersStore,
|
|
useSettingsStore,
|
|
useWorkflowsStore,
|
|
useWorkflowsEEStore,
|
|
),
|
|
workflowName(): string {
|
|
return this.workflowsStore.workflowName;
|
|
},
|
|
workflowId(): string {
|
|
return this.workflowsStore.workflowId;
|
|
},
|
|
workflow(): IWorkflowDb {
|
|
return this.workflowsStore.workflow;
|
|
},
|
|
currentUser(): IUser | null {
|
|
return this.usersStore.currentUser;
|
|
},
|
|
isSharingEnabled(): boolean {
|
|
return this.settingsStore.isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing);
|
|
},
|
|
workflowOwnerName(): string {
|
|
const fallback = this.$locale.baseText(
|
|
'workflowSettings.callerPolicy.options.workflowsFromSameOwner.fallback',
|
|
);
|
|
|
|
return this.workflowsEEStore.getWorkflowOwnerName(`${this.workflowId}`, fallback);
|
|
},
|
|
},
|
|
async mounted() {
|
|
this.executionTimeout = this.rootStore.executionTimeout;
|
|
this.maxExecutionTimeout = this.rootStore.maxExecutionTimeout;
|
|
|
|
if (!this.workflowId || this.workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) {
|
|
this.showMessage({
|
|
title: 'No workflow active',
|
|
message: 'No workflow active to display settings of.',
|
|
type: 'error',
|
|
duration: 0,
|
|
});
|
|
this.closeDialog();
|
|
return;
|
|
}
|
|
|
|
this.defaultValues.saveDataErrorExecution = this.settingsStore.saveDataErrorExecution;
|
|
this.defaultValues.saveDataSuccessExecution = this.settingsStore.saveDataSuccessExecution;
|
|
this.defaultValues.saveManualExecutions = this.settingsStore.saveManualExecutions;
|
|
this.defaultValues.timezone = this.rootStore.timezone;
|
|
this.defaultValues.workflowCallerPolicy = this.settingsStore.workflowCallerPolicyDefaultOption;
|
|
|
|
this.isLoading = true;
|
|
const promises = [];
|
|
promises.push(this.loadWorkflows());
|
|
promises.push(this.loadSaveDataErrorExecutionOptions());
|
|
promises.push(this.loadSaveDataSuccessExecutionOptions());
|
|
promises.push(this.loadSaveExecutionProgressOptions());
|
|
promises.push(this.loadSaveManualOptions());
|
|
promises.push(this.loadTimezones());
|
|
promises.push(this.loadWorkflowCallerPolicyOptions());
|
|
|
|
try {
|
|
await Promise.all(promises);
|
|
} catch (error) {
|
|
this.showError(
|
|
error,
|
|
'Problem loading settings',
|
|
'The following error occurred loading the data:',
|
|
);
|
|
}
|
|
|
|
const workflowSettings = deepCopy(this.workflowsStore.workflowSettings) as IWorkflowSettings;
|
|
|
|
if (workflowSettings.timezone === undefined) {
|
|
workflowSettings.timezone = 'DEFAULT';
|
|
}
|
|
if (workflowSettings.saveDataErrorExecution === undefined) {
|
|
workflowSettings.saveDataErrorExecution = 'DEFAULT';
|
|
}
|
|
if (workflowSettings.saveDataSuccessExecution === undefined) {
|
|
workflowSettings.saveDataSuccessExecution = 'DEFAULT';
|
|
}
|
|
if (workflowSettings.saveExecutionProgress === undefined) {
|
|
workflowSettings.saveExecutionProgress = 'DEFAULT';
|
|
}
|
|
if (workflowSettings.saveManualExecutions === undefined) {
|
|
workflowSettings.saveManualExecutions = this.defaultValues.saveManualExecutions;
|
|
}
|
|
if (workflowSettings.callerPolicy === undefined) {
|
|
workflowSettings.callerPolicy = this.defaultValues
|
|
.workflowCallerPolicy as WorkflowSettings.CallerPolicy;
|
|
}
|
|
if (workflowSettings.executionTimeout === undefined) {
|
|
workflowSettings.executionTimeout = this.rootStore.executionTimeout;
|
|
}
|
|
if (workflowSettings.maxExecutionTimeout === undefined) {
|
|
workflowSettings.maxExecutionTimeout = this.rootStore.maxExecutionTimeout;
|
|
}
|
|
if (workflowSettings.executionOrder === undefined) {
|
|
workflowSettings.executionOrder = 'v0';
|
|
}
|
|
|
|
this.workflowSettings = workflowSettings;
|
|
this.timeoutHMS = this.convertToHMS(workflowSettings.executionTimeout);
|
|
this.isLoading = false;
|
|
|
|
void this.$externalHooks().run('workflowSettings.dialogVisibleChanged', {
|
|
dialogVisible: true,
|
|
});
|
|
this.$telemetry.track('User opened workflow settings', {
|
|
workflow_id: this.workflowsStore.workflowId,
|
|
});
|
|
},
|
|
methods: {
|
|
onCallerIdsInput(str: string) {
|
|
this.workflowSettings.callerIds = /^[0-9,\s]+$/.test(str)
|
|
? str
|
|
: str.replace(/[^0-9,\s]/g, '');
|
|
},
|
|
closeDialog() {
|
|
this.modalBus.emit('close');
|
|
void this.$externalHooks().run('workflowSettings.dialogVisibleChanged', {
|
|
dialogVisible: false,
|
|
});
|
|
},
|
|
setTimeout(key: string, value: string) {
|
|
const time = value ? parseInt(value, 10) : 0;
|
|
|
|
this.timeoutHMS = {
|
|
...this.timeoutHMS,
|
|
[key]: time,
|
|
};
|
|
},
|
|
async loadWorkflowCallerPolicyOptions() {
|
|
const currentUserIsOwner = this.workflow.ownedBy?.id === this.currentUser?.id;
|
|
|
|
this.workflowCallerPolicyOptions = [
|
|
{
|
|
key: 'none',
|
|
value: this.$locale.baseText('workflowSettings.callerPolicy.options.none'),
|
|
},
|
|
{
|
|
key: 'workflowsFromSameOwner',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.callerPolicy.options.workflowsFromSameOwner',
|
|
{
|
|
interpolate: {
|
|
owner: currentUserIsOwner
|
|
? this.$locale.baseText(
|
|
'workflowSettings.callerPolicy.options.workflowsFromSameOwner.owner',
|
|
)
|
|
: this.workflowOwnerName,
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
key: 'workflowsFromAList',
|
|
value: this.$locale.baseText('workflowSettings.callerPolicy.options.workflowsFromAList'),
|
|
},
|
|
{
|
|
key: 'any',
|
|
value: this.$locale.baseText('workflowSettings.callerPolicy.options.any'),
|
|
},
|
|
];
|
|
},
|
|
async loadSaveDataErrorExecutionOptions() {
|
|
this.saveDataErrorExecutionOptions.length = 0;
|
|
this.saveDataErrorExecutionOptions.push.apply(
|
|
// eslint-disable-line no-useless-call
|
|
this.saveDataErrorExecutionOptions,
|
|
[
|
|
{
|
|
key: 'DEFAULT',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.saveDataErrorExecutionOptions.defaultSave',
|
|
{
|
|
interpolate: {
|
|
defaultValue:
|
|
this.defaultValues.saveDataErrorExecution === 'all'
|
|
? this.$locale.baseText('workflowSettings.saveDataErrorExecutionOptions.save')
|
|
: this.$locale.baseText(
|
|
'workflowSettings.saveDataErrorExecutionOptions.doNotSave',
|
|
),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
key: 'all',
|
|
value: this.$locale.baseText('workflowSettings.saveDataErrorExecutionOptions.save'),
|
|
},
|
|
{
|
|
key: 'none',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.saveDataErrorExecutionOptions.doNotSave',
|
|
),
|
|
},
|
|
],
|
|
);
|
|
},
|
|
async loadSaveDataSuccessExecutionOptions() {
|
|
this.saveDataSuccessExecutionOptions.length = 0;
|
|
this.saveDataSuccessExecutionOptions.push.apply(
|
|
// eslint-disable-line no-useless-call
|
|
this.saveDataSuccessExecutionOptions,
|
|
[
|
|
{
|
|
key: 'DEFAULT',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.saveDataSuccessExecutionOptions.defaultSave',
|
|
{
|
|
interpolate: {
|
|
defaultValue:
|
|
this.defaultValues.saveDataSuccessExecution === 'all'
|
|
? this.$locale.baseText(
|
|
'workflowSettings.saveDataSuccessExecutionOptions.save',
|
|
)
|
|
: this.$locale.baseText(
|
|
'workflowSettings.saveDataSuccessExecutionOptions.doNotSave',
|
|
),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
key: 'all',
|
|
value: this.$locale.baseText('workflowSettings.saveDataSuccessExecutionOptions.save'),
|
|
},
|
|
{
|
|
key: 'none',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.saveDataSuccessExecutionOptions.doNotSave',
|
|
),
|
|
},
|
|
],
|
|
);
|
|
},
|
|
async loadSaveExecutionProgressOptions() {
|
|
this.saveExecutionProgressOptions.length = 0;
|
|
this.saveExecutionProgressOptions.push.apply(
|
|
// eslint-disable-line no-useless-call
|
|
this.saveExecutionProgressOptions,
|
|
[
|
|
{
|
|
key: 'DEFAULT',
|
|
value: this.$locale.baseText(
|
|
'workflowSettings.saveExecutionProgressOptions.defaultSave',
|
|
{
|
|
interpolate: {
|
|
defaultValue: this.defaultValues.saveExecutionProgress
|
|
? this.$locale.baseText('workflowSettings.saveExecutionProgressOptions.yes')
|
|
: this.$locale.baseText('workflowSettings.saveExecutionProgressOptions.no'),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
key: true,
|
|
value: this.$locale.baseText('workflowSettings.saveExecutionProgressOptions.yes'),
|
|
},
|
|
{
|
|
key: false,
|
|
value: this.$locale.baseText('workflowSettings.saveExecutionProgressOptions.no'),
|
|
},
|
|
],
|
|
);
|
|
},
|
|
async loadSaveManualOptions() {
|
|
this.saveManualOptions.length = 0;
|
|
this.saveManualOptions.push({
|
|
key: 'DEFAULT',
|
|
value: this.$locale.baseText('workflowSettings.saveManualOptions.defaultSave', {
|
|
interpolate: {
|
|
defaultValue: this.defaultValues.saveManualExecutions
|
|
? this.$locale.baseText('workflowSettings.saveManualOptions.yes')
|
|
: this.$locale.baseText('workflowSettings.saveManualOptions.no'),
|
|
},
|
|
}),
|
|
});
|
|
this.saveManualOptions.push({
|
|
key: true,
|
|
value: this.$locale.baseText('workflowSettings.saveManualOptions.yes'),
|
|
});
|
|
this.saveManualOptions.push({
|
|
key: false,
|
|
value: this.$locale.baseText('workflowSettings.saveManualOptions.no'),
|
|
});
|
|
},
|
|
|
|
async loadTimezones() {
|
|
if (this.timezones.length !== 0) {
|
|
// Data got already loaded
|
|
return;
|
|
}
|
|
|
|
const timezones = await this.settingsStore.getTimezones();
|
|
|
|
let defaultTimezoneValue = timezones[this.defaultValues.timezone] as string | undefined;
|
|
if (defaultTimezoneValue === undefined) {
|
|
defaultTimezoneValue = this.$locale.baseText('workflowSettings.defaultTimezoneNotValid');
|
|
}
|
|
|
|
this.timezones.push({
|
|
key: 'DEFAULT',
|
|
value: this.$locale.baseText('workflowSettings.defaultTimezone', {
|
|
interpolate: { defaultTimezoneValue },
|
|
}),
|
|
});
|
|
for (const timezone of Object.keys(timezones)) {
|
|
this.timezones.push({
|
|
key: timezone,
|
|
value: timezones[timezone] as string,
|
|
});
|
|
}
|
|
},
|
|
async loadWorkflows() {
|
|
const workflows = (await this.workflowsStore.fetchAllWorkflows()) as IWorkflowShortResponse[];
|
|
workflows.sort((a, b) => {
|
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
return -1;
|
|
}
|
|
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
|
|
workflows.unshift({
|
|
id: undefined as unknown as string,
|
|
name: this.$locale.baseText('workflowSettings.noWorkflow'),
|
|
} as IWorkflowShortResponse);
|
|
|
|
this.workflows = workflows;
|
|
},
|
|
async saveSettings() {
|
|
// Set that the active state should be changed
|
|
const data: IWorkflowDataUpdate = {
|
|
settings: this.workflowSettings,
|
|
};
|
|
|
|
// Convert hours, minutes, seconds into seconds for the workflow timeout
|
|
const { hours, minutes, seconds } = this.timeoutHMS;
|
|
data.settings!.executionTimeout =
|
|
data.settings!.executionTimeout !== -1 ? hours * 3600 + minutes * 60 + seconds : -1;
|
|
|
|
if (data.settings!.executionTimeout === 0) {
|
|
this.showError(
|
|
new Error(this.$locale.baseText('workflowSettings.showError.saveSettings1.errorMessage')),
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings1.title'),
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings1.message') + ':',
|
|
);
|
|
return;
|
|
}
|
|
|
|
// @ts-ignore
|
|
if (data.settings!.executionTimeout > this.workflowSettings.maxExecutionTimeout) {
|
|
const { hours, minutes, seconds } = this.convertToHMS(
|
|
this.workflowSettings.maxExecutionTimeout as number,
|
|
);
|
|
this.showError(
|
|
new Error(
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings2.errorMessage', {
|
|
interpolate: {
|
|
hours: hours.toString(),
|
|
minutes: minutes.toString(),
|
|
seconds: seconds.toString(),
|
|
},
|
|
}),
|
|
),
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings2.title'),
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings2.message') + ':',
|
|
);
|
|
return;
|
|
}
|
|
delete data.settings!.maxExecutionTimeout;
|
|
|
|
this.isLoading = true;
|
|
data.versionId = this.workflowsStore.workflowVersionId;
|
|
|
|
try {
|
|
const workflow = await this.workflowsStore.updateWorkflow(this.$route.params.name, data);
|
|
this.workflowsStore.setWorkflowVersionId(workflow.versionId);
|
|
} catch (error) {
|
|
this.showError(
|
|
error,
|
|
this.$locale.baseText('workflowSettings.showError.saveSettings3.title'),
|
|
);
|
|
this.isLoading = false;
|
|
return;
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
}
|
|
|
|
const oldSettings = deepCopy(this.workflowsStore.workflowSettings);
|
|
|
|
this.workflowsStore.setWorkflowSettings(localWorkflowSettings);
|
|
|
|
this.isLoading = false;
|
|
|
|
this.showMessage({
|
|
title: this.$locale.baseText('workflowSettings.showMessage.saveSettings.title'),
|
|
type: 'success',
|
|
});
|
|
|
|
this.closeDialog();
|
|
|
|
void this.$externalHooks().run('workflowSettings.saveSettings', { oldSettings });
|
|
this.$telemetry.track('User updated workflow settings', {
|
|
workflow_id: this.workflowsStore.workflowId,
|
|
});
|
|
},
|
|
toggleTimeout() {
|
|
this.workflowSettings.executionTimeout =
|
|
this.workflowSettings.executionTimeout === -1 ? 0 : -1;
|
|
},
|
|
convertToHMS(num: number): ITimeoutHMS {
|
|
if (num > 0) {
|
|
const hours = Math.floor(num / 3600);
|
|
const remainder = num % 3600;
|
|
const minutes = Math.floor(remainder / 60);
|
|
const seconds = remainder % 60;
|
|
return { hours, minutes, seconds };
|
|
}
|
|
return { hours: 0, minutes: 0, seconds: 0 };
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.workflow-settings {
|
|
font-size: var(--font-size-s);
|
|
.el-row {
|
|
padding: 0.25em 0;
|
|
}
|
|
}
|
|
|
|
.setting-name {
|
|
line-height: 32px;
|
|
|
|
svg {
|
|
display: inline-flex;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
&:hover {
|
|
svg {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
.timeout-input {
|
|
margin-left: 5px;
|
|
}
|
|
</style>
|