mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-17 01:17:29 +02:00
feat: paginated hook for applications list (#6315)
This commit is contained in:
parent
fb63f21d8a
commit
edbd71ac15
@ -13,12 +13,18 @@ import { IconCell } from 'component/common/Table/cells/IconCell/IconCell';
|
||||
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||
import { ApplicationUsageCell } from './ApplicationUsageCell/ApplicationUsageCell';
|
||||
import { ApplicationSchema } from '../../../openapi';
|
||||
import { NumberParam, StringParam, withDefault } from 'use-query-params';
|
||||
import {
|
||||
encodeQueryParams,
|
||||
NumberParam,
|
||||
StringParam,
|
||||
withDefault,
|
||||
} from 'use-query-params';
|
||||
import { DEFAULT_PAGE_LIMIT } from 'hooks/api/getters/useProjectApplications/useProjectApplications';
|
||||
import { usePersistentTableState } from 'hooks/usePersistentTableState';
|
||||
import { createColumnHelper, useReactTable } from '@tanstack/react-table';
|
||||
import { withTableState } from 'utils/withTableState';
|
||||
import useLoading from 'hooks/useLoading';
|
||||
import mapValues from 'lodash.mapvalues';
|
||||
|
||||
const renderNoApplications = () => (
|
||||
<>
|
||||
@ -42,9 +48,6 @@ const renderNoApplications = () => (
|
||||
const columnHelper = createColumnHelper<ApplicationSchema>();
|
||||
|
||||
export const PaginatedApplicationList = () => {
|
||||
const { applications: data, loading } = useApplications();
|
||||
const total = 1000;
|
||||
|
||||
const stateConfig = {
|
||||
offset: withDefault(NumberParam, 0),
|
||||
limit: withDefault(NumberParam, DEFAULT_PAGE_LIMIT),
|
||||
@ -56,11 +59,21 @@ export const PaginatedApplicationList = () => {
|
||||
`applications-table`,
|
||||
stateConfig,
|
||||
);
|
||||
const {
|
||||
applications: data,
|
||||
total,
|
||||
loading,
|
||||
} = useApplications(
|
||||
mapValues(encodeQueryParams(stateConfig, tableState), (value) =>
|
||||
value ? `${value}` : undefined,
|
||||
),
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
columnHelper.accessor('icon', {
|
||||
id: 'Icon',
|
||||
header: () => '',
|
||||
cell: ({
|
||||
row: {
|
||||
original: { icon },
|
||||
@ -74,6 +87,7 @@ export const PaginatedApplicationList = () => {
|
||||
}
|
||||
/>
|
||||
),
|
||||
enableSorting: false,
|
||||
}),
|
||||
columnHelper.accessor('appName', {
|
||||
header: 'Name',
|
||||
@ -93,6 +107,7 @@ export const PaginatedApplicationList = () => {
|
||||
columnHelper.accessor('usage', {
|
||||
header: 'Project(environment)',
|
||||
meta: { width: '50%' },
|
||||
enableSorting: false,
|
||||
cell: ({
|
||||
row: { original },
|
||||
}: {
|
||||
|
@ -13,12 +13,11 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
||||
import styles from '../../strategies.module.scss';
|
||||
import { TogglesLinkList } from 'component/strategies/TogglesLinkList/TogglesLinkList';
|
||||
import { IStrategy, IStrategyParameter } from 'interfaces/strategy';
|
||||
import { IApplication } from 'interfaces/application';
|
||||
import { FeatureSchema } from 'openapi';
|
||||
import { ApplicationSchema, FeatureSchema } from 'openapi';
|
||||
|
||||
interface IStrategyDetailsProps {
|
||||
strategy: IStrategy;
|
||||
applications: IApplication[];
|
||||
applications: ApplicationSchema[];
|
||||
toggles: FeatureSchema[];
|
||||
}
|
||||
|
||||
|
@ -1,40 +1,49 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { IApplication } from 'interfaces/application';
|
||||
import { ApplicationsSchema, GetApplicationsParams } from '../../../../openapi';
|
||||
import { useClearSWRCache } from '../../../useClearSWRCache';
|
||||
|
||||
const path = formatApiPath('api/admin/metrics/applications');
|
||||
|
||||
interface IUseApplicationsOutput {
|
||||
applications: IApplication[];
|
||||
interface IUseApplicationsOutput extends ApplicationsSchema {
|
||||
refetchApplications: () => void;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
APPLICATIONS_CACHE_KEY: string;
|
||||
}
|
||||
|
||||
const PREFIX_KEY = 'api/admin/metrics/applications?';
|
||||
|
||||
const useApplications = (
|
||||
params: GetApplicationsParams = {},
|
||||
options: SWRConfiguration = {},
|
||||
): IUseApplicationsOutput => {
|
||||
const urlSearchParams = new URLSearchParams(
|
||||
Array.from(
|
||||
Object.entries(params)
|
||||
.filter(([_, value]) => !!value)
|
||||
.map(([key, value]) => [key, value.toString()]),
|
||||
),
|
||||
).toString();
|
||||
|
||||
const KEY = `${PREFIX_KEY}${urlSearchParams}`;
|
||||
useClearSWRCache(KEY, PREFIX_KEY);
|
||||
|
||||
const fetcher = async () => {
|
||||
return fetch(path, {
|
||||
return fetch(formatApiPath(KEY), {
|
||||
method: 'GET',
|
||||
})
|
||||
.then(handleErrorResponses('Applications data'))
|
||||
.then((res) => res.json());
|
||||
};
|
||||
|
||||
const APPLICATIONS_CACHE_KEY = 'api/admin/metrics/applications';
|
||||
|
||||
const { data, error } = useSWR(APPLICATIONS_CACHE_KEY, fetcher, {
|
||||
const { data, error } = useSWR(KEY, fetcher, {
|
||||
...options,
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(!error && !data);
|
||||
|
||||
const refetchApplications = () => {
|
||||
mutate(APPLICATIONS_CACHE_KEY);
|
||||
mutate(KEY);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -43,10 +52,10 @@ const useApplications = (
|
||||
|
||||
return {
|
||||
applications: data?.applications || [],
|
||||
total: data?.total || 0,
|
||||
error,
|
||||
loading,
|
||||
refetchApplications,
|
||||
APPLICATIONS_CACHE_KEY,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import useSWR, { SWRConfiguration, useSWRConfig } from 'swr';
|
||||
import useSWR, { SWRConfiguration } from 'swr';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { SearchFeaturesParams, SearchFeaturesSchema } from 'openapi';
|
||||
import { useClearSWRCache } from 'hooks/useClearSWRCache';
|
||||
|
||||
type UseFeatureSearchOutput = {
|
||||
loading: boolean;
|
||||
@ -26,19 +27,6 @@ const fallbackData: SearchFeaturesSchema = {
|
||||
|
||||
const PREFIX_KEY = 'api/admin/search/features?';
|
||||
|
||||
/**
|
||||
With dynamic search and filter parameters we want to prevent cache from growing extensively.
|
||||
We only keep the latest cache key `currentKey` and remove all other entries identified
|
||||
by the `clearPrefix`
|
||||
*/
|
||||
const useClearSWRCache = (currentKey: string, clearPrefix: string) => {
|
||||
const { cache } = useSWRConfig();
|
||||
const keys = [...cache.keys()];
|
||||
keys.filter((key) => key !== currentKey && key.startsWith(clearPrefix)).map(
|
||||
(key) => cache.delete(key),
|
||||
);
|
||||
};
|
||||
|
||||
const createFeatureSearch = () => {
|
||||
const internalCache: InternalCache = {};
|
||||
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
GetProjectApplicationsParams,
|
||||
ProjectApplicationsSchema,
|
||||
} from 'openapi';
|
||||
import { useClearSWRCache } from 'hooks/useClearSWRCache';
|
||||
|
||||
type UseProjectApplicationsOutput = {
|
||||
loading: boolean;
|
||||
@ -66,6 +67,7 @@ const getProjectApplicationsFetcher = (
|
||||
),
|
||||
).toString();
|
||||
const KEY = `${getPrefixKey(projectId)}${urlSearchParams}`;
|
||||
useClearSWRCache(KEY, getPrefixKey(projectId));
|
||||
const fetcher = () => {
|
||||
const path = formatApiPath(KEY);
|
||||
return fetch(path, {
|
||||
|
14
frontend/src/hooks/useClearSWRCache.ts
Normal file
14
frontend/src/hooks/useClearSWRCache.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { useSWRConfig } from 'swr';
|
||||
|
||||
/**
|
||||
With dynamic search and filter parameters we want to prevent cache from growing extensively.
|
||||
We only keep the latest cache key `currentKey` and remove all other entries identified
|
||||
by the `clearPrefix`
|
||||
*/
|
||||
export const useClearSWRCache = (currentKey: string, clearPrefix: string) => {
|
||||
const { cache } = useSWRConfig();
|
||||
const keys = [...cache.keys()];
|
||||
keys.filter((key) => key !== currentKey && key.startsWith(clearPrefix)).map(
|
||||
(key) => cache.delete(key),
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user