mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Fix loading executions in long execution list (#5843)
* fix(editor): Fix loading executions in long execution list * ⚡ Added max number of attempts before displaying temporary execution card * ⚡ Simplifying temp execution preview logic, handling current execution delete, updating style * 💄 Renaming `executionWIthGap` -> `temporaryExecution`
This commit is contained in:
parent
3be37e25a5
commit
d5d9f58f17
|
@ -6,6 +6,7 @@
|
||||||
[$style.active]: isActive,
|
[$style.active]: isActive,
|
||||||
[$style[executionUIDetails.name]]: true,
|
[$style[executionUIDetails.name]]: true,
|
||||||
[$style.highlight]: highlight,
|
[$style.highlight]: highlight,
|
||||||
|
[$style.showGap]: showGap,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
|
@ -107,6 +108,10 @@ export default mixins(executionHelpers, showMessage, restApi).extend({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
showGap: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
retryExecutionActions(): object[] {
|
retryExecutionActions(): object[] {
|
||||||
|
@ -139,6 +144,7 @@ export default mixins(executionHelpers, showMessage, restApi).extend({
|
||||||
<style module lang="scss">
|
<style module lang="scss">
|
||||||
.executionCard {
|
.executionCard {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
padding-right: var(--spacing-m);
|
padding-right: var(--spacing-m);
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
|
@ -252,4 +258,10 @@ export default mixins(executionHelpers, showMessage, restApi).extend({
|
||||||
margin-left: var(--spacing-2xs);
|
margin-left: var(--spacing-2xs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.showGap {
|
||||||
|
margin-bottom: var(--spacing-2xs);
|
||||||
|
.executionLink {
|
||||||
|
border-bottom: 1px solid var(--color-foreground-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
:executions="executions"
|
:executions="executions"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:loadingMore="loadingMore"
|
:loadingMore="loadingMore"
|
||||||
|
:temporaryExecution="temporaryExecution"
|
||||||
@reloadExecutions="setExecutions"
|
@reloadExecutions="setExecutions"
|
||||||
@filterUpdated="onFilterUpdated"
|
@filterUpdated="onFilterUpdated"
|
||||||
@loadMore="loadMore"
|
@loadMore="onLoadMore"
|
||||||
@retryExecution="onRetryExecution"
|
@retryExecution="onRetryExecution"
|
||||||
@refresh="loadAutoRefresh"
|
@refresh="loadAutoRefresh"
|
||||||
/>
|
/>
|
||||||
|
@ -55,7 +56,7 @@ import { Route } from 'vue-router';
|
||||||
import { executionHelpers } from '@/mixins/executionsHelpers';
|
import { executionHelpers } from '@/mixins/executionsHelpers';
|
||||||
import { range as _range } from 'lodash-es';
|
import { range as _range } from 'lodash-es';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
import { debounceHelper } from '@/mixins/debounce';
|
||||||
import { getNodeViewTab, isEmpty, NO_NETWORK_ERROR_CODE } from '@/utils';
|
import { getNodeViewTab, NO_NETWORK_ERROR_CODE } from '@/utils';
|
||||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows';
|
import { useWorkflowsStore } from '@/stores/workflows';
|
||||||
|
@ -65,6 +66,11 @@ import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||||
import { useTagsStore } from '@/stores/tags';
|
import { useTagsStore } from '@/stores/tags';
|
||||||
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
||||||
|
|
||||||
|
// Number of execution pages that are fetched before temporary execution card is shown
|
||||||
|
const MAX_LOADING_ATTEMPTS = 1;
|
||||||
|
// Number of executions fetched on each page
|
||||||
|
const LOAD_MORE_PAGE_SIZE = 10;
|
||||||
|
|
||||||
export default mixins(
|
export default mixins(
|
||||||
restApi,
|
restApi,
|
||||||
showMessage,
|
showMessage,
|
||||||
|
@ -81,6 +87,7 @@ export default mixins(
|
||||||
loading: false,
|
loading: false,
|
||||||
loadingMore: false,
|
loadingMore: false,
|
||||||
filter: {} as ExecutionFilterType,
|
filter: {} as ExecutionFilterType,
|
||||||
|
temporaryExecution: null as IExecutionsSummary | null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -234,6 +241,10 @@ export default mixins(
|
||||||
if (currentExecutions.find((ex) => ex.id === newExecution.id) === undefined) {
|
if (currentExecutions.find((ex) => ex.id === newExecution.id) === undefined) {
|
||||||
currentExecutions.push(newExecution);
|
currentExecutions.push(newExecution);
|
||||||
}
|
}
|
||||||
|
// If we loaded temp execution, put it into it's place and remove from top of the list
|
||||||
|
if (newExecution.id === this.temporaryExecution?.id) {
|
||||||
|
this.temporaryExecution = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.workflowsStore.currentWorkflowExecutions = currentExecutions;
|
this.workflowsStore.currentWorkflowExecutions = currentExecutions;
|
||||||
this.loadingMore = false;
|
this.loadingMore = false;
|
||||||
|
@ -250,6 +261,9 @@ export default mixins(
|
||||||
this.executions[0];
|
this.executions[0];
|
||||||
|
|
||||||
await this.restApi().deleteExecutions({ ids: [this.$route.params.executionId] });
|
await this.restApi().deleteExecutions({ ids: [this.$route.params.executionId] });
|
||||||
|
if (this.temporaryExecution?.id === this.$route.params.executionId) {
|
||||||
|
this.temporaryExecution = null;
|
||||||
|
}
|
||||||
if (this.executions.length > 0) {
|
if (this.executions.length > 0) {
|
||||||
await this.$router
|
await this.$router
|
||||||
.push({
|
.push({
|
||||||
|
@ -371,7 +385,7 @@ export default mixins(
|
||||||
this.workflowsStore.activeWorkflowExecution = updatedActiveExecution;
|
this.workflowsStore.activeWorkflowExecution = updatedActiveExecution;
|
||||||
} else {
|
} else {
|
||||||
const activeInList = existingExecutions.some((ex) => ex.id === this.activeExecution?.id);
|
const activeInList = existingExecutions.some((ex) => ex.id === this.activeExecution?.id);
|
||||||
if (!activeInList && this.executions.length > 0) {
|
if (!activeInList && this.executions.length > 0 && !this.temporaryExecution) {
|
||||||
this.$router
|
this.$router
|
||||||
.push({
|
.push({
|
||||||
name: VIEWS.EXECUTION_PREVIEW,
|
name: VIEWS.EXECUTION_PREVIEW,
|
||||||
|
@ -422,7 +436,11 @@ export default mixins(
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no execution in the route, select the first one
|
// If there is no execution in the route, select the first one
|
||||||
if (this.workflowsStore.activeWorkflowExecution === null && this.executions.length > 0) {
|
if (
|
||||||
|
this.workflowsStore.activeWorkflowExecution === null &&
|
||||||
|
this.executions.length > 0 &&
|
||||||
|
!this.temporaryExecution
|
||||||
|
) {
|
||||||
this.workflowsStore.activeWorkflowExecution = this.executions[0];
|
this.workflowsStore.activeWorkflowExecution = this.executions[0];
|
||||||
this.$router
|
this.$router
|
||||||
.push({
|
.push({
|
||||||
|
@ -435,8 +453,8 @@ export default mixins(
|
||||||
async tryToFindExecution(executionId: string, attemptCount = 0): Promise<void> {
|
async tryToFindExecution(executionId: string, attemptCount = 0): Promise<void> {
|
||||||
// First check if executions exists in the DB at all
|
// First check if executions exists in the DB at all
|
||||||
if (attemptCount === 0) {
|
if (attemptCount === 0) {
|
||||||
const executionExists = await this.workflowsStore.fetchExecutionDataById(executionId);
|
const existingExecution = await this.workflowsStore.fetchExecutionDataById(executionId);
|
||||||
if (!executionExists) {
|
if (!existingExecution) {
|
||||||
this.workflowsStore.activeWorkflowExecution = null;
|
this.workflowsStore.activeWorkflowExecution = null;
|
||||||
this.$showError(
|
this.$showError(
|
||||||
new Error(
|
new Error(
|
||||||
|
@ -447,17 +465,21 @@ export default mixins(
|
||||||
this.$locale.baseText('nodeView.showError.openExecution.title'),
|
this.$locale.baseText('nodeView.showError.openExecution.title'),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
this.temporaryExecution = existingExecution as IExecutionsSummary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop if the execution wasn't found in the first 1000 lookups
|
// stop if the execution wasn't found in the first 1000 lookups
|
||||||
if (attemptCount >= 10) {
|
if (attemptCount >= MAX_LOADING_ATTEMPTS) {
|
||||||
|
if (this.temporaryExecution) {
|
||||||
|
this.workflowsStore.activeWorkflowExecution = this.temporaryExecution;
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.workflowsStore.activeWorkflowExecution = null;
|
this.workflowsStore.activeWorkflowExecution = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch next batch of executions
|
// Fetch next batch of executions
|
||||||
await this.loadMore(100);
|
await this.loadMore(LOAD_MORE_PAGE_SIZE);
|
||||||
const execution = this.workflowsStore.getExecutionDataById(executionId);
|
const execution = this.workflowsStore.getExecutionDataById(executionId);
|
||||||
if (!execution) {
|
if (!execution) {
|
||||||
// If it's not there load next until found
|
// If it's not there load next until found
|
||||||
|
@ -467,6 +489,7 @@ export default mixins(
|
||||||
} else {
|
} else {
|
||||||
// When found set execution as active
|
// When found set execution as active
|
||||||
this.workflowsStore.activeWorkflowExecution = execution;
|
this.workflowsStore.activeWorkflowExecution = execution;
|
||||||
|
this.temporaryExecution = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,7 +36,15 @@
|
||||||
</n8n-text>
|
</n8n-text>
|
||||||
</div>
|
</div>
|
||||||
<execution-card
|
<execution-card
|
||||||
v-else
|
v-else-if="temporaryExecution"
|
||||||
|
:execution="temporaryExecution"
|
||||||
|
:ref="`execution-${temporaryExecution.id}`"
|
||||||
|
:data-test-id="`execution-details-${temporaryExecution.id}`"
|
||||||
|
:showGap="true"
|
||||||
|
@refresh="onRefresh"
|
||||||
|
@retryExecution="onRetryExecution"
|
||||||
|
/>
|
||||||
|
<execution-card
|
||||||
v-for="execution in executions"
|
v-for="execution in executions"
|
||||||
:key="execution.id"
|
:key="execution.id"
|
||||||
:execution="execution"
|
:execution="execution"
|
||||||
|
@ -89,6 +97,10 @@ export default Vue.extend({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
temporaryExecution: {
|
||||||
|
type: Object as PropType<IExecutionsSummary>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in a new issue