Add server-side pagination to cluster explorer events and general events list

This commit is contained in:
Richard Cox 2024-08-20 14:38:10 +01:00
parent a0a6883a7b
commit 8b03d567f0
11 changed files with 148 additions and 48 deletions

View File

@ -89,13 +89,13 @@ export default {
const hasListComponent = getters['type-map/hasCustomList'](resource);
const inStore = getters['currentStore'](resource);
const schema = getters[`${ inStore }/schemaFor`](resource);
const derpinStore = getters['currentStore'](resource); // TODO: RC fix in parent commit (dupe inStore props)
const schema = getters[`${ derpinStore }/schemaFor`](resource);
const showMasthead = getters[`type-map/optionsFor`](resource).showListMasthead;
return {
inStore,
// inStore,
schema,
hasListComponent,
showMasthead: showMasthead === undefined ? true : showMasthead,

View File

@ -553,7 +553,8 @@ export default {
this.tableActions ||
this.$scopedSlots['header-left'] ||
this.$scopedSlots['header-middle'] ||
this.$scopedSlots['header-right'];
this.$scopedSlots['header-right'] ||
this.isTooManyItemsToAutoUpdate;
},
columns() {

View File

@ -1,4 +1,6 @@
import { STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE } from '@shell/config/table-headers';
import {
STATE, NAME as NAME_COL, NAMESPACE as NAMESPACE_COL, AGE, OBJECT
} from '@shell/config/table-headers';
// This file contains table headers
// These table headers are used for server side pagination
@ -44,6 +46,11 @@ export const STEVE_NAMESPACE_COL = {
search: 'metadata.namespace',
};
export const STEVE_EVENT_OBJECT = {
...OBJECT,
sort: 'involvedObject.kind',
};
export const STEVE_LIST_GROUPS = [{
tooltipKey: 'resourceTable.groupBy.none',
icon: 'icon-list-flat',

View File

@ -25,7 +25,7 @@ import {
import { DSL } from '@shell/store/type-map';
import {
STEVE_AGE_COL, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
STEVE_AGE_COL, STEVE_EVENT_OBJECT, STEVE_LIST_GROUPS, STEVE_NAMESPACE_COL, STEVE_NAME_COL, STEVE_STATE_COL
} from '@shell/config/pagination-table-headers';
import { COLUMN_BREAKPOINTS } from '@shell/types/store/type-map';
@ -182,7 +182,7 @@ export function init(store) {
configureType(SNAPSHOT, { depaginate: true });
configureType(NORMAN.ETCD_BACKUP, { depaginate: true });
configureType(EVENT, { limit: 500 });
// configureType(EVENT, { limit: 500 }); // TODO: RC search for where EVENT is requested
weightType(EVENT, -1, true);
configureType(POD, {
@ -256,7 +256,35 @@ export function init(store) {
headers(INGRESS, [STATE, NAME_COL, NAMESPACE_COL, INGRESS_TARGET, INGRESS_DEFAULT_BACKEND, INGRESS_CLASS, AGE]);
headers(SERVICE, [STATE, NAME_COL, NAMESPACE_COL, TARGET_PORT, SELECTOR, SPEC_TYPE, AGE]);
headers(EVENT, [STATE, { ...LAST_SEEN_TIME, defaultSort: true }, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, 'First Seen', 'Count', NAME_COL, NAMESPACE_COL]);
const eventLastSeenTime = {
...LAST_SEEN_TIME,
defaultSort: true,
};
headers(EVENT,
[STATE, eventLastSeenTime, EVENT_TYPE, REASON, OBJECT, 'Subobject', 'Source', MESSAGE, 'First Seen', 'Count', NAME_COL, NAMESPACE_COL],
[
STEVE_STATE_COL, {
...eventLastSeenTime,
value: 'metadata.fields.0',
sort: 'metadata.fields.0',
}, {
...EVENT_TYPE,
value: '_type',
sort: '_type', // TODO: RC API request
},
REASON,
STEVE_EVENT_OBJECT,
'Subobject',
'Source',
MESSAGE,
'First Seen',
'Count',
STEVE_NAME_COL,
STEVE_NAMESPACE_COL,
]
);
headers(HPA, [STATE, NAME_COL, HPA_REFERENCE, MIN_REPLICA, MAX_REPLICA, CURRENT_REPLICA, AGE]);
headers(WORKLOAD, [STATE, NAME_COL, NAMESPACE_COL, TYPE, WORKLOAD_IMAGES, WORKLOAD_ENDPOINTS, POD_RESTARTS, AGE, WORKLOAD_HEALTH_SCALE]);
headers(WORKLOAD_TYPES.DEPLOYMENT, [STATE, NAME_COL, NAMESPACE_COL, WORKLOAD_IMAGES, WORKLOAD_ENDPOINTS, 'Ready', 'Up-to-date', 'Available', POD_RESTARTS, AGE, WORKLOAD_HEALTH_SCALE]);

View File

@ -1,7 +1,7 @@
// Settings
import { GC_DEFAULTS, GC_PREFERENCES } from '@shell/utils/gc/gc-types';
import { PaginationSettings } from '@shell/types/resources/settings';
import { CAPI } from 'config/types';
import { CAPI, EVENT, SCHEMA, NAMESPACE } from '@shell/config/types';
interface GlobalSettingRuleset {
name: string,
@ -250,8 +250,8 @@ export const DEFAULT_PERF_SETTING: PerfSettings = {
resources: {
enableAll: false,
enableSome: {
enabled: ['configmap', 'secret', 'pod', 'node'],
generic: true,
enabled: ['configmap', 'secret', 'pod', 'node', EVENT],
generic: false,
}
}
},

View File

@ -317,9 +317,12 @@ export default {
return;
}
await this.fetchPageSecondaryResources({
canPaginate: this.canPaginate, force: false, page: this.rows, pagResult: this.paginationResult
});
// TODO: RC fix in parent commit (make calls to fetchPageX null safe)
if (this.fetchPageSecondaryResources) {
await this.fetchPageSecondaryResources({
canPaginate: this.canPaginate, force: false, page: this.rows, pagResult: this.paginationResult
});
}
}
},
};

View File

@ -1,16 +1,14 @@
<script>
import SortableTable from '@shell/components/SortableTable';
import { MESSAGE, NAME, OBJECT, REASON } from '@shell/config/table-headers';
import { EVENT } from '@shell/config/types';
import { fetchClusterResources } from './explorer-utils';
import PaginatedResourceTable from '@shell/components/PaginatedResourceTable.vue';
import { STEVE_EVENT_OBJECT, STEVE_NAME_COL } from '@shell/config/pagination-table-headers';
import { headerFromSchemaColString } from '@shell/store/type-map.utils';
import { NAME as EXPLORER } from '@shell/config/product/explorer';
export default {
components: { SortableTable },
async fetch() {
this.events = await fetchClusterResources(this.$store, EVENT);
},
components: { PaginatedResourceTable },
data() {
const reason = {
@ -23,8 +21,7 @@ export default {
reason,
OBJECT,
MESSAGE,
NAME,
{
NAME, {
name: 'date',
label: 'Date',
labelKey: 'clusterIndexPage.sections.events.date.label',
@ -36,9 +33,36 @@ export default {
},
];
const schema = this.$store.getters['cluster/schemaFor'](EVENT);
const paginationHeaders = [
reason,
STEVE_EVENT_OBJECT,
MESSAGE,
{
...STEVE_NAME_COL,
defaultSort: false,
},
headerFromSchemaColString('First Seen', schema, this.$store.getters, true),
{
...headerFromSchemaColString('Last Seen', schema, this.$store.getters, true),
defaultSort: true,
},
headerFromSchemaColString('Count', schema, this.$store.getters, true),
];
return {
events: [],
schema,
events: [],
eventHeaders,
paginationHeaders,
allEventsLink: {
name: 'c-cluster-product-resource',
params: {
product: EXPLORER,
resource: EVENT,
}
}
};
},
@ -63,16 +87,35 @@ export default {
</script>
<template>
<SortableTable
:loading="$fetchState.pending"
:rows="events"
<!-- TODO: RC test paging (create events) -->
<!-- TODO: RC test no-vai again -->
<PaginatedResourceTable
:schema="schema"
:headers="eventHeaders"
:pagination-headers="paginationHeaders"
key-field="id"
:search="false"
:table-actions="false"
:row-actions="false"
:paging="true"
:groupable="false"
:rows-per-page="10"
default-sort-by="date"
/>
>
<template slot="header-right">
<router-link
:to="allEventsLink"
class="events-link"
>
<span>{{ t('glance.eventsTable') }}</span>
</router-link>
</template>
</PaginatedResourceTable>
</template>
<style lang="scss" scoped>
.events-link {
align-self: center;
padding-right: 20px;
min-width: 200px;
}
</style>

View File

@ -459,16 +459,6 @@ export default {
return !!this.currentCluster?.spec?.description;
},
allEventsLink() {
return {
name: 'c-cluster-product-resource',
params: {
product: EXPLORER,
resource: EVENT,
}
};
},
allSecretsLink() {
return {
name: 'c-cluster-product-resource',
@ -723,11 +713,6 @@ export default {
:label="t('clusterIndexPage.sections.events.label')"
:weight="2"
>
<span class="events-table-link">
<router-link :to="allEventsLink">
<span>{{ t('glance.eventsTable') }}</span>
</router-link>
</span>
<EventsTable />
</Tab>
<Tab
@ -888,7 +873,7 @@ export default {
}
}
.events-table-link, .cert-table-link {
.cert-table-link {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;

View File

@ -5,6 +5,7 @@ import AsyncButton from '@shell/components/AsyncButton';
import { Banner } from '@components/Banner';
import { LabeledInput } from '@components/Form/LabeledInput';
import { MANAGEMENT } from '@shell/config/types';
import Vue from 'vue';
import { DEFAULT_PERF_SETTING, SETTING } from '@shell/config/settings';
import { _EDIT, _VIEW } from '@shell/config/query-params';
import UnitInput from '@shell/components/form/UnitInput';
@ -185,6 +186,11 @@ export default {
body: this.t(`performance.${ l10n[property] }.incompatibleDescription`, {}, true),
},
});
},
setDefaults() {
Vue.set(this, 'value', { ...DEFAULT_PERF_SETTING });
console.warn(this.value, DEFAULT_PERF_SETTING);
}
},
};
@ -196,6 +202,14 @@ export default {
<h1 class="mb-20">
{{ t('performance.label') }}
</h1>
<button
class="btn btn-sm role-primary"
style="width: fit-content;"
@click.prevent="setDefaults()"
>
<!-- TODO: RC tidy -->
Populate with Defaults
</button>
<div>
<div class="ui-perf-setting">
<!-- Server Side Pagination -->

View File

@ -5,7 +5,7 @@ import Namespace from '@shell/models/namespace';
import { uniq } from '@shell/utils/array';
import {
CAPI,
CONFIG_MAP, MANAGEMENT, NAMESPACE, NODE, POD
CONFIG_MAP, EVENT, MANAGEMENT, NAMESPACE, NODE, POD
} from '@shell/config/types';
import { Schema } from 'plugins/steve/schema';
@ -144,6 +144,12 @@ class StevePaginationUtils extends NamespaceProjectFilters {
// { field: 'status.allocatable.cpu' } // Pending API support // TODO: RC
// { field: 'status.allocatable.memory' } // Pending API support // TODO: RC
// { field: 'status.allocatable.pods' } // Pending API support // TODO: RC
],
[EVENT]: [
// { field: '_type' }, // Pending API support // TODO: RC
// { field: 'reason' }, // Pending API support // TODO: RC
// { field: 'involvedObject.kind' }, // Pending API support // TODO: RC
// { field: 'message' }, // Pending API support // TODO: RC
]
}

View File

@ -1,4 +1,4 @@
import { SchemaAttribute, SchemaAttributeColumn } from '@shell/plugins/steve/schema';
import { Schema, SchemaAttribute, SchemaAttributeColumn } from '@shell/plugins/steve/schema';
import { TableColumn } from '@shell/types/store/type-map';
import { VuexStoreGetters } from '@shell/types/store/vuex';
import { findBy, insertAt, removeObject } from '@shell/utils/array';
@ -119,6 +119,19 @@ export function createHeaders(
return out;
}
/**
* Given a schema's attribute.column value create a header
*/
export function headerFromSchemaColString(colName: string, schema: Schema, rootGetters: VuexStoreGetters, pagination: boolean, ageColumn: TableColumn): TableColumn {
const col = schema.attributes.columns.find((c) => c.name === colName);
if (!col) {
throw new Error(`Unable to find column '${ colName }' in schema '${ schema.id }'`);
}
return headerFromSchemaCol(col, rootGetters, pagination, ageColumn);
}
/**
* Given a schema's attribute.column value create a header
*/