From 866f4d80326a1cb1353d69f73dba67e360e376d4 Mon Sep 17 00:00:00 2001 From: Alexandre Alves <97888974+aalves08@users.noreply.github.com> Date: Sun, 9 Oct 2022 10:37:38 +0100 Subject: [PATCH] Add manual refresh + incremental loading to all list views (#6908) * removing check for restriction of types on incremental+manual + update masthead to incorportate directly the ResourceLoadingIndicator so that it can used by list views with custom mastheads + move catalog.clusterrepo typedescription to its rightful component and delete custom list view + updating custom list views to use resource-fetch mixin * continue updating custom list views to use resource-fetch mixin * finish updating custom list views to use resource-fetch mixin + prevent error on loadAdd mutation where type is not set in store yet + code cleanup * address PR comments * update all custom list views to use loading prop on ResourceTable rather than Loading component + use getter to get incremental updates propagated from the store into the table itself + other minor fixes * revert changes to mutation loadAdd as check is not needed * revert all changes to shell/list/harvesterhci.io.management.cluster.vue * revert deletion of clusterrepo due to CI/CD validation of plugin * add manual + refresh to namespaces list + fix issue where switching between workspaces results in the manual refresh button continually spinning * move rows and loading flag to resource-fetch and do necessary changes to custom lists to minimize code changes for the future * Minor fixes - Match existing loading check in projectnamespace list (had a check for currentCluster, probably not needed but added just in case) - Fixed masthead loading indicator for management users and features Co-authored-by: Alexandre Alves Co-authored-by: Alexandre Alves Co-authored-by: Richard Cox --- shell/assets/translations/en-us.yaml | 4 +- .../components/ExplorerProjectsNamespaces.vue | 23 ++++- shell/components/ResourceList/Masthead.vue | 22 ++++- .../ResourceList/ResourceLoadingIndicator.vue | 8 -- shell/components/ResourceList/index.vue | 32 ++----- shell/components/SortableTable/index.vue | 21 +++-- shell/components/TypeDescription.vue | 11 ++- shell/components/fleet/FleetClusters.vue | 6 ++ shell/components/fleet/FleetRepos.vue | 8 +- shell/config/product/manager.js | 2 - shell/list/catalog.cattle.io.app.vue | 19 +++-- shell/list/catalog.cattle.io.clusterrepo.vue | 67 ++------------- shell/list/cis.cattle.io.clusterscan.vue | 24 +++--- shell/list/fleet.cattle.io.bundle.vue | 61 +++++++------ shell/list/fleet.cattle.io.cluster.vue | 48 ++++++----- shell/list/fleet.cattle.io.clustergroup.vue | 6 ++ ...eet.cattle.io.clusterregistrationtoken.vue | 52 ++++++------ shell/list/fleet.cattle.io.gitrepo.vue | 39 ++++++--- .../list/helm.cattle.io.projecthelmchart.vue | 85 ++++++++++++------- .../logging.banzaicloud.io.clusterflow.vue | 19 ++--- shell/list/logging.banzaicloud.io.flow.vue | 21 ++--- shell/list/management.cattle.io.cluster.vue | 41 +++++---- shell/list/management.cattle.io.feature.vue | 21 +++-- shell/list/management.cattle.io.user.vue | 57 ++++++++----- ...nitoring.coreos.com.alertmanagerconfig.vue | 23 ++--- shell/list/namespace.vue | 15 +++- shell/list/node.vue | 29 +++---- shell/list/persistentvolume.vue | 25 ++++-- shell/list/persistentvolumeclaim.vue | 13 ++- shell/list/provisioning.cattle.io.cluster.vue | 42 +++++++-- shell/list/service.vue | 36 +++++--- shell/list/ui.cattle.io.navlink.vue | 6 ++ shell/list/workload.vue | 4 +- shell/mixins/resource-fetch.js | 30 +++---- 34 files changed, 510 insertions(+), 410 deletions(-) diff --git a/shell/assets/translations/en-us.yaml b/shell/assets/translations/en-us.yaml index a8863c5237..7a3e9a27fc 100644 --- a/shell/assets/translations/en-us.yaml +++ b/shell/assets/translations/en-us.yaml @@ -6174,7 +6174,7 @@ performance: label: Incremental Loading setting: You can configure the threshold above which incremental loading will be used. description: |- - When enabled, resources will appear more quickly, but it may take slightly longer to load the entire set of resources. This setting only applies to the following resources: Pods, Deployments, Cron Jobs, Daemon Sets, Jobs, Stateful Sets, Replica Sets, Replication Controllers, Workloads and Secrets. + When enabled, resources will appear more quickly, but it may take slightly longer to load the entire set of resources. This setting only applies to resources that come from the Kubernetes API checkboxLabel: Enable incremental loading inputLabel: Resource Threshold manualRefresh: @@ -6183,7 +6183,7 @@ performance: setting: You can configure a threshold above which manual refresh will be enabled. buttonTooltip: Refresh list description: |- - When enabled, list data will not auto-update but instead the user must manually trigger a list-view refresh. This setting only applies to the following resources: Pods, Deployments, Cron Jobs, Daemon Sets, Jobs, Stateful Sets, Replica Sets, Replication Controllers, Workloads and Secrets. + When enabled, list data will not auto-update but instead the user must manually trigger a list-view refresh. This setting only applies to resources that come from the Kubernetes API checkboxLabel: Enable manual refresh of data for lists inputLabel: Resource Threshold websocketNotification: diff --git a/shell/components/ExplorerProjectsNamespaces.vue b/shell/components/ExplorerProjectsNamespaces.vue index b2a3537b44..8fad21f034 100644 --- a/shell/components/ExplorerProjectsNamespaces.vue +++ b/shell/components/ExplorerProjectsNamespaces.vue @@ -10,12 +10,14 @@ import { mapPref, GROUP_RESOURCES, ALL_NAMESPACES } from '@shell/store/prefs'; import MoveModal from '@shell/components/MoveModal'; import { defaultTableSortGenerationFn } from '@shell/components/ResourceTable.vue'; import { NAMESPACE_FILTER_ALL_ORPHANS } from '@shell/utils/namespace-filter'; +import ResourceFetch from '@shell/mixins/resource-fetch'; export default { name: 'ListProjectNamespace', components: { Masthead, MoveModal, ResourceTable }, + mixins: [ResourceFetch], props: { createProjectLocationOverride: { @@ -42,14 +44,15 @@ export default { return; } - this.namespaces = await this.$store.dispatch(`${ inStore }/findAll`, { type: NAMESPACE }); + await this.$fetchType(NAMESPACE); this.projects = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PROJECT, opt: { force: true } }); }, data() { return { + loadResources: [NAMESPACE], + loadIndeterminate: true, schema: null, - namespaces: [], projects: [], projectSchema: null, MANAGEMENT, @@ -66,6 +69,17 @@ export default { computed: { ...mapGetters(['currentCluster', 'currentProduct']), + namespaces() { + const inStore = this.$store.getters['currentStore'](NAMESPACE); + + return this.$store.getters[`${ inStore }/all`](NAMESPACE); + }, + loading() { + return !this.currentCluster || this.namespaces.length ? false : this.$fetchState.pending; + }, + showIncrementalLoadingIndicator() { + return this.perfConfig?.incrementalLoading?.enabled; + }, isNamespaceCreatable() { return (this.schema?.collectionMethods || []).includes('POST'); }, @@ -309,6 +323,9 @@ export default { :favorite-resource="VIRTUAL_TYPES.PROJECT_NAMESPACES" :create-location="createProjectLocation" :create-button-label="t('projectNamespaces.createProject')" + :show-incremental-loading-indicator="showIncrementalLoadingIndicator" + :load-resources="loadResources" + :load-indeterminate="loadIndeterminate" /> [] + }, + + loadIndeterminate: { + type: Boolean, + default: false + }, + + showIncrementalLoadingIndicator: { + type: Boolean, + default: false + }, /** * Inherited global identifier prefix for tests @@ -155,7 +171,11 @@ export default {

{{ _typeDisplay }}

- +
diff --git a/shell/components/ResourceList/ResourceLoadingIndicator.vue b/shell/components/ResourceList/ResourceLoadingIndicator.vue index 30cb920d88..9e07fac3b7 100644 --- a/shell/components/ResourceList/ResourceLoadingIndicator.vue +++ b/shell/components/ResourceList/ResourceLoadingIndicator.vue @@ -16,10 +16,6 @@ export default { indeterminate: { type: Boolean, default: false, - }, - rows: { - type: Array, - default: undefined, } }, @@ -32,10 +28,6 @@ export default { computed: { // Count of rows - either from the data provided or from the rows for the first resource rowsCount() { - if (this.rows) { - return this.rows.length; - } - if (this.resources.length > 0) { const existingData = this.$store.getters[`${ this.inStore }/all`](this.resources[0]) || []; diff --git a/shell/components/ResourceList/index.vue b/shell/components/ResourceList/index.vue index 9e01d25e1e..0f71be3516 100644 --- a/shell/components/ResourceList/index.vue +++ b/shell/components/ResourceList/index.vue @@ -3,7 +3,7 @@ import ResourceTable from '@shell/components/ResourceTable'; import Loading from '@shell/components/Loading'; import Masthead from './Masthead'; import ResourceLoadingIndicator from './ResourceLoadingIndicator'; -import ResourceFetch, { TYPES_RESTRICTED } from '@shell/mixins/resource-fetch'; +import ResourceFetch from '@shell/mixins/resource-fetch'; export default { components: { @@ -43,8 +43,8 @@ export default { if (component?.$loadingResources) { const { loadResources, loadIndeterminate } = component?.$loadingResources(this.$route, this.$store); - this.loadResources = loadResources; - this.loadIndeterminate = loadIndeterminate; + this.loadResources = loadResources || [resource]; + this.loadIndeterminate = loadIndeterminate || false; } } @@ -55,11 +55,7 @@ export default { return; } - if (TYPES_RESTRICTED.includes(resource)) { - this.rows = await this.$fetchType(resource); - } else { - this.rows = await store.dispatch(`${ inStore }/findAll`, { type: resource }); - } + await this.$fetchType(resource); } }, @@ -75,13 +71,10 @@ export default { const showMasthead = getters[`type-map/optionsFor`](resource).showListMasthead; - const existingData = getters[`${ inStore }/all`](resource) || []; - return { inStore, schema, hasListComponent, - hasData: existingData.length > 0, showMasthead: showMasthead === undefined ? true : showMasthead, resource, // manual refresh @@ -89,7 +82,6 @@ export default { watch: false, force: false, // Provided by fetch later - rows: [], customTypeDisplay: null, // incremental loading loadResources: [resource], @@ -111,10 +103,6 @@ export default { return this.$store.getters['type-map/groupByFor'](this.schema); }, - loading() { - return this.hasData ? false : this.$fetchState.pending; - }, - showIncrementalLoadingIndicator() { return this.perfConfig?.incrementalLoading?.enabled; } @@ -142,18 +130,16 @@ export default { :type-display="customTypeDisplay" :schema="schema" :resource="resource" + :show-incremental-loading-indicator="showIncrementalLoadingIndicator" + :load-resources="loadResources" + :load-indeterminate="loadIndeterminate" > -
diff --git a/shell/components/SortableTable/index.vue b/shell/components/SortableTable/index.vue index 3243c26a24..04f19d9285 100644 --- a/shell/components/SortableTable/index.vue +++ b/shell/components/SortableTable/index.vue @@ -368,16 +368,19 @@ export default { immediate: true }, - isManualRefreshLoading(neu, old) { - this.currentPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION; + isManualRefreshLoading: { + handler(neu, old) { + this.currentPhase = neu ? ASYNC_BUTTON_STATES.WAITING : ASYNC_BUTTON_STATES.ACTION; - // setTimeout is needed so that this is pushed further back on the JS computing queue - // because nextTick isn't enough to capture the DOM update for the manual refresh only scenario - if (old && !neu) { - this.manualRefreshTimer = setTimeout(() => { - this.watcherUpdateLiveAndDelayed(neu, old); - }, 1000); - } + // setTimeout is needed so that this is pushed further back on the JS computing queue + // because nextTick isn't enough to capture the DOM update for the manual refresh only scenario + if (old && !neu) { + this.manualRefreshTimer = setTimeout(() => { + this.watcherUpdateLiveAndDelayed(neu, old); + }, 1000); + } + }, + immediate: true } }, diff --git a/shell/components/TypeDescription.vue b/shell/components/TypeDescription.vue index 217d9b6d1f..2173e8cb94 100644 --- a/shell/components/TypeDescription.vue +++ b/shell/components/TypeDescription.vue @@ -1,7 +1,9 @@