mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-20 00:08:02 +01:00
feat: connect sort table to backend (#5338)
Now FE sorting is done in backend.
This commit is contained in:
parent
db77962a72
commit
4e1040c849
@ -63,11 +63,18 @@ import { ListItemType } from './ProjectFeatureToggles.types';
|
||||
import { createFeatureToggleCell } from './FeatureToggleSwitch/createFeatureToggleCell';
|
||||
import { useFeatureToggleSwitch } from './FeatureToggleSwitch/useFeatureToggleSwitch';
|
||||
import useLoading from 'hooks/useLoading';
|
||||
import { DEFAULT_PAGE_LIMIT } from '../ProjectOverview';
|
||||
|
||||
const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
|
||||
whiteSpace: 'nowrap',
|
||||
}));
|
||||
|
||||
export interface ISortingRules {
|
||||
sortBy: string;
|
||||
sortOrder: 'asc' | 'desc';
|
||||
isFavoritesPinned: boolean;
|
||||
}
|
||||
|
||||
interface IPaginatedProjectFeatureTogglesProps {
|
||||
features: IProject['features'];
|
||||
environments: IProject['environments'];
|
||||
@ -78,6 +85,8 @@ interface IPaginatedProjectFeatureTogglesProps {
|
||||
searchValue: string;
|
||||
setSearchValue: React.Dispatch<React.SetStateAction<string>>;
|
||||
paginationBar: JSX.Element;
|
||||
sortingRules: ISortingRules;
|
||||
setSortingRules: (sortingRules: ISortingRules) => void;
|
||||
}
|
||||
|
||||
const staticColumns = ['Select', 'Actions', 'name', 'favorite'];
|
||||
@ -96,6 +105,8 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
paginationBar,
|
||||
sortingRules,
|
||||
setSortingRules,
|
||||
}: IPaginatedProjectFeatureTogglesProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const bodyLoadingRef = useLoading(loading);
|
||||
@ -223,7 +234,11 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
Cell: ({ value }: { value: string }) => (
|
||||
Cell: ({
|
||||
value,
|
||||
}: {
|
||||
value: string;
|
||||
}) => (
|
||||
<Tooltip title={value} arrow describeChild>
|
||||
<span>
|
||||
<LinkCell
|
||||
@ -285,7 +300,7 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
return {
|
||||
Header: loading ? () => '' : name,
|
||||
maxWidth: 90,
|
||||
id: `environments.${name}`,
|
||||
id: `environment:${name}`,
|
||||
accessor: (row: ListItemType) =>
|
||||
row.environments[name]?.enabled,
|
||||
align: 'center',
|
||||
@ -301,7 +316,11 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
id: 'Actions',
|
||||
maxWidth: 56,
|
||||
width: 56,
|
||||
Cell: (props: { row: { original: ListItemType } }) => (
|
||||
Cell: (props: {
|
||||
row: {
|
||||
original: ListItemType;
|
||||
};
|
||||
}) => (
|
||||
<ActionsCell
|
||||
projectId={projectId}
|
||||
onOpenArchiveDialog={setFeatureArchiveState}
|
||||
@ -372,7 +391,10 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
name: `Feature name ${index}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
environments: {
|
||||
production: { name: 'production', enabled: false },
|
||||
production: {
|
||||
name: 'production',
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}));
|
||||
// Coerce loading data to FeatureSchema[]
|
||||
@ -419,7 +441,7 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
id:
|
||||
searchParams.get('sort') ||
|
||||
storedParams.id ||
|
||||
'createdAt',
|
||||
sortingRules.sortBy,
|
||||
desc: searchParams.has('order')
|
||||
? searchParams.get('order') === 'desc'
|
||||
: storedParams.desc,
|
||||
@ -462,10 +484,12 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
const sortedByColumn = sortBy[0].id;
|
||||
const sortOrder = sortBy[0].desc ? 'desc' : 'asc';
|
||||
const tableState: Record<string, string> = {};
|
||||
tableState.sort = sortBy[0].id;
|
||||
tableState.sort = sortedByColumn;
|
||||
if (sortBy[0].desc) {
|
||||
tableState.order = 'desc';
|
||||
tableState.order = sortOrder;
|
||||
}
|
||||
if (searchValue) {
|
||||
tableState.search = searchValue;
|
||||
@ -490,10 +514,17 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
desc: sortBy[0].desc || false,
|
||||
columns: tableState.columns.split(','),
|
||||
}));
|
||||
const favoritesPinned = Boolean(isFavoritesPinned);
|
||||
setGlobalStore((params) => ({
|
||||
...params,
|
||||
favorites: Boolean(isFavoritesPinned),
|
||||
favorites: favoritesPinned,
|
||||
}));
|
||||
setSortingRules({
|
||||
sortBy: sortedByColumn,
|
||||
sortOrder,
|
||||
isFavoritesPinned: favoritesPinned,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
loading,
|
||||
@ -504,9 +535,12 @@ export const PaginatedProjectFeatureToggles = ({
|
||||
isFavoritesPinned,
|
||||
]);
|
||||
|
||||
const showPaginationBar = Boolean(total && total > 25);
|
||||
const showPaginationBar = Boolean(total && total > DEFAULT_PAGE_LIMIT);
|
||||
const style = showPaginationBar
|
||||
? { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }
|
||||
? {
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
}
|
||||
: {};
|
||||
|
||||
return (
|
||||
|
@ -12,10 +12,14 @@ import { ProjectStats } from './ProjectStats/ProjectStats';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
|
||||
import { PaginatedProjectFeatureToggles } from './ProjectFeatureToggles/PaginatedProjectFeatureToggles';
|
||||
import {
|
||||
ISortingRules,
|
||||
PaginatedProjectFeatureToggles,
|
||||
} from './ProjectFeatureToggles/PaginatedProjectFeatureToggles';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { PaginationBar } from 'component/common/PaginationBar/PaginationBar';
|
||||
import { SortingRule } from 'react-table';
|
||||
|
||||
const refreshInterval = 15 * 1000;
|
||||
|
||||
@ -38,28 +42,43 @@ const StyledContentContainer = styled(Box)(() => ({
|
||||
minWidth: 0,
|
||||
}));
|
||||
|
||||
export const DEFAULT_PAGE_LIMIT = 25;
|
||||
|
||||
const PaginatedProjectOverview = () => {
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const { project, loading: projectLoading } = useProject(projectId, {
|
||||
refreshInterval,
|
||||
});
|
||||
const [pageLimit, setPageLimit] = useState(25);
|
||||
const [pageLimit, setPageLimit] = useState(DEFAULT_PAGE_LIMIT);
|
||||
const [currentOffset, setCurrentOffset] = useState(0);
|
||||
|
||||
const [searchValue, setSearchValue] = useState(
|
||||
searchParams.get('search') || '',
|
||||
);
|
||||
|
||||
const [sortingRules, setSortingRules] = useState<ISortingRules>({
|
||||
sortBy: 'createdBy',
|
||||
sortOrder: 'desc',
|
||||
isFavoritesPinned: false,
|
||||
});
|
||||
|
||||
const {
|
||||
features: searchFeatures,
|
||||
total,
|
||||
refetch,
|
||||
loading,
|
||||
initialLoad,
|
||||
} = useFeatureSearch(currentOffset, pageLimit, projectId, searchValue, {
|
||||
refreshInterval,
|
||||
});
|
||||
} = useFeatureSearch(
|
||||
currentOffset,
|
||||
pageLimit,
|
||||
sortingRules,
|
||||
projectId,
|
||||
searchValue,
|
||||
{
|
||||
refreshInterval,
|
||||
},
|
||||
);
|
||||
|
||||
const { members, features, health, description, environments, stats } =
|
||||
project;
|
||||
@ -102,6 +121,8 @@ const PaginatedProjectOverview = () => {
|
||||
total={total}
|
||||
searchValue={searchValue}
|
||||
setSearchValue={setSearchValue}
|
||||
sortingRules={sortingRules}
|
||||
setSortingRules={setSortingRules}
|
||||
paginationBar={
|
||||
<StickyPaginationBar>
|
||||
<PaginationBar
|
||||
|
@ -4,6 +4,7 @@ import { IFeatureToggleListItem } from 'interfaces/featureToggle';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { translateToQueryParams } from './searchToQueryParams';
|
||||
import { ISortingRules } from 'component/project/Project/ProjectFeatureToggles/PaginatedProjectFeatureToggles';
|
||||
|
||||
type IFeatureSearchResponse = {
|
||||
features: IFeatureToggleListItem[];
|
||||
@ -62,6 +63,7 @@ const createFeatureSearch = () => {
|
||||
return (
|
||||
offset: number,
|
||||
limit: number,
|
||||
sortingRules: ISortingRules,
|
||||
projectId = '',
|
||||
searchValue = '',
|
||||
options: SWRConfiguration = {},
|
||||
@ -71,6 +73,7 @@ const createFeatureSearch = () => {
|
||||
offset,
|
||||
limit,
|
||||
searchValue,
|
||||
sortingRules,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -113,9 +116,11 @@ const getFeatureSearchFetcher = (
|
||||
offset: number,
|
||||
limit: number,
|
||||
searchValue: string,
|
||||
sortingRules: ISortingRules,
|
||||
) => {
|
||||
const searchQueryParams = translateToQueryParams(searchValue);
|
||||
const KEY = `api/admin/search/features?projectId=${projectId}&offset=${offset}&limit=${limit}&${searchQueryParams}`;
|
||||
const sortQueryParams = translateToSortQueryParams(sortingRules);
|
||||
const KEY = `api/admin/search/features?projectId=${projectId}&offset=${offset}&limit=${limit}&${searchQueryParams}&${sortQueryParams}`;
|
||||
const fetcher = () => {
|
||||
const path = formatApiPath(KEY);
|
||||
return fetch(path, {
|
||||
@ -130,3 +135,9 @@ const getFeatureSearchFetcher = (
|
||||
KEY,
|
||||
};
|
||||
};
|
||||
|
||||
const translateToSortQueryParams = (sortingRules: ISortingRules) => {
|
||||
const { sortBy, sortOrder, isFavoritesPinned } = sortingRules;
|
||||
const sortQueryParams = `sortBy=${sortBy}&sortOrder=${sortOrder}&favoritesFirst=${isFavoritesPinned}`;
|
||||
return sortQueryParams;
|
||||
};
|
||||
|
@ -713,7 +713,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
|
||||
const [, envName] = sortBy.split(':');
|
||||
query = query
|
||||
.orderByRaw(
|
||||
`CASE WHEN feature_environments.environment = ? THEN feature_environments.enabled ELSE NULL END ${validatedSortOrder}`,
|
||||
`CASE WHEN feature_environments.environment = ? THEN feature_environments.enabled ELSE NULL END ${validatedSortOrder} NULLS LAST`,
|
||||
[envName],
|
||||
)
|
||||
.orderBy('created_at', 'asc');
|
||||
@ -733,6 +733,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
|
||||
.select(selectColumns)
|
||||
.limit(limit * environmentCount)
|
||||
.offset(offset * environmentCount);
|
||||
|
||||
const rows = await query;
|
||||
|
||||
if (rows.length > 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user