Provisioning: Refactor createOnCacheEntryAdded (#105228)
* Provisioning: Refactor createOnCacheEntryAdded * Use custom list resource type * add generated types and transformers * Switch to type guards * Do not create new array
This commit is contained in:
@@ -3,18 +3,7 @@ import { isFetchError } from '@grafana/runtime';
|
||||
import { notifyApp } from 'app/core/actions';
|
||||
import { createSuccessNotification, createErrorNotification } from 'app/core/copy/appNotification';
|
||||
|
||||
import {
|
||||
generatedAPI,
|
||||
JobSpec,
|
||||
JobStatus,
|
||||
RepositorySpec,
|
||||
RepositoryStatus,
|
||||
Job,
|
||||
JobList,
|
||||
Repository,
|
||||
RepositoryList,
|
||||
ErrorDetails,
|
||||
} from './endpoints.gen';
|
||||
import { generatedAPI, JobSpec, JobStatus, RepositorySpec, RepositoryStatus, ErrorDetails } from './endpoints.gen';
|
||||
import { createOnCacheEntryAdded } from './utils/createOnCacheEntryAdded';
|
||||
|
||||
export const provisioningAPI = generatedAPI.enhanceEndpoints({
|
||||
@@ -26,16 +15,14 @@ export const provisioningAPI = generatedAPI.enhanceEndpoints({
|
||||
url: `/jobs`,
|
||||
params: queryArg,
|
||||
}),
|
||||
onCacheEntryAdded: createOnCacheEntryAdded<JobSpec, JobStatus, Job, JobList>('jobs'),
|
||||
onCacheEntryAdded: createOnCacheEntryAdded<JobSpec, JobStatus>('jobs'),
|
||||
},
|
||||
listRepository: {
|
||||
query: ({ watch, ...queryArg }) => ({
|
||||
url: `/repositories`,
|
||||
params: queryArg,
|
||||
}),
|
||||
onCacheEntryAdded: createOnCacheEntryAdded<RepositorySpec, RepositoryStatus, Repository, RepositoryList>(
|
||||
'repositories'
|
||||
),
|
||||
onCacheEntryAdded: createOnCacheEntryAdded<RepositorySpec, RepositoryStatus>('repositories'),
|
||||
},
|
||||
deleteRepository: {
|
||||
onQueryStarted: async (_, { queryFulfilled, dispatch }) => {
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { ScopedResourceClient } from '../../../../features/apiserver/client';
|
||||
import { ListOptions } from '../../../../features/apiserver/types';
|
||||
import { ListMeta, ObjectMeta } from '../endpoints.gen';
|
||||
import { ScopedResourceClient } from 'app/features/apiserver/client';
|
||||
import { ListOptions, GeneratedResourceList as ResourceList } from 'app/features/apiserver/types';
|
||||
|
||||
/**
|
||||
* Creates a cache entry handler for RTK Query that watches for changes to a resource
|
||||
* and updates the cache accordingly.
|
||||
*/
|
||||
export function createOnCacheEntryAdded<
|
||||
Spec,
|
||||
Status,
|
||||
T extends { spec?: Spec; status?: Status; metadata?: ObjectMeta },
|
||||
List extends { items?: T[]; metadata?: ListMeta },
|
||||
>(resourceName: string) {
|
||||
return async function onCacheEntryAdded(
|
||||
export function createOnCacheEntryAdded<Spec, Status>(resourceName: string) {
|
||||
return async function onCacheEntryAdded<List extends ResourceList<Spec, Status>>(
|
||||
arg: ListOptions | undefined,
|
||||
{
|
||||
updateCachedData,
|
||||
@@ -41,24 +35,24 @@ export function createOnCacheEntryAdded<
|
||||
// Wait for the initial query to resolve before proceeding
|
||||
const response = await cacheDataLoaded;
|
||||
const resourceVersion = response.data.metadata?.resourceVersion;
|
||||
|
||||
subscription = client.watch({ resourceVersion }).subscribe((event) => {
|
||||
updateCachedData((draft) => {
|
||||
if (!draft.items) {
|
||||
draft.items = [];
|
||||
}
|
||||
// Find the item with the matching name
|
||||
const existingIndex = draft.items.findIndex((item) => item.metadata?.name === event.object.metadata.name);
|
||||
|
||||
if (event.type === 'ADDED' && existingIndex === -1) {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
draft.items.push(event.object as unknown as T);
|
||||
draft.items.push(event.object);
|
||||
} else if (event.type === 'DELETED' && existingIndex !== -1) {
|
||||
// Remove the item if it exists
|
||||
draft.items.splice(existingIndex, 1);
|
||||
} else if (existingIndex !== -1) {
|
||||
// Could be ADDED or MODIFIED
|
||||
// Update the existing item if it exists
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
draft.items[existingIndex] = event.object as unknown as T;
|
||||
draft.items[existingIndex] = event.object;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Resource, ResourceList, GeneratedResource, GeneratedResourceList } from './types';
|
||||
|
||||
/**
|
||||
* Type guard to check if a GeneratedResource has all required fields to be a Resource
|
||||
*/
|
||||
export function isResource<T = object, S = object, K = string>(
|
||||
generated: GeneratedResource<T, S, K>
|
||||
): generated is Resource<T, S, K> {
|
||||
return (
|
||||
!!generated.apiVersion &&
|
||||
!!generated.kind &&
|
||||
!!generated.metadata?.name &&
|
||||
!!generated.metadata?.resourceVersion &&
|
||||
!!generated.metadata?.creationTimestamp &&
|
||||
!!generated.spec
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check if a GeneratedResourceList has all required fields to be a ResourceList
|
||||
*/
|
||||
export function isResourceList<T = object, S = object, K = string>(
|
||||
generatedList: GeneratedResourceList<T, S, K>
|
||||
): generatedList is ResourceList<T, S, K> {
|
||||
return !!generatedList.metadata?.resourceVersion && Array.isArray(generatedList.items);
|
||||
}
|
||||
@@ -257,3 +257,18 @@ export interface K8sAPIGroupList {
|
||||
kind: 'APIGroupList';
|
||||
groups: K8sAPIGroup[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic types to match the generated k8s API types in the RTK query clients
|
||||
*/
|
||||
export interface GeneratedObjectMeta extends Partial<ObjectMeta> {}
|
||||
export interface GeneratedResource<T = object, S = object, K = string> extends Partial<TypeMeta<K>> {
|
||||
metadata?: GeneratedObjectMeta;
|
||||
spec?: T;
|
||||
status?: S;
|
||||
}
|
||||
|
||||
export interface GeneratedResourceList<Spec, Status, K = string> {
|
||||
metadata?: Partial<ListMeta>;
|
||||
items?: Array<GeneratedResource<Spec, Status, K>>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user