refactor(editor): Apply Prettier (no-changelog) (#4920)

*  Adjust `format` script

* 🔥 Remove exemption for `editor-ui`

* 🎨 Prettify

* 👕 Fix lint
This commit is contained in:
Iván Ovejero
2022-12-14 10:04:10 +01:00
committed by GitHub
parent bcde07e032
commit 5ca2148c7e
284 changed files with 19247 additions and 15540 deletions

View File

@@ -10,23 +10,48 @@
>
<router-link
:class="$style.executionLink"
:to="{ name: VIEWS.EXECUTION_PREVIEW, params: { workflowId: currentWorkflow, executionId: execution.id }}"
:to="{
name: VIEWS.EXECUTION_PREVIEW,
params: { workflowId: currentWorkflow, executionId: execution.id },
}"
>
<div :class="$style.description">
<n8n-text color="text-dark" :bold="true" size="medium">{{ executionUIDetails.startTime }}</n8n-text>
<n8n-text color="text-dark" :bold="true" size="medium">{{
executionUIDetails.startTime
}}</n8n-text>
<div :class="$style.executionStatus">
<n8n-spinner v-if="executionUIDetails.name === 'running'" size="small" :class="[$style.spinner, 'mr-4xs']"/>
<n8n-text :class="$style.statusLabel" size="small">{{ executionUIDetails.label }}</n8n-text>
<n8n-text v-if="executionUIDetails.name === 'running'" :color="isActive? 'text-dark' : 'text-base'" size="small">
<n8n-spinner
v-if="executionUIDetails.name === 'running'"
size="small"
:class="[$style.spinner, 'mr-4xs']"
/>
<n8n-text :class="$style.statusLabel" size="small">{{
executionUIDetails.label
}}</n8n-text>
<n8n-text
v-if="executionUIDetails.name === 'running'"
:color="isActive ? 'text-dark' : 'text-base'"
size="small"
>
{{ $locale.baseText('executionDetails.runningTimeRunning') }}
<execution-time :start-time="execution.startedAt"/>
<execution-time :start-time="execution.startedAt" />
</n8n-text>
<n8n-text v-else-if="executionUIDetails.name !== 'waiting' && executionUIDetails.name !== 'unknown'" :color="isActive? 'text-dark' : 'text-base'" size="small">
{{ $locale.baseText('executionDetails.runningTimeFinished', { interpolate: { time: executionUIDetails.runningTime } }) }}
<n8n-text
v-else-if="
executionUIDetails.name !== 'waiting' && executionUIDetails.name !== 'unknown'
"
:color="isActive ? 'text-dark' : 'text-base'"
size="small"
>
{{
$locale.baseText('executionDetails.runningTimeFinished', {
interpolate: { time: executionUIDetails.runningTime },
})
}}
</n8n-text>
</div>
<div v-if="execution.mode === 'retry'">
<n8n-text :color="isActive? 'text-dark' : 'text-base'" size="small">
<n8n-text :color="isActive ? 'text-dark' : 'text-base'" size="small">
{{ $locale.baseText('executionDetails.retry') }} #{{ execution.retryOf }}
</n8n-text>
</div>
@@ -44,7 +69,7 @@
:class="[$style.icon, $style.manual]"
:title="$locale.baseText('executionsList.manual')"
icon="flask"
/>
/>
</div>
</router-link>
</div>
@@ -59,11 +84,7 @@ import { showMessage } from '@/mixins/showMessage';
import { restApi } from '@/mixins/restApi';
import ExecutionTime from '@/components/ExecutionTime.vue';
export default mixins(
executionHelpers,
showMessage,
restApi,
).extend({
export default mixins(executionHelpers, showMessage, restApi).extend({
name: 'execution-card',
components: {
ExecutionTime,
@@ -86,8 +107,14 @@ export default mixins(
computed: {
retryExecutionActions(): object[] {
return [
{ id: 'current-workflow', label: this.$locale.baseText('executionsList.retryWithCurrentlySavedWorkflow') },
{ id: 'original-workflow', label: this.$locale.baseText('executionsList.retryWithOriginalWorkflow') },
{
id: 'current-workflow',
label: this.$locale.baseText('executionsList.retryWithCurrentlySavedWorkflow'),
},
{
id: 'original-workflow',
label: this.$locale.baseText('executionsList.retryWithOriginalWorkflow'),
},
];
},
executionUIDetails(): IExecutionUIData {
@@ -119,9 +146,12 @@ export default mixins(
}
}
& + &.active { padding-top: var(--spacing-2xs); }
& + &.active {
padding-top: var(--spacing-2xs);
}
&:hover, &.active {
&:hover,
&.active {
.executionLink {
background-color: var(--color-foreground-base);
}
@@ -132,34 +162,47 @@ export default mixins(
position: relative;
top: 1px;
}
&, & .executionLink {
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) hsl(var(--color-warning-h), 94%, 80%);
}
.statusLabel, .spinner { color: var(--color-warning); }
.statusLabel,
.spinner {
color: var(--color-warning);
}
}
&.success {
&, & .executionLink {
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) hsl(var(--color-success-h), 60%, 70%);
}
}
&.waiting {
&, & .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) hsl(var(--color-secondary-h), 94%, 80%);
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base)
hsl(var(--color-secondary-h), 94%, 80%);
}
.statusLabel {
color: var(--color-secondary);
}
.statusLabel { color: var(--color-secondary); }
}
&.error {
&, & .executionLink {
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) hsl(var(--color-danger-h), 94%, 80%);
}
.statusLabel { color: var(--color-danger ); }
.statusLabel {
color: var(--color-danger);
}
}
&.unknown {
&, & .executionLink {
&,
& .executionLink {
border-left: var(--spacing-4xs) var(--border-style-base) var(--color-text-light);
}
}
@@ -176,11 +219,14 @@ export default mixins(
padding-right: var(--spacing-s);
border-radius: var(--border-radius-base);
position: relative;
left: calc(-1 * var(--spacing-4xs)); // Hide link border under card border so it's not visible when not hovered
left: calc(
-1 * var(--spacing-4xs)
); // Hide link border under card border so it's not visible when not hovered
&:active {
.icon, .statusLabel {
color: var(--color-text-base);;
.icon,
.statusLabel {
color: var(--color-text-base);
}
}
}

View File

@@ -1,5 +1,8 @@
<template>
<div v-if="executionUIDetails && executionUIDetails.name === 'running'" :class="$style.runningInfo">
<div
v-if="executionUIDetails && executionUIDetails.name === 'running'"
:class="$style.runningInfo"
>
<div :class="$style.spinner">
<n8n-spinner type="ring" />
</div>
@@ -11,32 +14,66 @@
</n8n-button>
</div>
<div v-else :class="$style.previewContainer">
<div :class="{[$style.executionDetails]: true, [$style.sidebarCollapsed]: sidebarCollapsed }" v-if="activeExecution">
<div
:class="{ [$style.executionDetails]: true, [$style.sidebarCollapsed]: sidebarCollapsed }"
v-if="activeExecution"
>
<div>
<n8n-text size="large" color="text-base" :bold="true">{{ executionUIDetails.startTime }}</n8n-text><br>
<n8n-spinner v-if="executionUIDetails.name === 'running'" size="small" :class="[$style.spinner, 'mr-4xs']"/>
<n8n-text size="medium" :class="[$style.status, $style[executionUIDetails.name]]">{{ executionUIDetails.label }}</n8n-text>
<n8n-text size="large" color="text-base" :bold="true">{{
executionUIDetails.startTime
}}</n8n-text
><br />
<n8n-spinner
v-if="executionUIDetails.name === 'running'"
size="small"
:class="[$style.spinner, 'mr-4xs']"
/>
<n8n-text size="medium" :class="[$style.status, $style[executionUIDetails.name]]">{{
executionUIDetails.label
}}</n8n-text>
<n8n-text v-if="executionUIDetails.name === 'running'" color="text-base" size="medium">
{{ $locale.baseText('executionDetails.runningTimeRunning', { interpolate: { time: executionUIDetails.runningTime } }) }} | ID#{{ activeExecution.id }}
{{
$locale.baseText('executionDetails.runningTimeRunning', {
interpolate: { time: executionUIDetails.runningTime },
})
}}
| ID#{{ activeExecution.id }}
</n8n-text>
<n8n-text v-else-if="executionUIDetails.name !== 'waiting'" color="text-base" size="medium">
{{ $locale.baseText('executionDetails.runningTimeFinished', { interpolate: { time: executionUIDetails.runningTime } }) }} | ID#{{ activeExecution.id }}
{{
$locale.baseText('executionDetails.runningTimeFinished', {
interpolate: { time: executionUIDetails.runningTime },
})
}}
| ID#{{ activeExecution.id }}
</n8n-text>
<n8n-text v-else-if="executionUIDetails.name === 'waiting'" color="text-base" size="medium">
| ID#{{ activeExecution.id }}
</n8n-text>
<br><n8n-text v-if="activeExecution.mode === 'retry'" color="text-base" size= "medium">
<br /><n8n-text v-if="activeExecution.mode === 'retry'" color="text-base" size="medium">
{{ $locale.baseText('executionDetails.retry') }}
<router-link
:class="$style.executionLink"
:to="{ name: VIEWS.EXECUTION_PREVIEW, params: { workflowId: activeExecution.workflowId, executionId: activeExecution.retryOf }}"
:to="{
name: VIEWS.EXECUTION_PREVIEW,
params: {
workflowId: activeExecution.workflowId,
executionId: activeExecution.retryOf,
},
}"
>
#{{ activeExecution.retryOf }}
</router-link>
</n8n-text>
</div>
<div>
<el-dropdown v-if="executionUIDetails.name === 'error'" trigger="click" class="mr-xs" @command="handleRetryClick" ref="retryDropdown">
<el-dropdown
v-if="executionUIDetails.name === 'error'"
trigger="click"
class="mr-xs"
@command="handleRetryClick"
ref="retryDropdown"
>
<span class="retry-button">
<n8n-icon-button
size="large"
@@ -57,10 +94,21 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<n8n-icon-button :title="$locale.baseText('executionDetails.deleteExecution')" icon="trash" size="large" type="tertiary" @click="onDeleteExecution" />
<n8n-icon-button
:title="$locale.baseText('executionDetails.deleteExecution')"
icon="trash"
size="large"
type="tertiary"
@click="onDeleteExecution"
/>
</div>
</div>
<workflow-preview mode="execution" loaderType="spinner" :executionId="executionId" :executionMode="executionMode"/>
<workflow-preview
mode="execution"
loaderType="spinner"
:executionId="executionId"
:executionMode="executionMode"
/>
</div>
</template>
@@ -87,9 +135,7 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
};
},
computed: {
...mapStores(
useUIStore,
),
...mapStores(useUIStore),
executionUIDetails(): IExecutionUIData | null {
return this.activeExecution ? this.getExecutionUIDetails(this.activeExecution) : null;
},
@@ -122,7 +168,7 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
},
onRetryButtonBlur(event: FocusEvent): void {
// Hide dropdown when clicking outside of current document
const retryDropdown = this.$refs.retryDropdown as Vue & { hide: () => void } | undefined;
const retryDropdown = this.$refs.retryDropdown as (Vue & { hide: () => void }) | undefined;
if (retryDropdown && event.relatedTarget === null) {
retryDropdown.hide();
}
@@ -132,7 +178,6 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
</script>
<style module lang="scss">
.previewContainer {
height: calc(100% - $header-height);
overflow: hidden;
@@ -148,7 +193,9 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
transition: all 150ms ease-in-out;
pointer-events: none;
& * { pointer-events: all; }
& * {
pointer-events: all;
}
&.sidebarCollapsed {
width: calc(100% - 375px);
@@ -163,10 +210,19 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
}
}
.running, .spinner { color: var(--color-warning); }
.waiting { color: var(--color-secondary); }
.success { color: var(--color-success); }
.error { color: var(--color-danger); }
.running,
.spinner {
color: var(--color-warning);
}
.waiting {
color: var(--color-secondary);
}
.success {
color: var(--color-success);
}
.error {
color: var(--color-danger);
}
.runningInfo {
display: flex;

View File

@@ -14,11 +14,19 @@
<n8n-tooltip :disabled="!isNewWorkflow">
<template #content>
<div>
<n8n-link @click.prevent="onSaveWorkflowClick">{{ $locale.baseText('executionsLandingPage.emptyState.accordion.footer.tooltipLink') }}</n8n-link>
{{ $locale.baseText('executionsLandingPage.emptyState.accordion.footer.tooltipText') }}
<n8n-link @click.prevent="onSaveWorkflowClick">{{
$locale.baseText('executionsLandingPage.emptyState.accordion.footer.tooltipLink')
}}</n8n-link>
{{
$locale.baseText('executionsLandingPage.emptyState.accordion.footer.tooltipText')
}}
</div>
</template>
<n8n-link @click.prevent="openWorkflowSettings" :class="{[$style.disabled]: isNewWorkflow}" size="small">
<n8n-link
@click.prevent="openWorkflowSettings"
:class="{ [$style.disabled]: isNewWorkflow }"
size="small"
>
{{ $locale.baseText('executionsLandingPage.emptyState.accordion.footer.settingsLink') }}
</n8n-link>
</n8n-tooltip>
@@ -39,10 +47,10 @@ import mixins from 'vue-typed-mixins';
import { workflowHelpers } from '@/mixins/workflowHelpers';
interface IWorkflowSaveSettings {
saveFailedExecutions: boolean,
saveSuccessfulExecutions: boolean,
saveManualExecutions: boolean,
};
saveFailedExecutions: boolean;
saveSuccessfulExecutions: boolean;
saveManualExecutions: boolean;
}
export default mixins(workflowHelpers).extend({
name: 'executions-info-accordion',
@@ -78,24 +86,28 @@ export default mixins(workflowHelpers).extend({
},
},
computed: {
...mapStores(
useRootStore,
useSettingsStore,
useUIStore,
useWorkflowsStore,
),
...mapStores(useRootStore, useSettingsStore, useUIStore, useWorkflowsStore),
accordionItems(): Object[] {
return [
{
id: 'productionExecutions',
label: this.$locale.baseText('executionsLandingPage.emptyState.accordion.productionExecutions'),
label: this.$locale.baseText(
'executionsLandingPage.emptyState.accordion.productionExecutions',
),
icon: this.productionExecutionsIcon.icon,
iconColor: this.productionExecutionsIcon.color,
tooltip: this.productionExecutionsStatus === 'unknown' ? this.$locale.baseText('executionsLandingPage.emptyState.accordion.productionExecutionsWarningTooltip') : null,
tooltip:
this.productionExecutionsStatus === 'unknown'
? this.$locale.baseText(
'executionsLandingPage.emptyState.accordion.productionExecutionsWarningTooltip',
)
: null,
},
{
id: 'manualExecutions',
label: this.$locale.baseText('executionsLandingPage.emptyState.accordion.manualExecutions'),
label: this.$locale.baseText(
'executionsLandingPage.emptyState.accordion.manualExecutions',
),
icon: this.workflowSaveSettings.saveManualExecutions ? 'check' : 'times',
iconColor: this.workflowSaveSettings.saveManualExecutions ? 'success' : 'danger',
},
@@ -105,11 +117,13 @@ export default mixins(workflowHelpers).extend({
if (this.initiallyExpanded === false) {
return false;
}
return this.workflowSaveSettings.saveFailedExecutions === false ||
return (
this.workflowSaveSettings.saveFailedExecutions === false ||
this.workflowSaveSettings.saveSuccessfulExecutions === false ||
this.workflowSaveSettings.saveManualExecutions === false;
this.workflowSaveSettings.saveManualExecutions === false
);
},
productionExecutionsIcon(): { icon: string, color: string } {
productionExecutionsIcon(): { icon: string; color: string } {
if (this.productionExecutionsStatus === 'saving') {
return { icon: 'check', color: 'success' };
} else if (this.productionExecutionsStatus === 'not-saving') {
@@ -118,7 +132,10 @@ export default mixins(workflowHelpers).extend({
return { icon: 'exclamation-triangle', color: 'warning' };
},
productionExecutionsStatus(): string {
if (this.workflowSaveSettings.saveSuccessfulExecutions === this.workflowSaveSettings.saveFailedExecutions) {
if (
this.workflowSaveSettings.saveSuccessfulExecutions ===
this.workflowSaveSettings.saveFailedExecutions
) {
if (this.workflowSaveSettings.saveSuccessfulExecutions === true) {
return 'saving';
}
@@ -131,8 +148,11 @@ export default mixins(workflowHelpers).extend({
const workflowSettings = deepCopy(this.workflowsStore.workflowSettings);
return workflowSettings;
},
accordionIcon(): { icon: string, color: string }|null {
if (this.workflowSaveSettings.saveManualExecutions !== true || this.productionExecutionsStatus !== 'saving') {
accordionIcon(): { icon: string; color: string } | null {
if (
this.workflowSaveSettings.saveManualExecutions !== true ||
this.productionExecutionsStatus !== 'saving'
) {
return { icon: 'exclamation-triangle', color: 'warning' };
}
return null;
@@ -141,7 +161,11 @@ export default mixins(workflowHelpers).extend({
return this.workflowsStore.workflowId;
},
isNewWorkflow(): boolean {
return !this.currentWorkflowId || (this.currentWorkflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID || this.currentWorkflowId === 'new');
return (
!this.currentWorkflowId ||
this.currentWorkflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID ||
this.currentWorkflowId === 'new'
);
},
workflowName(): string {
return this.workflowsStore.workflowName;
@@ -152,9 +176,18 @@ export default mixins(workflowHelpers).extend({
},
methods: {
updateSettings(workflowSettings: IWorkflowSettings): void {
this.workflowSaveSettings.saveFailedExecutions = workflowSettings.saveDataErrorExecution === undefined ? this.defaultValues.saveFailedExecutions === 'all' : workflowSettings.saveDataErrorExecution === 'all';
this.workflowSaveSettings.saveSuccessfulExecutions = workflowSettings.saveDataSuccessExecution === undefined ? this.defaultValues.saveSuccessfulExecutions === 'all' : workflowSettings.saveDataSuccessExecution === 'all';
this.workflowSaveSettings.saveManualExecutions = workflowSettings.saveManualExecutions === undefined ? this.defaultValues.saveManualExecutions : workflowSettings.saveManualExecutions as boolean;
this.workflowSaveSettings.saveFailedExecutions =
workflowSettings.saveDataErrorExecution === undefined
? this.defaultValues.saveFailedExecutions === 'all'
: workflowSettings.saveDataErrorExecution === 'all';
this.workflowSaveSettings.saveSuccessfulExecutions =
workflowSettings.saveDataSuccessExecution === undefined
? this.defaultValues.saveSuccessfulExecutions === 'all'
: workflowSettings.saveDataSuccessExecution === 'all';
this.workflowSaveSettings.saveManualExecutions =
workflowSettings.saveManualExecutions === undefined
? this.defaultValues.saveManualExecutions
: (workflowSettings.saveManualExecutions as boolean);
},
onAccordionClick(event: MouseEvent): void {
if (event.target instanceof HTMLAnchorElement) {
@@ -178,7 +211,11 @@ export default mixins(workflowHelpers).extend({
} else if (this.$route.params.name && this.$route.params.name !== 'new') {
currentId = this.$route.params.name;
}
const saved = await this.saveCurrentWorkflow({ id: currentId, name: this.workflowName, tags: this.currentWorkflowTagIds });
const saved = await this.saveCurrentWorkflow({
id: currentId,
name: this.workflowName,
tags: this.currentWorkflowTagIds,
});
if (saved) this.settingsStore.fetchPromptsData();
},
},
@@ -186,7 +223,6 @@ export default mixins(workflowHelpers).extend({
</script>
<style module lang="scss">
.accordion {
background: none;
width: 320px;
@@ -208,7 +244,9 @@ export default mixins(workflowHelpers).extend({
width: 100%;
padding: 0 var(--spacing-l) var(--spacing-s) !important;
span { width: 100%; }
span {
width: 100%;
}
}
footer {
@@ -224,5 +262,4 @@ export default mixins(workflowHelpers).extend({
text-decoration: none;
}
}
</style>

View File

@@ -39,10 +39,7 @@ export default Vue.extend({
ExecutionsInfoAccordion,
},
computed: {
...mapStores(
useUIStore,
useWorkflowsStore,
),
...mapStores(useUIStore, useWorkflowsStore),
executionCount(): number {
return this.workflowsStore.currentWorkflowExecutions.length;
},
@@ -56,7 +53,7 @@ export default Vue.extend({
const workflowRoute = this.getWorkflowRoute();
this.$router.push(workflowRoute);
},
getWorkflowRoute(): { name: string, params: {}} {
getWorkflowRoute(): { name: string; params: {} } {
const workflowId = this.workflowsStore.workflowId || this.$route.params.name;
if (workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID) {
return { name: VIEWS.NEW_WORKFLOW, params: {} };
@@ -69,7 +66,6 @@ export default Vue.extend({
</script>
<style module lang="scss">
.container {
width: 100%;
height: 100%;

View File

@@ -1,13 +1,15 @@
<template>
<div :class="['executions-sidebar', $style.container]">
<div :class="$style.heading">
<n8n-heading tag="h2" size="medium" color="text-dark">
<n8n-heading tag="h2" size="medium" color="text-dark">
{{ $locale.baseText('generic.executions') }}
</n8n-heading>
</div>
<div :class="$style.controls">
<el-checkbox v-model="autoRefresh" @change="onAutoRefreshToggle">{{ $locale.baseText('executionsList.autoRefresh') }}</el-checkbox>
<n8n-popover trigger="click" >
<el-checkbox v-model="autoRefresh" @change="onAutoRefreshToggle">{{
$locale.baseText('executionsList.autoRefresh')
}}</el-checkbox>
<n8n-popover trigger="click">
<template #reference>
<div :class="$style.filterButton">
<n8n-button icon="filter" type="tertiary" size="medium" :active="statusFilterApplied">
@@ -37,7 +39,8 @@
v-for="item in executionStatuses"
:key="item.id"
:label="item.name"
:value="item.id">
:value="item.id"
>
</n8n-option>
</n8n-select>
</div>
@@ -86,7 +89,7 @@ import ExecutionCard from '@/components/ExecutionsView/ExecutionCard.vue';
import ExecutionsInfoAccordion from '@/components/ExecutionsView/ExecutionsInfoAccordion.vue';
import { VIEWS } from '../../constants';
import { range as _range } from 'lodash';
import { IExecutionsSummary } from "@/Interface";
import { IExecutionsSummary } from '@/Interface';
import { Route } from 'vue-router';
import Vue from 'vue';
import { PropType } from 'vue';
@@ -124,13 +127,11 @@ export default Vue.extend({
};
},
computed: {
...mapStores(
useUIStore,
),
...mapStores(useUIStore),
statusFilterApplied(): boolean {
return this.filter.status !== '';
},
executionStatuses(): Array<{ id: string, name: string }> {
executionStatuses(): Array<{ id: string; name: string }> {
return [
{ id: 'error', name: this.$locale.baseText('executionsList.error') },
{ id: 'running', name: this.$locale.baseText('executionsList.running') },
@@ -140,12 +141,12 @@ export default Vue.extend({
},
},
watch: {
$route (to: Route, from: Route) {
$route(to: Route, from: Route) {
if (from.name === VIEWS.EXECUTION_PREVIEW && to.name === VIEWS.EXECUTION_HOME) {
// Skip parent route when navigating through executions with back button
this.$router.go(-1);
}
},
},
},
mounted() {
this.autoRefresh = this.uiStore.executionSidebarAutoRefresh === true;
@@ -164,8 +165,9 @@ export default Vue.extend({
if (!this.loading) {
const executionsList = this.$refs.executionList as HTMLElement;
if (executionsList) {
const diff = executionsList.offsetHeight - (executionsList.scrollHeight - executionsList.scrollTop);
if (diff > -10 && diff < 10) {
const diff =
executionsList.offsetHeight - (executionsList.scrollHeight - executionsList.scrollTop);
if (diff > -10 && diff < 10) {
this.$emit('loadMore');
}
}
@@ -269,7 +271,7 @@ export default Vue.extend({
& > div {
width: 309px;
background-color: var(--color-background-light);
margin-top: 0 !important;
margin-top: 0 !important;
}
}
</style>

View File

@@ -29,9 +29,29 @@
<script lang="ts">
import ExecutionsSidebar from '@/components/ExecutionsView/ExecutionsSidebar.vue';
import { MODAL_CANCEL, MODAL_CLOSE, MODAL_CONFIRMED, PLACEHOLDER_EMPTY_WORKFLOW_ID, VIEWS, WEBHOOK_NODE_TYPE } from '@/constants';
import { IExecutionsListResponse, IExecutionsSummary, INodeUi, ITag, IWorkflowDb } from '@/Interface';
import { IConnection, IConnections, IDataObject, INodeTypeDescription, INodeTypeNameVersion, NodeHelpers } from 'n8n-workflow';
import {
MODAL_CANCEL,
MODAL_CLOSE,
MODAL_CONFIRMED,
PLACEHOLDER_EMPTY_WORKFLOW_ID,
VIEWS,
WEBHOOK_NODE_TYPE,
} from '@/constants';
import {
IExecutionsListResponse,
IExecutionsSummary,
INodeUi,
ITag,
IWorkflowDb,
} from '@/Interface';
import {
IConnection,
IConnections,
IDataObject,
INodeTypeDescription,
INodeTypeNameVersion,
NodeHelpers,
} from 'n8n-workflow';
import mixins from 'vue-typed-mixins';
import { restApi } from '@/mixins/restApi';
import { showMessage } from '@/mixins/showMessage';
@@ -49,7 +69,13 @@ import { useSettingsStore } from '@/stores/settings';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { useTagsStore } from '@/stores/tags';
export default mixins(restApi, showMessage, executionHelpers, debounceHelper, workflowHelpers).extend({
export default mixins(
restApi,
showMessage,
executionHelpers,
debounceHelper,
workflowHelpers,
).extend({
name: 'executions-page',
components: {
ExecutionsSidebar,
@@ -62,16 +88,14 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
};
},
computed: {
...mapStores(
useTagsStore,
useNodeTypesStore,
useSettingsStore,
useUIStore,
useWorkflowsStore,
),
...mapStores(useTagsStore, useNodeTypesStore, useSettingsStore, useUIStore, useWorkflowsStore),
hidePreview(): boolean {
const nothingToShow = this.executions.length === 0 && this.filterApplied;
const activeNotPresent = this.filterApplied && (this.executions as IExecutionsSummary[]).find(ex => ex.id === this.activeExecution.id) === undefined;
const activeNotPresent =
this.filterApplied &&
(this.executions as IExecutionsSummary[]).find(
(ex) => ex.id === this.activeExecution.id,
) === undefined;
return this.loading || nothingToShow || activeNotPresent;
},
showSidebar(): boolean {
@@ -84,7 +108,10 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
return this.filter.status !== '';
},
workflowDataNotLoaded(): boolean {
return this.workflowsStore.workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID && this.workflowsStore.workflowName === '';
return (
this.workflowsStore.workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID &&
this.workflowsStore.workflowName === ''
);
},
loadedFinishedExecutionsCount(): number {
return this.workflowsStore.getAllLoadedFinishedExecutions.length;
@@ -93,8 +120,8 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
return this.workflowsStore.getTotalFinishedExecutionsCount;
},
},
watch:{
$route (to: Route, from: Route) {
watch: {
$route(to: Route, from: Route) {
const workflowChanged = from.params.name !== to.params.name;
this.initView(workflowChanged);
@@ -141,7 +168,9 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
async mounted() {
this.loading = true;
const workflowUpdated = this.$route.params.name !== this.workflowsStore.workflowId;
const onNewWorkflow = this.$route.params.name === 'new' && this.workflowsStore.workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID;
const onNewWorkflow =
this.$route.params.name === 'new' &&
this.workflowsStore.workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID;
const shouldUpdate = workflowUpdated && !onNewWorkflow;
await this.initView(shouldUpdate);
if (!shouldUpdate) {
@@ -150,7 +179,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
this.loading = false;
},
methods: {
async initView(loadWorkflow: boolean) : Promise<void> {
async initView(loadWorkflow: boolean): Promise<void> {
if (loadWorkflow) {
if (this.nodeTypesStore.allNodeTypes.length === 0) {
await this.nodeTypesStore.getNodeTypes();
@@ -159,20 +188,25 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
this.uiStore.nodeViewInitialized = false;
this.setExecutions();
if (this.activeExecution) {
this.$router.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.activeExecution.id },
}).catch(()=>{});;
this.$router
.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.activeExecution.id },
})
.catch(() => {});
}
}
},
async onLoadMore(): Promise<void> {
if (!this.loadingMore) {
this.callDebounced("loadMore", { debounceTime: 1000 });
this.callDebounced('loadMore', { debounceTime: 1000 });
}
},
async loadMore(): Promise<void> {
if (this.filter.status === 'running' || this.loadedFinishedExecutionsCount >= this.totalFinishedExecutionsCount) {
if (
this.filter.status === 'running' ||
this.loadedFinishedExecutionsCount >= this.totalFinishedExecutionsCount
) {
return;
}
this.loadingMore = true;
@@ -186,7 +220,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
const requestFilter: IDataObject = { workflowId: this.currentWorkflow };
if (this.filter.status === 'waiting') {
requestFilter.waitTill = true;
} else if (this.filter.status !== '') {
} else if (this.filter.status !== '') {
requestFilter.finished = this.filter.status === 'success';
}
let data: IExecutionsListResponse;
@@ -194,10 +228,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
data = await this.restApi().getPastExecutions(requestFilter, 20, lastId);
} catch (error) {
this.loadingMore = false;
this.$showError(
error,
this.$locale.baseText('executionsList.showError.loadMore.title'),
);
this.$showError(error, this.$locale.baseText('executionsList.showError.loadMore.title'));
return;
}
@@ -205,9 +236,9 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
// @ts-ignore
return { ...execution, mode: execution.mode };
});
const currentExecutions = [ ...this.executions ];
const currentExecutions = [...this.executions];
for (const newExecution of data.results) {
if (currentExecutions.find(ex => ex.id === newExecution.id) === undefined) {
if (currentExecutions.find((ex) => ex.id === newExecution.id) === undefined) {
currentExecutions.push(newExecution);
}
}
@@ -217,16 +248,19 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
async onDeleteCurrentExecution(): Promise<void> {
this.loading = true;
try {
await this.restApi().deleteExecutions({ ids: [ this.$route.params.executionId ] });
await this.restApi().deleteExecutions({ ids: [this.$route.params.executionId] });
await this.setExecutions();
// Select first execution in the list after deleting the current one
if (this.executions.length > 0) {
this.workflowsStore.activeWorkflowExecution = this.executions[0];
this.$router.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
}).catch(()=>{});;
} else { // If there are no executions left, show empty state and clear active execution from the store
this.$router
.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
})
.catch(() => {});
} else {
// If there are no executions left, show empty state and clear active execution from the store
this.workflowsStore.activeWorkflowExecution = null;
this.$router.push({ name: VIEWS.EXECUTION_HOME, params: { name: this.currentWorkflow } });
}
@@ -253,10 +287,9 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
this.$showMessage({
title: this.$locale.baseText('executionsList.showMessage.stopExecution.title'),
message: this.$locale.baseText(
'executionsList.showMessage.stopExecution.message',
{ interpolate: { activeExecutionId } },
),
message: this.$locale.baseText('executionsList.showMessage.stopExecution.message', {
interpolate: { activeExecutionId },
}),
type: 'success',
});
@@ -268,7 +301,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
);
}
},
onFilterUpdated(newFilter: { finished: boolean, status: string }): void {
onFilterUpdated(newFilter: { finished: boolean; status: string }): void {
this.filter = newFilter;
this.setExecutions();
},
@@ -280,13 +313,13 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
async loadAutoRefresh(): Promise<void> {
// Most of the auto-refresh logic is taken from the `ExecutionsList` component
const fetchedExecutions: IExecutionsSummary[] = await this.loadExecutions();
let existingExecutions: IExecutionsSummary[] = [ ...this.executions ];
const alreadyPresentExecutionIds = existingExecutions.map(exec => parseInt(exec.id, 10));
let existingExecutions: IExecutionsSummary[] = [...this.executions];
const alreadyPresentExecutionIds = existingExecutions.map((exec) => parseInt(exec.id, 10));
let lastId = 0;
const gaps = [] as number[];
let updatedActiveExecution = null;
for(let i = fetchedExecutions.length - 1; i >= 0; i--) {
for (let i = fetchedExecutions.length - 1; i >= 0; i--) {
const currentItem = fetchedExecutions[i];
const currentId = parseInt(currentItem.id, 10);
if (lastId !== 0 && isNaN(currentId) === false) {
@@ -299,9 +332,12 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
const executionIndex = alreadyPresentExecutionIds.indexOf(currentId);
if (executionIndex !== -1) {
const existingExecution = existingExecutions.find(ex => ex.id === currentItem.id);
const existingStillRunning = existingExecution && existingExecution.finished === false || existingExecution?.stoppedAt === undefined;
const currentFinished = currentItem.finished === true || currentItem.stoppedAt !== undefined;
const existingExecution = existingExecutions.find((ex) => ex.id === currentItem.id);
const existingStillRunning =
(existingExecution && existingExecution.finished === false) ||
existingExecution?.stoppedAt === undefined;
const currentFinished =
currentItem.finished === true || currentItem.stoppedAt !== undefined;
if (existingStillRunning && currentFinished) {
existingExecutions[executionIndex] = currentItem;
@@ -324,19 +360,25 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
}
}
existingExecutions = existingExecutions.filter(execution => !gaps.includes(parseInt(execution.id, 10)) && lastId >= parseInt(execution.id, 10));
existingExecutions = existingExecutions.filter(
(execution) =>
!gaps.includes(parseInt(execution.id, 10)) && lastId >= parseInt(execution.id, 10),
);
this.workflowsStore.currentWorkflowExecutions = existingExecutions;
if (updatedActiveExecution !== null) {
this.workflowsStore.activeWorkflowExecution = updatedActiveExecution;
} else {
const activeNotInTheList = existingExecutions.find(ex => ex.id === this.activeExecution.id) === undefined;
const activeNotInTheList =
existingExecutions.find((ex) => ex.id === this.activeExecution.id) === undefined;
if (activeNotInTheList && this.executions.length > 0) {
this.$router.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
}).catch(()=>{});
this.$router
.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
})
.catch(() => {});
} else if (this.executions.length === 0) {
this.$router.push({ name: VIEWS.EXECUTION_HOME }).catch(()=>{});
this.$router.push({ name: VIEWS.EXECUTION_HOME }).catch(() => {});
this.workflowsStore.activeWorkflowExecution = null;
}
}
@@ -350,10 +392,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
await this.workflowsStore.loadCurrentWorkflowExecutions(this.filter);
return executions;
} catch (error) {
this.$showError(
error,
this.$locale.baseText('executionsList.showError.refreshData.title'),
);
this.$showError(error, this.$locale.baseText('executionsList.showError.refreshData.title'));
return [];
}
},
@@ -368,56 +407,56 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
// If there is no execution in the route, select the first one
if (this.workflowsStore.activeWorkflowExecution === null && this.executions.length > 0) {
this.workflowsStore.activeWorkflowExecution = this.executions[0];
this.$router.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
}).catch(()=>{});;
this.$router
.push({
name: VIEWS.EXECUTION_PREVIEW,
params: { name: this.currentWorkflow, executionId: this.executions[0].id },
})
.catch(() => {});
}
},
async openWorkflow(workflowId: string): Promise<void> {
await this.loadActiveWorkflows();
let data: IWorkflowDb | undefined;
try {
data = await this.restApi().getWorkflow(workflowId);
} catch (error) {
this.$showError(
error,
this.$locale.baseText('nodeView.showError.openWorkflow.title'),
);
return;
}
if (data === undefined) {
throw new Error(
this.$locale.baseText(
'nodeView.workflowWithIdCouldNotBeFound',
{ interpolate: { workflowId } },
),
);
}
await this.addNodes(data.nodes, data.connections);
try {
data = await this.restApi().getWorkflow(workflowId);
} catch (error) {
this.$showError(error, this.$locale.baseText('nodeView.showError.openWorkflow.title'));
return;
}
if (data === undefined) {
throw new Error(
this.$locale.baseText('nodeView.workflowWithIdCouldNotBeFound', {
interpolate: { workflowId },
}),
);
}
await this.addNodes(data.nodes, data.connections);
this.workflowsStore.setActive(data.active || false);
this.workflowsStore.setWorkflowId(workflowId);
this.workflowsStore.setWorkflowName({ newName: data.name, setStateDirty: false });
this.workflowsStore.setWorkflowSettings(data.settings || {});
this.workflowsStore.setWorkflowPinData(data.pinData || {});
const tags = (data.tags || []) as ITag[];
const tagIds = tags.map((tag) => tag.id);
this.workflowsStore.setWorkflowTagIds(tagIds || []);
this.workflowsStore.setWorkflowVersionId(data.versionId);
this.workflowsStore.setActive(data.active || false);
this.workflowsStore.setWorkflowId(workflowId);
this.workflowsStore.setWorkflowName({ newName: data.name, setStateDirty: false });
this.workflowsStore.setWorkflowSettings(data.settings || {});
this.workflowsStore.setWorkflowPinData(data.pinData || {});
const tags = (data.tags || []) as ITag[];
const tagIds = tags.map((tag) => tag.id);
this.workflowsStore.setWorkflowTagIds(tagIds || []);
this.workflowsStore.setWorkflowVersionId(data.versionId);
this.tagsStore.upsertTags(tags);
this.tagsStore.upsertTags(tags);
this.$externalHooks().run('workflow.open', { workflowId, workflowName: data.name });
this.uiStore.stateIsDirty = false;
this.$externalHooks().run('workflow.open', { workflowId, workflowName: data.name });
this.uiStore.stateIsDirty = false;
},
async addNodes(nodes: INodeUi[], connections?: IConnections) {
if (!nodes || !nodes.length) {
return;
}
await this.loadNodesProperties(nodes.map(node => ({ name: node.type, version: node.typeVersion })));
await this.loadNodesProperties(
nodes.map((node) => ({ name: node.type, version: node.typeVersion })),
);
let nodeType: INodeTypeDescription | null;
nodes.forEach((node) => {
@@ -441,9 +480,18 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
if (nodeType !== null) {
let nodeParameters = null;
try {
nodeParameters = NodeHelpers.getNodeParameters(nodeType.properties, node.parameters, true, false, node);
nodeParameters = NodeHelpers.getNodeParameters(
nodeType.properties,
node.parameters,
true,
false,
node,
);
} catch (e) {
console.error(this.$locale.baseText('nodeView.thereWasAProblemLoadingTheNodeParametersOfNode') + `: "${node.name}"`); // eslint-disable-line no-console
console.error(
this.$locale.baseText('nodeView.thereWasAProblemLoadingTheNodeParametersOfNode') +
`: "${node.name}"`,
); // eslint-disable-line no-console
console.error(e); // eslint-disable-line no-console
}
node.parameters = nodeParameters !== null ? nodeParameters : {};
@@ -462,14 +510,16 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
let connectionData;
for (const sourceNode of Object.keys(connections)) {
for (const type of Object.keys(connections[sourceNode])) {
for (let sourceIndex = 0; sourceIndex < connections[sourceNode][type].length; sourceIndex++) {
for (
let sourceIndex = 0;
sourceIndex < connections[sourceNode][type].length;
sourceIndex++
) {
const outwardConnections = connections[sourceNode][type][sourceIndex];
if (!outwardConnections) {
continue;
}
outwardConnections.forEach((
targetData,
) => {
outwardConnections.forEach((targetData) => {
connectionData = [
{
node: sourceNode,
@@ -483,7 +533,10 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
},
] as [IConnection, IConnection];
this.workflowsStore.addConnection({ connection: connectionData, setStateDirty: false });
this.workflowsStore.addConnection({
connection: connectionData,
setStateDirty: false,
});
});
}
}
@@ -494,14 +547,15 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
const allNodes: INodeTypeDescription[] = this.nodeTypesStore.allNodeTypes;
const nodesToBeFetched: INodeTypeNameVersion[] = [];
allNodes.forEach(node => {
allNodes.forEach((node) => {
const nodeVersions = Array.isArray(node.version) ? node.version : [node.version];
if (!!nodeInfos.find(n => n.name === node.name && nodeVersions.includes(n.version)) && !node.hasOwnProperty('properties')) {
if (
!!nodeInfos.find((n) => n.name === node.name && nodeVersions.includes(n.version)) &&
!node.hasOwnProperty('properties')
) {
nodesToBeFetched.push({
name: node.name,
version: Array.isArray(node.version)
? node.version.slice(-1)[0]
: node.version,
version: Array.isArray(node.version) ? node.version.slice(-1)[0] : node.version,
});
}
});
@@ -515,7 +569,7 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
const activeWorkflows = await this.restApi().getActiveWorkflows();
this.workflowsStore.activeWorkflows = activeWorkflows;
},
async onRetryExecution(payload: { execution: IExecutionsSummary, command: string }) {
async onRetryExecution(payload: { execution: IExecutionsSummary; command: string }) {
const loadWorkflow = payload.command === 'current-workflow';
this.$showMessage({
@@ -547,7 +601,6 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
type: 'error',
});
}
} catch (error) {
this.$showError(
error,
@@ -560,7 +613,6 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
</script>
<style module lang="scss">
.container {
display: flex;
height: 100%;
@@ -575,5 +627,4 @@ export default mixins(restApi, showMessage, executionHelpers, debounceHelper, wo
margin-top: var(--spacing-2xl);
text-align: center;
}
</style>