diff --git a/cypress/e2e/20-workflow-executions.cy.ts b/cypress/e2e/20-workflow-executions.cy.ts index 37036a7971d6e..0773d6f8fc35c 100644 --- a/cypress/e2e/20-workflow-executions.cy.ts +++ b/cypress/e2e/20-workflow-executions.cy.ts @@ -71,6 +71,45 @@ describe('Current Workflow Executions', () => { cy.wait(executionsRefreshInterval); cy.url().should('not.include', '/executions'); }); + + it.only('should auto load more items if there is space and auto scroll', () => { + cy.viewport(1280, 960); + executionsTab.actions.createManualExecutions(24); + + cy.intercept('GET', '/rest/executions?filter=*').as('getExecutions'); + cy.intercept('GET', '/rest/executions/*').as('getExecution'); + executionsTab.actions.switchToExecutionsTab(); + + cy.wait(['@getExecutions']); + executionsTab.getters.executionListItems().its('length').should('be.gte', 10); + + cy.getByTestId('current-executions-list').scrollTo('bottom'); + cy.wait(['@getExecutions']); + executionsTab.getters.executionListItems().should('have.length', 24); + + executionsTab.getters.executionListItems().eq(14).click(); + cy.wait(['@getExecution']); + cy.reload(); + + cy.wait(['@getExecutions']); + executionsTab.getters.executionListItems().eq(14).should('not.be.visible'); + executionsTab.getters.executionListItems().should('have.length', 24); + executionsTab.getters.executionListItems().first().should('not.be.visible'); + cy.getByTestId('current-executions-list').scrollTo(0, 0); + executionsTab.getters.executionListItems().first().should('be.visible'); + executionsTab.getters.executionListItems().eq(14).should('not.be.visible'); + + executionsTab.actions.switchToEditorTab(); + executionsTab.actions.switchToExecutionsTab(); + + cy.wait(['@getExecutions']); + executionsTab.getters.executionListItems().eq(14).should('not.be.visible'); + executionsTab.getters.executionListItems().should('have.length', 24); + executionsTab.getters.executionListItems().first().should('not.be.visible'); + cy.getByTestId('current-executions-list').scrollTo(0, 0); + executionsTab.getters.executionListItems().first().should('be.visible'); + executionsTab.getters.executionListItems().eq(14).should('not.be.visible'); + }); }); const createMockExecutions = () => { diff --git a/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsCard.vue b/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsCard.vue index d178273ca53a0..fc4907745fc4b 100644 --- a/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsCard.vue +++ b/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsCard.vue @@ -110,6 +110,7 @@ export default defineComponent({ default: false, }, }, + emits: ['retryExecution', 'mounted'], setup() { const executionHelpers = useExecutionHelpers(); @@ -147,6 +148,9 @@ export default defineComponent({ return VIEWS.EXECUTION_PREVIEW; }, }, + mounted() { + this.$emit('mounted', this.execution.id); + }, methods: { onRetryMenuItemSelect(action: string): void { this.$emit('retryExecution', { execution: this.execution, command: action }); diff --git a/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsSidebar.vue b/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsSidebar.vue index d0f5fc7e41317..1b5553259ed49 100644 --- a/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsSidebar.vue +++ b/packages/editor-ui/src/components/executions/workflow/WorkflowExecutionsSidebar.vue @@ -53,6 +53,7 @@ :execution="execution" :data-test-id="`execution-details-${execution.id}`" @retry-execution="onRetryExecution" + @mounted="onItemMounted" />
@@ -80,6 +81,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store'; import type { ExecutionFilterType } from '@/Interface'; type WorkflowExecutionsCardRef = InstanceType; +type AutoScrollDeps = { activeExecutionSet: boolean; cardsMounted: boolean; scroll: boolean }; export default defineComponent({ name: 'WorkflowExecutionsSidebar', @@ -117,6 +119,12 @@ export default defineComponent({ data() { return { filter: {} as ExecutionFilterType, + mountedItems: [] as string[], + autoScrollDeps: { + activeExecutionSet: false, + cardsMounted: false, + scroll: true, + } as AutoScrollDeps, }; }, computed: { @@ -129,16 +137,35 @@ export default defineComponent({ this.$router.go(-1); } }, - }, - mounted() { - // On larger screens, we need to load more then first page of executions - // for the scroll bar to appear and infinite scrolling is enabled - this.checkListSize(); - setTimeout(() => { - this.scrollToActiveCard(); - }, 1000); + 'executionsStore.activeExecution'( + newValue: ExecutionSummary | null, + oldValue: ExecutionSummary | null, + ) { + if (newValue && newValue.id !== oldValue?.id) { + this.autoScrollDeps.activeExecutionSet = true; + } + }, + autoScrollDeps: { + handler(updatedDeps: AutoScrollDeps) { + if (Object.values(updatedDeps).every(Boolean)) { + this.scrollToActiveCard(); + } + }, + deep: true, + }, }, methods: { + onItemMounted(id: string): void { + this.mountedItems.push(id); + if (this.mountedItems.length === this.executions.length) { + this.autoScrollDeps.cardsMounted = true; + this.checkListSize(); + } + + if (this.executionsStore.activeExecution?.id === id) { + this.autoScrollDeps.activeExecutionSet = true; + } + }, loadMore(limit = 20): void { if (!this.loading) { const executionsListRef = this.$refs.executionList as HTMLElement | undefined; @@ -167,7 +194,7 @@ export default defineComponent({ checkListSize(): void { const sidebarContainerRef = this.$refs.container as HTMLElement | undefined; const currentWorkflowExecutionsCardRefs = this.$refs[ - `execution-${this.executionsStore.activeExecution?.id}` + `execution-${this.mountedItems[this.mountedItems.length - 1]}` ] as WorkflowExecutionsCardRef[] | undefined; // Find out how many execution card can fit into list @@ -196,7 +223,11 @@ export default defineComponent({ const cardRect = cardElement.getBoundingClientRect(); const LIST_HEADER_OFFSET = 200; if (cardRect.top > executionsListRef.offsetHeight) { - executionsListRef.scrollTo({ top: cardRect.top - LIST_HEADER_OFFSET }); + this.autoScrollDeps.scroll = false; + executionsListRef.scrollTo({ + top: cardRect.top - LIST_HEADER_OFFSET, + behavior: 'smooth', + }); } } },