Skip to content
1 change: 1 addition & 0 deletions shell/components/ResourceList/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ export default {
v-else
:schema="schema"
:rows="rows"
:alt-loading="canPaginate"
:loading="loading"
:headers="headers"
:group-by="groupBy"
Expand Down
6 changes: 6 additions & 0 deletions shell/components/ResourceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ export default {
required: false
},

altLoading: {
type: Boolean,
required: false
},

keyField: {
// Field that is unique for each row.
type: String,
Expand Down Expand Up @@ -532,6 +537,7 @@ export default {
:headers="_headers"
:rows="filteredRows"
:loading="loading"
:alt-loading="altLoading"
:group-by="computedGroupBy"
:group="group"
:group-options="groupOptions"
Expand Down
74 changes: 60 additions & 14 deletions shell/components/SortableTable/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ export default {
required: false
},

/**
* Alt Loading - True: Always show table rows and obscure them when `loading`. Intended for use with server-side pagination.
*
* Alt Loading - False: Hide the table rows when `loading`. Intended when all resources are provided up front.
*/
altLoading: {
type: Boolean,
required: false
},

groupBy: {
// Field to group rows by, row[groupBy] must be something that can be a map key
type: String,
Expand Down Expand Up @@ -343,14 +353,18 @@ export default {
}

return {
currentPhase: ASYNC_BUTTON_STATES.WAITING,
refreshButtonPhase: ASYNC_BUTTON_STATES.WAITING,
expanded: {},
searchQuery,
eventualSearchQuery,
subMatches: null,
actionOfInterest: null,
loadingDelay: false,
debouncedPaginationChanged: null,
/**
* The is the bool the DOM uses to show loading state. it's proxied from `loading` to avoid blipping the indicator (see usages)
*/
isLoading: false,
};
},

Expand All @@ -369,9 +383,9 @@ export default {
},

beforeDestroy() {
clearTimeout(this.loadingDelayTimer);
clearTimeout(this._scrollTimer);
clearTimeout(this._loadingDelayTimer);
clearTimeout(this._altLoadingDelayTimer);
clearTimeout(this._liveColumnsTimer);
clearTimeout(this._delayedColumnsTimer);
clearTimeout(this.manualRefreshTimer);
Expand Down Expand Up @@ -444,13 +458,35 @@ export default {
manualRefreshLoadingFinished: {
handler(neu, old) {
// this is merely to update the manual refresh button status
this.currentPhase = !neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
this.refreshButtonPhase = !neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;
if (neu && neu !== old) {
this.$nextTick(() => this.updateLiveAndDelayed());
}
},
immediate: true
}
},

loading: {
handler(neu, old) {
// Always ensure the Refresh button phase aligns with loading state (to ensure external phase changes which can then reset the internal phase changed by click)
this.refreshButtonPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;

if (this.altLoading) {
// Delay setting the actual loading indicator. This should avoid flashing up the indicator if the API responds quickly
if (neu) {
this._altLoadingDelayTimer = setTimeout(() => {
this.isLoading = true;
}, 200); // this should be higher than the targetted quick response
} else {
clearTimeout(this._altLoadingDelayTimer);
this.isLoading = false;
}
} else {
this.isLoading = neu;
}
},
immediate: true
},
},

created() {
Expand All @@ -466,11 +502,16 @@ export default {
},

initalLoad() {
return !!(!this.loading && !this._didinit && this.rows?.length);
return !!(!this.isLoading && !this._didinit && this.rows?.length);
},

manualRefreshLoadingFinished() {
return !!(!this.loading && this._didinit && this.rows?.length && !this.isManualRefreshLoading);
const res = !!(!this.isLoading && this._didinit && this.rows?.length && !this.isManualRefreshLoading);

// Always ensure the Refresh button phase aligns with loading state (regardless of if manualRefreshLoadingFinished has changed or not)
this.refreshButtonPhase = !res || this.loading ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION;

return res;
},

fullColspan() {
Expand Down Expand Up @@ -570,6 +611,7 @@ export default {
'body-dividers': this.bodyDividers,
'overflow-y': this.overflowY,
'overflow-x': this.overflowX,
'alt-loading': this.altLoading && this.isLoading
};
},

Expand Down Expand Up @@ -1078,7 +1120,7 @@ export default {
v-if="isTooManyItemsToAutoUpdate"
class="manual-refresh"
mode="manual-refresh"
:current-phase="currentPhase"
:current-phase="refreshButtonPhase"
@click="debouncedRefreshTableData"
/>
<div
Expand Down Expand Up @@ -1171,7 +1213,7 @@ export default {
:default-sort-by="_defaultSortBy"
:descending="descending"
:no-rows="noRows"
:loading="loading && !loadingDelay"
:loading="isLoading && !loadingDelay"
:no-results="noResults"
@on-toggle-all="onToggleAll"
@on-sort-change="changeSort"
Expand All @@ -1181,9 +1223,9 @@ export default {
/>

<!-- Don't display anything if we're loading and the delay has yet to pass -->
<div v-if="loading && !loadingDelay" />
<div v-if="isLoading && !loadingDelay" />

<tbody v-else-if="loading">
<tbody v-else-if="isLoading && !altLoading">
<slot name="loading">
<tr>
<td :colspan="fullColspan">
Expand Down Expand Up @@ -1428,15 +1470,15 @@ export default {
<button
type="button"
class="btn btn-sm role-multi-action"
:disabled="page == 1"
:disabled="page == 1 || loading"
@click="goToPage('first')"
>
<i class="icon icon-chevron-beginning" />
</button>
<button
type="button"
class="btn btn-sm role-multi-action"
:disabled="page == 1"
:disabled="page == 1 || loading"
@click="goToPage('prev')"
>
<i class="icon icon-chevron-left" />
Expand All @@ -1447,15 +1489,15 @@ export default {
<button
type="button"
class="btn btn-sm role-multi-action"
:disabled="page == totalPages"
:disabled="page == totalPages || loading"
@click="goToPage('next')"
>
<i class="icon icon-chevron-right" />
</button>
<button
type="button"
class="btn btn-sm role-multi-action"
:disabled="page == totalPages"
:disabled="page == totalPages || loading"
@click="goToPage('last')"
>
<i class="icon icon-chevron-end" />
Expand Down Expand Up @@ -1494,6 +1536,10 @@ export default {
</template>

<style lang="scss" scoped>
.sortable-table.alt-loading {
opacity: 0.5;
pointer-events: none;
}

.manual-refresh {
height: 40px;
Expand Down
12 changes: 11 additions & 1 deletion shell/components/SortableTable/paging.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@ export default {
},

showPaging() {
return !this.loading && this.paging && this.totalPages > 1;
if (!this.paging) {
return false;
}

const havePages = this.totalPages > 1;

if (this.altLoading) {
return havePages;
}

return !this.loading && havePages;
},

pagingDisplay() {
Expand Down