fix(editor): Add loading skeletons to Executions list page (#6184)

* fix(editor): Add loading skeletons to Executions list page

* fix(editor): lint fix

* fix(editor): fix loading

* fix(editor): fix loading

* fix(editor): fix keys

* fix(editor): fix localization

* fix(editor): fix key
This commit is contained in:
Csaba Tuncsik 2023-05-09 18:41:38 +02:00 committed by GitHub
parent cbc4256007
commit eae3a55cc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 34 deletions

View file

@ -162,26 +162,24 @@ onBeforeMount(() => {
data-test-id="execution-filter-badge" data-test-id="execution-filter-badge"
>{{ countSelectedFilterProps }}</n8n-badge >{{ countSelectedFilterProps }}</n8n-badge
> >
{{ $locale.baseText('executionsList.filters') }} {{ locale.baseText('executionsList.filters') }}
</n8n-button> </n8n-button>
</template> </template>
<div data-test-id="execution-filter-form"> <div data-test-id="execution-filter-form">
<div v-if="workflows?.length" :class="$style.group"> <div v-if="workflows?.length" :class="$style.group">
<label for="execution-filter-workflows">{{ <label for="execution-filter-workflows">{{ locale.baseText('workflows.heading') }}</label>
$locale.baseText('workflows.heading')
}}</label>
<n8n-select <n8n-select
id="execution-filter-workflows" id="execution-filter-workflows"
v-model="vModel.workflowId" v-model="vModel.workflowId"
:placeholder="$locale.baseText('executionsFilter.selectWorkflow')" :placeholder="locale.baseText('executionsFilter.selectWorkflow')"
size="medium" size="medium"
filterable filterable
data-test-id="executions-filter-workflows-select" data-test-id="executions-filter-workflows-select"
> >
<div class="ph-no-capture"> <div class="ph-no-capture">
<n8n-option <n8n-option
v-for="item in workflows" v-for="(item, idx) in props.workflows"
:key="item.id" :key="idx"
:label="item.name" :label="item.name"
:value="item.id" :value="item.id"
/> />
@ -189,12 +187,10 @@ onBeforeMount(() => {
</n8n-select> </n8n-select>
</div> </div>
<div v-if="showTags" :class="$style.group"> <div v-if="showTags" :class="$style.group">
<label for="execution-filter-tags">{{ <label for="execution-filter-tags">{{ locale.baseText('workflows.filters.tags') }}</label>
$locale.baseText('workflows.filters.tags')
}}</label>
<TagsDropdown <TagsDropdown
id="execution-filter-tags" id="execution-filter-tags"
:placeholder="$locale.baseText('workflowOpen.filterWorkflows')" :placeholder="locale.baseText('workflowOpen.filterWorkflows')"
:currentTagIds="filter.tags" :currentTagIds="filter.tags"
:createEnabled="false" :createEnabled="false"
@update="onTagsChange" @update="onTagsChange"
@ -203,19 +199,19 @@ onBeforeMount(() => {
</div> </div>
<div :class="$style.group"> <div :class="$style.group">
<label for="execution-filter-status">{{ <label for="execution-filter-status">{{
$locale.baseText('executionsList.status') locale.baseText('executionsList.status')
}}</label> }}</label>
<n8n-select <n8n-select
id="execution-filter-status" id="execution-filter-status"
v-model="vModel.status" v-model="vModel.status"
:placeholder="$locale.baseText('executionsFilter.selectStatus')" :placeholder="locale.baseText('executionsFilter.selectStatus')"
size="medium" size="medium"
filterable filterable
data-test-id="executions-filter-status-select" data-test-id="executions-filter-status-select"
> >
<n8n-option <n8n-option
v-for="item in statuses" v-for="(item, idx) in statuses"
:key="item.id" :key="idx"
:label="item.name" :label="item.name"
:value="item.id" :value="item.id"
/> />
@ -223,7 +219,7 @@ onBeforeMount(() => {
</div> </div>
<div :class="$style.group"> <div :class="$style.group">
<label for="execution-filter-start-date">{{ <label for="execution-filter-start-date">{{
$locale.baseText('executionsFilter.start') locale.baseText('executionsFilter.start')
}}</label> }}</label>
<div :class="$style.dates"> <div :class="$style.dates">
<el-date-picker <el-date-picker
@ -231,7 +227,7 @@ onBeforeMount(() => {
type="datetime" type="datetime"
v-model="vModel.startDate" v-model="vModel.startDate"
:format="DATE_TIME_MASK" :format="DATE_TIME_MASK"
:placeholder="$locale.baseText('executionsFilter.startDate')" :placeholder="locale.baseText('executionsFilter.startDate')"
data-test-id="executions-filter-start-date-picker" data-test-id="executions-filter-start-date-picker"
/> />
<span :class="$style.divider">to</span> <span :class="$style.divider">to</span>
@ -240,7 +236,7 @@ onBeforeMount(() => {
type="datetime" type="datetime"
v-model="vModel.endDate" v-model="vModel.endDate"
:format="DATE_TIME_MASK" :format="DATE_TIME_MASK"
:placeholder="$locale.baseText('executionsFilter.endDate')" :placeholder="locale.baseText('executionsFilter.endDate')"
data-test-id="executions-filter-end-date-picker" data-test-id="executions-filter-end-date-picker"
/> />
</div> </div>
@ -254,19 +250,19 @@ onBeforeMount(() => {
target="_blank" target="_blank"
href="https://docs.n8n.io/workflows/executions/custom-executions-data/" href="https://docs.n8n.io/workflows/executions/custom-executions-data/"
> >
{{ $locale.baseText('executionsFilter.customData.docsTooltip.link') }} {{ locale.baseText('executionsFilter.customData.docsTooltip.link') }}
</a> </a>
</template> </template>
</i18n> </i18n>
</template> </template>
<span :class="$style.label"> <span :class="$style.label">
{{ $locale.baseText('executionsFilter.savedData') }} {{ locale.baseText('executionsFilter.savedData') }}
<n8n-icon :class="$style.tooltipIcon" icon="question-circle" size="small" /> <n8n-icon :class="$style.tooltipIcon" icon="question-circle" size="small" />
</span> </span>
</n8n-tooltip> </n8n-tooltip>
<div :class="$style.subGroup"> <div :class="$style.subGroup">
<label for="execution-filter-saved-data-key">{{ <label for="execution-filter-saved-data-key">{{
$locale.baseText('executionsFilter.savedDataKey') locale.baseText('executionsFilter.savedDataKey')
}}</label> }}</label>
<n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top"> <n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top">
<template #content> <template #content>
@ -276,7 +272,7 @@ onBeforeMount(() => {
href="#" href="#"
@click.prevent="goToUpgrade" @click.prevent="goToUpgrade"
data-test-id="executions-filter-view-plans-link" data-test-id="executions-filter-view-plans-link"
>{{ $locale.baseText('executionsFilter.customData.inputTooltip.link') }}</a >{{ locale.baseText('executionsFilter.customData.inputTooltip.link') }}</a
> >
</template> </template>
</i18n> </i18n>
@ -287,21 +283,21 @@ onBeforeMount(() => {
type="text" type="text"
size="medium" size="medium"
:disabled="!isAdvancedExecutionFilterEnabled" :disabled="!isAdvancedExecutionFilterEnabled"
:placeholder="$locale.baseText('executionsFilter.savedDataKeyPlaceholder')" :placeholder="locale.baseText('executionsFilter.savedDataKeyPlaceholder')"
:value="filter.metadata[0]?.key" :value="filter.metadata[0]?.key"
@input="onFilterMetaChange(0, 'key', $event)" @input="onFilterMetaChange(0, 'key', $event)"
data-test-id="execution-filter-saved-data-key-input" data-test-id="execution-filter-saved-data-key-input"
/> />
</n8n-tooltip> </n8n-tooltip>
<label for="execution-filter-saved-data-value">{{ <label for="execution-filter-saved-data-value">{{
$locale.baseText('executionsFilter.savedDataValue') locale.baseText('executionsFilter.savedDataValue')
}}</label> }}</label>
<n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top"> <n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top">
<template #content> <template #content>
<i18n tag="span" path="executionsFilter.customData.inputTooltip"> <i18n tag="span" path="executionsFilter.customData.inputTooltip">
<template #link> <template #link>
<a href="#" @click.prevent="goToUpgrade">{{ <a href="#" @click.prevent="goToUpgrade">{{
$locale.baseText('executionsFilter.customData.inputTooltip.link') locale.baseText('executionsFilter.customData.inputTooltip.link')
}}</a> }}</a>
</template> </template>
</i18n> </i18n>
@ -312,7 +308,7 @@ onBeforeMount(() => {
type="text" type="text"
size="medium" size="medium"
:disabled="!isAdvancedExecutionFilterEnabled" :disabled="!isAdvancedExecutionFilterEnabled"
:placeholder="$locale.baseText('executionsFilter.savedDataValuePlaceholder')" :placeholder="locale.baseText('executionsFilter.savedDataValuePlaceholder')"
:value="filter.metadata[0]?.value" :value="filter.metadata[0]?.value"
@input="onFilterMetaChange(0, 'value', $event)" @input="onFilterMetaChange(0, 'value', $event)"
data-test-id="execution-filter-saved-data-value-input" data-test-id="execution-filter-saved-data-value-input"
@ -328,7 +324,7 @@ onBeforeMount(() => {
text text
data-test-id="executions-filter-reset-button" data-test-id="executions-filter-reset-button"
> >
{{ $locale.baseText('executionsFilter.reset') }} {{ locale.baseText('executionsFilter.reset') }}
</n8n-button> </n8n-button>
</div> </div>
</n8n-popover> </n8n-popover>

View file

@ -4,7 +4,9 @@
<div :class="$style.execListHeader"> <div :class="$style.execListHeader">
<n8n-heading tag="h1" size="2xlarge">{{ this.pageTitle }}</n8n-heading> <n8n-heading tag="h1" size="2xlarge">{{ this.pageTitle }}</n8n-heading>
<div :class="$style.execListHeaderControls"> <div :class="$style.execListHeaderControls">
<n8n-loading v-if="isMounting" :class="$style.filterLoader" variant="custom" />
<el-checkbox <el-checkbox
v-else
class="mr-xl" class="mr-xl"
v-model="autoRefresh" v-model="autoRefresh"
@change="handleAutoRefreshToggle" @change="handleAutoRefreshToggle"
@ -12,7 +14,11 @@
> >
{{ $locale.baseText('executionsList.autoRefresh') }} {{ $locale.baseText('executionsList.autoRefresh') }}
</el-checkbox> </el-checkbox>
<execution-filter :workflows="workflows" @filterChanged="onFilterChanged" /> <execution-filter
v-show="!isMounting"
:workflows="workflows"
@filterChanged="onFilterChanged"
/>
</div> </div>
</div> </div>
@ -30,7 +36,12 @@
data-test-id="select-all-executions-checkbox" data-test-id="select-all-executions-checkbox"
/> />
<table :class="$style.execTable"> <div v-if="isMounting">
<n8n-loading :class="$style.tableLoader" variant="custom" />
<n8n-loading :class="$style.tableLoader" variant="custom" />
<n8n-loading :class="$style.tableLoader" variant="custom" />
</div>
<table v-else :class="$style.execTable">
<thead> <thead>
<tr> <tr>
<th> <th>
@ -210,7 +221,7 @@
</table> </table>
<div <div
v-if="!combinedExecutions.length" v-if="!combinedExecutions.length && !isMounting && !isDataLoading"
:class="$style.loadedAll" :class="$style.loadedAll"
data-test-id="execution-list-empty" data-test-id="execution-list-empty"
> >
@ -231,7 +242,11 @@
data-test-id="load-more-button" data-test-id="load-more-button"
/> />
</div> </div>
<div v-else :class="$style.loadedAll" data-test-id="execution-all-loaded"> <div
v-else-if="!isMounting && !isDataLoading"
:class="$style.loadedAll"
data-test-id="execution-all-loaded"
>
{{ $locale.baseText('executionsList.loadedAll') }} {{ $locale.baseText('executionsList.loadedAll') }}
</div> </div>
</div> </div>
@ -300,6 +315,7 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, showMessa
}, },
data() { data() {
return { return {
isMounting: true,
finishedExecutions: [] as IExecutionsSummary[], finishedExecutions: [] as IExecutionsSummary[],
finishedExecutionsCount: 0, finishedExecutionsCount: 0,
finishedExecutionsCountEstimated: false, finishedExecutionsCountEstimated: false,
@ -326,7 +342,6 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, showMessa
}, },
async created() { async created() {
await this.loadWorkflows(); await this.loadWorkflows();
//await this.refreshData();
this.handleAutoRefreshToggle(); this.handleAutoRefreshToggle();
this.$externalHooks().run('executionsList.openDialog'); this.$externalHooks().run('executionsList.openDialog');
@ -480,10 +495,11 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, showMessa
this.allExistingSelected = false; this.allExistingSelected = false;
Vue.set(this, 'selectedItems', {}); Vue.set(this, 'selectedItems', {});
}, },
onFilterChanged(filter: ExecutionFilterType) { async onFilterChanged(filter: ExecutionFilterType) {
this.filter = filter; this.filter = filter;
this.refreshData(); await this.refreshData();
this.handleClearSelection(); this.handleClearSelection();
this.isMounting = false;
}, },
handleActionItemClick(commandData: { command: string; execution: IExecutionsSummary }) { handleActionItemClick(commandData: { command: string; execution: IExecutionsSummary }) {
if (['currentlySaved', 'original'].includes(commandData.command)) { if (['currentlySaved', 'original'].includes(commandData.command)) {
@ -1134,4 +1150,15 @@ export default mixins(externalHooks, genericHelpers, executionHelpers, showMessa
margin: 0 0 var(--spacing-s) var(--spacing-s); margin: 0 0 var(--spacing-s) var(--spacing-s);
color: var(--color-danger); color: var(--color-danger);
} }
.filterLoader {
width: 220px;
height: 32px;
}
.tableLoader {
width: 100%;
height: 48px;
margin-bottom: var(--spacing-2xs);
}
</style> </style>