fix: properly handle default group and filter (#1083)
This commit is contained in:
parent
ccd242c06f
commit
2c72215e2d
@ -145,6 +145,8 @@ function applyFolderCollectionDefaults(
|
|||||||
): FolderCollectionWithDefaults {
|
): FolderCollectionWithDefaults {
|
||||||
const collection: FolderCollectionWithDefaults = {
|
const collection: FolderCollectionWithDefaults = {
|
||||||
...originalCollection,
|
...originalCollection,
|
||||||
|
view_filters: undefined,
|
||||||
|
view_groups: undefined,
|
||||||
i18n: collectionI18n,
|
i18n: collectionI18n,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -228,6 +230,8 @@ function applyFilesCollectionDefaults(
|
|||||||
const collection: FilesCollectionWithDefaults = {
|
const collection: FilesCollectionWithDefaults = {
|
||||||
...originalCollection,
|
...originalCollection,
|
||||||
i18n: collectionI18n,
|
i18n: collectionI18n,
|
||||||
|
view_filters: undefined,
|
||||||
|
view_groups: undefined,
|
||||||
files: originalCollection.files.map(f =>
|
files: originalCollection.files.map(f =>
|
||||||
applyCollectionFileDefaults(f, originalCollection, collectionI18n, config),
|
applyCollectionFileDefaults(f, originalCollection, collectionI18n, config),
|
||||||
),
|
),
|
||||||
@ -271,7 +275,7 @@ function applyCollectionDefaults(
|
|||||||
collection.fields = setI18nDefaultsForFields(collection.fields, Boolean(collectionI18n));
|
collection.fields = setI18nDefaultsForFields(collection.fields, Boolean(collectionI18n));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { view_filters, view_groups } = collection;
|
const { view_filters, view_groups } = originalCollection;
|
||||||
|
|
||||||
if (!collection.sortable_fields) {
|
if (!collection.sortable_fields) {
|
||||||
collection.sortable_fields = {
|
collection.sortable_fields = {
|
||||||
@ -280,7 +284,7 @@ function applyCollectionDefaults(
|
|||||||
}
|
}
|
||||||
|
|
||||||
collection.view_filters = {
|
collection.view_filters = {
|
||||||
default: collection.view_filters?.default,
|
default: originalCollection.view_filters?.default,
|
||||||
filters: (view_filters?.filters ?? []).map(filter => {
|
filters: (view_filters?.filters ?? []).map(filter => {
|
||||||
return {
|
return {
|
||||||
...filter,
|
...filter,
|
||||||
@ -290,7 +294,7 @@ function applyCollectionDefaults(
|
|||||||
};
|
};
|
||||||
|
|
||||||
collection.view_groups = {
|
collection.view_groups = {
|
||||||
default: collection.view_groups?.default,
|
default: originalCollection.view_groups?.default,
|
||||||
groups: (view_groups?.groups ?? []).map(group => {
|
groups: (view_groups?.groups ?? []).map(group => {
|
||||||
return {
|
return {
|
||||||
...group,
|
...group,
|
||||||
|
@ -44,11 +44,7 @@ import { Cursor } from '../lib/util';
|
|||||||
import { getFields, updateFieldByKey } from '../lib/util/collection.util';
|
import { getFields, updateFieldByKey } from '../lib/util/collection.util';
|
||||||
import { createEmptyDraftData, createEmptyDraftI18nData } from '../lib/util/entry.util';
|
import { createEmptyDraftData, createEmptyDraftI18nData } from '../lib/util/entry.util';
|
||||||
import { selectCollectionEntriesCursor } from '../reducers/selectors/cursors';
|
import { selectCollectionEntriesCursor } from '../reducers/selectors/cursors';
|
||||||
import {
|
import { selectIsFetching, selectPublishedSlugs } from '../reducers/selectors/entries';
|
||||||
selectEntriesSelectedSort,
|
|
||||||
selectIsFetching,
|
|
||||||
selectPublishedSlugs,
|
|
||||||
} from '../reducers/selectors/entries';
|
|
||||||
import { addSnackbar } from '../store/slices/snackbars';
|
import { addSnackbar } from '../store/slices/snackbars';
|
||||||
import { createAssetProxy } from '../valueObjects/AssetProxy';
|
import { createAssetProxy } from '../valueObjects/AssetProxy';
|
||||||
import createEntry from '../valueObjects/createEntry';
|
import createEntry from '../valueObjects/createEntry';
|
||||||
@ -73,7 +69,9 @@ import type {
|
|||||||
SortDirection,
|
SortDirection,
|
||||||
ValueOrNestedValue,
|
ValueOrNestedValue,
|
||||||
ViewFilter,
|
ViewFilter,
|
||||||
|
ViewFilterWithDefaults,
|
||||||
ViewGroup,
|
ViewGroup,
|
||||||
|
ViewGroupWithDefaults,
|
||||||
} from '../interface';
|
} from '../interface';
|
||||||
import type { RootState } from '../store';
|
import type { RootState } from '../store';
|
||||||
import type AssetProxy from '../valueObjects/AssetProxy';
|
import type AssetProxy from '../valueObjects/AssetProxy';
|
||||||
@ -122,7 +120,10 @@ export function entriesLoading(collection: CollectionWithDefaults) {
|
|||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterEntriesRequest(collection: CollectionWithDefaults, filter: ViewFilter) {
|
export function filterEntriesRequest(
|
||||||
|
collection: CollectionWithDefaults,
|
||||||
|
filter: ViewFilterWithDefaults,
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
type: FILTER_ENTRIES_REQUEST,
|
type: FILTER_ENTRIES_REQUEST,
|
||||||
payload: {
|
payload: {
|
||||||
@ -162,7 +163,10 @@ export function filterEntriesFailure(
|
|||||||
} as const;
|
} as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupEntriesRequest(collection: CollectionWithDefaults, group: ViewGroup) {
|
export function groupEntriesRequest(
|
||||||
|
collection: CollectionWithDefaults,
|
||||||
|
group: ViewGroupWithDefaults,
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
type: GROUP_ENTRIES_REQUEST,
|
type: GROUP_ENTRIES_REQUEST,
|
||||||
payload: {
|
payload: {
|
||||||
@ -315,7 +319,7 @@ export function sortByField(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterByField(collection: CollectionWithDefaults, filter: ViewFilter) {
|
export function filterByField(collection: CollectionWithDefaults, filter: ViewFilterWithDefaults) {
|
||||||
return async (dispatch: ThunkDispatch<RootState, {}, AnyAction>, getState: () => RootState) => {
|
return async (dispatch: ThunkDispatch<RootState, {}, AnyAction>, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
// if we're already fetching we update the filter key, but skip loading entries
|
// if we're already fetching we update the filter key, but skip loading entries
|
||||||
@ -334,17 +338,12 @@ export function filterByField(collection: CollectionWithDefaults, filter: ViewFi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupByField(collection: CollectionWithDefaults, group: ViewGroup) {
|
export function groupByField(collection: CollectionWithDefaults, group: ViewGroupWithDefaults) {
|
||||||
return async (dispatch: ThunkDispatch<RootState, {}, AnyAction>, getState: () => RootState) => {
|
return async (dispatch: ThunkDispatch<RootState, {}, AnyAction>, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const isFetching = selectIsFetching(state, collection.name);
|
const isFetching = selectIsFetching(state, collection.name);
|
||||||
dispatch({
|
dispatch(groupEntriesRequest(collection, group));
|
||||||
type: GROUP_ENTRIES_REQUEST,
|
|
||||||
payload: {
|
|
||||||
collection: collection.name,
|
|
||||||
group,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -699,10 +698,6 @@ export function loadEntries(collection: CollectionWithDefaults, page = 0) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const sortField = selectEntriesSelectedSort(state, collection.name);
|
|
||||||
if (sortField) {
|
|
||||||
return dispatch(sortByField(collection, sortField.key, sortField.direction));
|
|
||||||
}
|
|
||||||
|
|
||||||
const configState = state.config;
|
const configState = state.config;
|
||||||
if (!configState.config) {
|
if (!configState.config) {
|
||||||
@ -751,6 +746,7 @@ export function loadEntries(collection: CollectionWithDefaults, page = 0) {
|
|||||||
);
|
);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
dispatch(
|
dispatch(
|
||||||
addSnackbar({
|
addSnackbar({
|
||||||
|
@ -7,16 +7,16 @@ import GroupControl from './GroupControl';
|
|||||||
import MobileCollectionControls from './mobile/MobileCollectionControls';
|
import MobileCollectionControls from './mobile/MobileCollectionControls';
|
||||||
import SortControl from './SortControl';
|
import SortControl from './SortControl';
|
||||||
|
|
||||||
import type { ViewStyle } from '@staticcms/core/constants/views';
|
|
||||||
import type {
|
import type {
|
||||||
FilterMap,
|
FilterMap,
|
||||||
GroupMap,
|
GroupMap,
|
||||||
SortableField,
|
SortableField,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
SortMap,
|
SortMap,
|
||||||
ViewFilter,
|
ViewFilterWithDefaults,
|
||||||
ViewGroup,
|
ViewGroupWithDefaults,
|
||||||
} from '@staticcms/core';
|
} from '@staticcms/core';
|
||||||
|
import type { ViewStyle } from '@staticcms/core/constants/views';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
interface CollectionControlsProps {
|
interface CollectionControlsProps {
|
||||||
@ -26,11 +26,11 @@ interface CollectionControlsProps {
|
|||||||
onSortClick?: (key: string, direction?: SortDirection) => Promise<void>;
|
onSortClick?: (key: string, direction?: SortDirection) => Promise<void>;
|
||||||
sort?: SortMap | undefined;
|
sort?: SortMap | undefined;
|
||||||
filter?: Record<string, FilterMap>;
|
filter?: Record<string, FilterMap>;
|
||||||
viewFilters?: ViewFilter[];
|
viewFilters?: ViewFilterWithDefaults[];
|
||||||
onFilterClick?: (filter: ViewFilter) => void;
|
onFilterClick?: (filter: ViewFilterWithDefaults) => void;
|
||||||
group?: Record<string, GroupMap>;
|
group?: Record<string, GroupMap>;
|
||||||
viewGroups?: ViewGroup[];
|
viewGroups?: ViewGroupWithDefaults[];
|
||||||
onGroupClick?: (filter: ViewGroup) => void;
|
onGroupClick?: (filter: ViewGroupWithDefaults) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollectionControls: FC<CollectionControlsProps> = ({
|
const CollectionControls: FC<CollectionControlsProps> = ({
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
changeViewStyle,
|
changeViewStyle,
|
||||||
@ -6,7 +6,6 @@ import {
|
|||||||
groupByField,
|
groupByField,
|
||||||
sortByField,
|
sortByField,
|
||||||
} from '@staticcms/core/actions/entries';
|
} from '@staticcms/core/actions/entries';
|
||||||
import { SORT_DIRECTION_ASCENDING } from '@staticcms/core/constants';
|
|
||||||
import useTranslate from '@staticcms/core/lib/hooks/useTranslate';
|
import useTranslate from '@staticcms/core/lib/hooks/useTranslate';
|
||||||
import {
|
import {
|
||||||
getSortableFields,
|
getSortableFields,
|
||||||
@ -28,8 +27,13 @@ import CollectionHeader from './CollectionHeader';
|
|||||||
import EntriesCollection from './entries/EntriesCollection';
|
import EntriesCollection from './entries/EntriesCollection';
|
||||||
import EntriesSearch from './entries/EntriesSearch';
|
import EntriesSearch from './entries/EntriesSearch';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
CollectionWithDefaults,
|
||||||
|
SortDirection,
|
||||||
|
ViewFilterWithDefaults,
|
||||||
|
ViewGroupWithDefaults,
|
||||||
|
} from '@staticcms/core';
|
||||||
import type { ViewStyle } from '@staticcms/core/constants/views';
|
import type { ViewStyle } from '@staticcms/core/constants/views';
|
||||||
import type { CollectionWithDefaults, SortDirection, ViewFilter, ViewGroup } from '@staticcms/core';
|
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import './Collection.css';
|
import './Collection.css';
|
||||||
@ -70,13 +74,6 @@ const CollectionView: FC<CollectionViewProps> = ({
|
|||||||
const filter = useAppSelector(state => selectEntriesFilter(state, collection?.name));
|
const filter = useAppSelector(state => selectEntriesFilter(state, collection?.name));
|
||||||
const group = useAppSelector(state => selectEntriesGroup(state, collection?.name));
|
const group = useAppSelector(state => selectEntriesGroup(state, collection?.name));
|
||||||
|
|
||||||
const [readyToLoad, setReadyToLoad] = useState(false);
|
|
||||||
const [prevCollection, setPrevCollection] = useState<CollectionWithDefaults | null>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setPrevCollection(collection);
|
|
||||||
}, [collection]);
|
|
||||||
|
|
||||||
const searchResultKey = useMemo(
|
const searchResultKey = useMemo(
|
||||||
() => `collection.collectionTop.searchResults${isSingleSearchResult ? 'InCollection' : ''}`,
|
() => `collection.collectionTop.searchResults${isSingleSearchResult ? 'InCollection' : ''}`,
|
||||||
[isSingleSearchResult],
|
[isSingleSearchResult],
|
||||||
@ -110,12 +107,7 @@ const CollectionView: FC<CollectionViewProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EntriesCollection
|
<EntriesCollection collection={collection} viewStyle={viewStyle} filterTerm={filterTerm} />
|
||||||
collection={collection}
|
|
||||||
viewStyle={viewStyle}
|
|
||||||
filterTerm={filterTerm}
|
|
||||||
readyToLoad={readyToLoad && collection === prevCollection}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
collection,
|
collection,
|
||||||
@ -123,8 +115,6 @@ const CollectionView: FC<CollectionViewProps> = ({
|
|||||||
filterTerm,
|
filterTerm,
|
||||||
isSearchResults,
|
isSearchResults,
|
||||||
isSingleSearchResult,
|
isSingleSearchResult,
|
||||||
prevCollection,
|
|
||||||
readyToLoad,
|
|
||||||
searchTerm,
|
searchTerm,
|
||||||
viewStyle,
|
viewStyle,
|
||||||
]);
|
]);
|
||||||
@ -137,14 +127,14 @@ const CollectionView: FC<CollectionViewProps> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const onFilterClick = useCallback(
|
const onFilterClick = useCallback(
|
||||||
async (filter: ViewFilter) => {
|
async (filter: ViewFilterWithDefaults) => {
|
||||||
collection && (await dispatch(filterByField(collection, filter)));
|
collection && (await dispatch(filterByField(collection, filter)));
|
||||||
},
|
},
|
||||||
[collection, dispatch],
|
[collection, dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onGroupClick = useCallback(
|
const onGroupClick = useCallback(
|
||||||
async (group: ViewGroup) => {
|
async (group: ViewGroupWithDefaults) => {
|
||||||
collection && (await dispatch(groupByField(collection, group)));
|
collection && (await dispatch(groupByField(collection, group)));
|
||||||
},
|
},
|
||||||
[collection, dispatch],
|
[collection, dispatch],
|
||||||
@ -157,80 +147,6 @@ const CollectionView: FC<CollectionViewProps> = ({
|
|||||||
[dispatch],
|
[dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (prevCollection === collection) {
|
|
||||||
if (!readyToLoad) {
|
|
||||||
setReadyToLoad(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sort?.[0]?.key) {
|
|
||||||
if (!readyToLoad) {
|
|
||||||
setReadyToLoad(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultSort = collection?.sortable_fields?.default;
|
|
||||||
const defaultViewGroupName = collection?.view_groups?.default;
|
|
||||||
const defaultViewFilterName = collection?.view_filters?.default;
|
|
||||||
if (!defaultViewGroupName && !defaultViewFilterName && (!defaultSort || !defaultSort.field)) {
|
|
||||||
if (!readyToLoad) {
|
|
||||||
setReadyToLoad(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setReadyToLoad(false);
|
|
||||||
|
|
||||||
let alive = true;
|
|
||||||
|
|
||||||
const sortGroupFilterEntries = () => {
|
|
||||||
setTimeout(async () => {
|
|
||||||
if (defaultSort && defaultSort.field) {
|
|
||||||
await onSortClick(defaultSort.field, defaultSort.direction ?? SORT_DIRECTION_ASCENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultViewGroupName) {
|
|
||||||
const defaultViewGroup = viewGroups?.groups.find(g => g.name === defaultViewGroupName);
|
|
||||||
if (defaultViewGroup) {
|
|
||||||
await onGroupClick(defaultViewGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultViewFilterName) {
|
|
||||||
const defaultViewFilter = viewFilters?.filters.find(
|
|
||||||
f => f.name === defaultViewFilterName,
|
|
||||||
);
|
|
||||||
if (defaultViewFilter) {
|
|
||||||
await onFilterClick(defaultViewFilter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alive) {
|
|
||||||
setReadyToLoad(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
sortGroupFilterEntries();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
alive = false;
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
collection,
|
|
||||||
onFilterClick,
|
|
||||||
onGroupClick,
|
|
||||||
onSortClick,
|
|
||||||
prevCollection,
|
|
||||||
readyToLoad,
|
|
||||||
sort,
|
|
||||||
viewFilters?.filters,
|
|
||||||
viewGroups?.groups,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const collectionDescription = collection?.description;
|
const collectionDescription = collection?.description;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -7,8 +7,8 @@ import Menu from '../common/menu/Menu';
|
|||||||
import MenuGroup from '../common/menu/MenuGroup';
|
import MenuGroup from '../common/menu/MenuGroup';
|
||||||
import MenuItemButton from '../common/menu/MenuItemButton';
|
import MenuItemButton from '../common/menu/MenuItemButton';
|
||||||
|
|
||||||
import type { FilterMap, ViewFilter } from '@staticcms/core';
|
import type { FilterMap, ViewFilterWithDefaults } from '@staticcms/core';
|
||||||
import type { MouseEvent, FC } from 'react';
|
import type { FC, MouseEvent } from 'react';
|
||||||
|
|
||||||
import './FilterControl.css';
|
import './FilterControl.css';
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ export const classes = generateClassNames('FilterControl', [
|
|||||||
|
|
||||||
export interface FilterControlProps {
|
export interface FilterControlProps {
|
||||||
filter: Record<string, FilterMap> | undefined;
|
filter: Record<string, FilterMap> | undefined;
|
||||||
viewFilters: ViewFilter[] | undefined;
|
viewFilters: ViewFilterWithDefaults[] | undefined;
|
||||||
variant?: 'menu' | 'list';
|
variant?: 'menu' | 'list';
|
||||||
onFilterClick: ((viewFilter: ViewFilter) => void) | undefined;
|
onFilterClick: ((viewFilter: ViewFilterWithDefaults) => void) | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilterControl: FC<FilterControlProps> = ({
|
const FilterControl: FC<FilterControlProps> = ({
|
||||||
@ -40,7 +40,7 @@ const FilterControl: FC<FilterControlProps> = ({
|
|||||||
const anyActive = useMemo(() => Object.keys(filter).some(key => filter[key]?.active), [filter]);
|
const anyActive = useMemo(() => Object.keys(filter).some(key => filter[key]?.active), [filter]);
|
||||||
|
|
||||||
const handleFilterClick = useCallback(
|
const handleFilterClick = useCallback(
|
||||||
(viewFilter: ViewFilter) => (event: MouseEvent) => {
|
(viewFilter: ViewFilterWithDefaults) => (event: MouseEvent) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onFilterClick?.(viewFilter);
|
onFilterClick?.(viewFilter);
|
||||||
|
@ -7,7 +7,7 @@ import Menu from '../common/menu/Menu';
|
|||||||
import MenuGroup from '../common/menu/MenuGroup';
|
import MenuGroup from '../common/menu/MenuGroup';
|
||||||
import MenuItemButton from '../common/menu/MenuItemButton';
|
import MenuItemButton from '../common/menu/MenuItemButton';
|
||||||
|
|
||||||
import type { GroupMap, ViewGroup } from '@staticcms/core';
|
import type { GroupMap, ViewGroupWithDefaults } from '@staticcms/core';
|
||||||
import type { FC, MouseEvent } from 'react';
|
import type { FC, MouseEvent } from 'react';
|
||||||
|
|
||||||
import './GroupControl.css';
|
import './GroupControl.css';
|
||||||
@ -25,9 +25,9 @@ export const classes = generateClassNames('GroupControl', [
|
|||||||
|
|
||||||
export interface GroupControlProps {
|
export interface GroupControlProps {
|
||||||
group: Record<string, GroupMap> | undefined;
|
group: Record<string, GroupMap> | undefined;
|
||||||
viewGroups: ViewGroup[] | undefined;
|
viewGroups: ViewGroupWithDefaults[] | undefined;
|
||||||
variant?: 'menu' | 'list';
|
variant?: 'menu' | 'list';
|
||||||
onGroupClick: ((viewGroup: ViewGroup) => void) | undefined;
|
onGroupClick: ((viewGroup: ViewGroupWithDefaults) => void) | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupControl: FC<GroupControlProps> = ({
|
const GroupControl: FC<GroupControlProps> = ({
|
||||||
@ -41,7 +41,7 @@ const GroupControl: FC<GroupControlProps> = ({
|
|||||||
const activeGroup = useMemo(() => Object.values(group).find(f => f.active === true), [group]);
|
const activeGroup = useMemo(() => Object.values(group).find(f => f.active === true), [group]);
|
||||||
|
|
||||||
const handleGroupClick = useCallback(
|
const handleGroupClick = useCallback(
|
||||||
(viewGroup: ViewGroup) => (event: MouseEvent) => {
|
(viewGroup: ViewGroupWithDefaults) => (event: MouseEvent) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onGroupClick?.(viewGroup);
|
onGroupClick?.(viewGroup);
|
||||||
|
@ -15,8 +15,8 @@ import Button from '../../common/button/Button';
|
|||||||
import Entries from './Entries';
|
import Entries from './Entries';
|
||||||
import entriesClasses from './Entries.classes';
|
import entriesClasses from './Entries.classes';
|
||||||
|
|
||||||
import type { ViewStyle } from '@staticcms/core/constants/views';
|
|
||||||
import type { CollectionWithDefaults, Entry, GroupOfEntries } from '@staticcms/core';
|
import type { CollectionWithDefaults, Entry, GroupOfEntries } from '@staticcms/core';
|
||||||
|
import type { ViewStyle } from '@staticcms/core/constants/views';
|
||||||
import type { RootState } from '@staticcms/core/store';
|
import type { RootState } from '@staticcms/core/store';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import type { t } from 'react-polyglot';
|
import type { t } from 'react-polyglot';
|
||||||
@ -65,13 +65,11 @@ const EntriesCollection: FC<EntriesCollectionProps> = ({
|
|||||||
cursor,
|
cursor,
|
||||||
page,
|
page,
|
||||||
entriesLoaded,
|
entriesLoaded,
|
||||||
readyToLoad,
|
|
||||||
}) => {
|
}) => {
|
||||||
const t = useTranslate();
|
const t = useTranslate();
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const [prevReadyToLoad, setPrevReadyToLoad] = useState(false);
|
|
||||||
const [prevCollection, setPrevCollection] = useState(collection);
|
const [prevCollection, setPrevCollection] = useState(collection);
|
||||||
|
|
||||||
const groups = useGroups(collection.name);
|
const groups = useGroups(collection.name);
|
||||||
@ -89,26 +87,12 @@ const EntriesCollection: FC<EntriesCollectionProps> = ({
|
|||||||
}, [collection, entries, filterTerm]);
|
}, [collection, entries, filterTerm]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (collection && !entriesLoaded && prevCollection !== collection) {
|
||||||
collection &&
|
|
||||||
!entriesLoaded &&
|
|
||||||
readyToLoad &&
|
|
||||||
(!prevReadyToLoad || prevCollection !== collection)
|
|
||||||
) {
|
|
||||||
dispatch(loadEntries(collection));
|
dispatch(loadEntries(collection));
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrevReadyToLoad(readyToLoad);
|
|
||||||
setPrevCollection(collection);
|
setPrevCollection(collection);
|
||||||
}, [
|
}, [collection, dispatch, entriesLoaded, prevCollection, useWorkflow]);
|
||||||
collection,
|
|
||||||
dispatch,
|
|
||||||
entriesLoaded,
|
|
||||||
prevCollection,
|
|
||||||
prevReadyToLoad,
|
|
||||||
readyToLoad,
|
|
||||||
useWorkflow,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleCursorActions = useCallback(
|
const handleCursorActions = useCallback(
|
||||||
(action: string) => {
|
(action: string) => {
|
||||||
@ -182,7 +166,6 @@ const EntriesCollection: FC<EntriesCollectionProps> = ({
|
|||||||
interface EntriesCollectionOwnProps {
|
interface EntriesCollectionOwnProps {
|
||||||
collection: CollectionWithDefaults;
|
collection: CollectionWithDefaults;
|
||||||
viewStyle: ViewStyle;
|
viewStyle: ViewStyle;
|
||||||
readyToLoad: boolean;
|
|
||||||
filterTerm: string;
|
filterTerm: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,9 +89,9 @@ export type SortMap = Record<string, SortObject>;
|
|||||||
|
|
||||||
export type Sort = Record<string, SortMap>;
|
export type Sort = Record<string, SortMap>;
|
||||||
|
|
||||||
export type FilterMap = ViewFilter & { active?: boolean };
|
export type FilterMap = ViewFilterWithDefaults & { active?: boolean };
|
||||||
|
|
||||||
export type GroupMap = ViewGroup & { active?: boolean };
|
export type GroupMap = ViewGroupWithDefaults & { active?: boolean };
|
||||||
|
|
||||||
export type Filter = Record<string, Record<string, FilterMap>>; // collection.field.active
|
export type Filter = Record<string, Record<string, FilterMap>>; // collection.field.active
|
||||||
|
|
||||||
@ -305,6 +305,8 @@ export interface BaseCollection {
|
|||||||
|
|
||||||
export interface BaseCollectionWithDefaults extends Omit<BaseCollection, 'i18n'> {
|
export interface BaseCollectionWithDefaults extends Omit<BaseCollection, 'i18n'> {
|
||||||
i18n?: I18nInfo;
|
i18n?: I18nInfo;
|
||||||
|
view_filters?: ViewFiltersWithDefaults;
|
||||||
|
view_groups?: ViewGroupsWithDefaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilesCollection<EF extends BaseField = UnknownField> extends BaseCollection {
|
export interface FilesCollection<EF extends BaseField = UnknownField> extends BaseCollection {
|
||||||
@ -958,11 +960,19 @@ export interface ViewFilter {
|
|||||||
pattern: string | boolean | number;
|
pattern: string | boolean | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ViewFilterWithDefaults extends ViewFilter {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ViewFilters {
|
export interface ViewFilters {
|
||||||
default?: string;
|
default?: string;
|
||||||
filters: ViewFilter[];
|
filters: ViewFilter[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ViewFiltersWithDefaults extends ViewFilters {
|
||||||
|
filters: ViewFilterWithDefaults[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ViewGroup {
|
export interface ViewGroup {
|
||||||
id?: string;
|
id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -971,11 +981,19 @@ export interface ViewGroup {
|
|||||||
pattern?: string;
|
pattern?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ViewGroupWithDefaults extends ViewGroup {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ViewGroups {
|
export interface ViewGroups {
|
||||||
default?: string;
|
default?: string;
|
||||||
groups: ViewGroup[];
|
groups: ViewGroup[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ViewGroupsWithDefaults extends ViewGroups {
|
||||||
|
groups: ViewGroupWithDefaults[];
|
||||||
|
}
|
||||||
|
|
||||||
export type SortDirection =
|
export type SortDirection =
|
||||||
| typeof SORT_DIRECTION_ASCENDING
|
| typeof SORT_DIRECTION_ASCENDING
|
||||||
| typeof SORT_DIRECTION_DESCENDING
|
| typeof SORT_DIRECTION_DESCENDING
|
||||||
|
@ -3,6 +3,7 @@ import sortBy from 'lodash/sortBy';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CHANGE_VIEW_STYLE,
|
CHANGE_VIEW_STYLE,
|
||||||
|
CONFIG_SUCCESS,
|
||||||
ENTRIES_FAILURE,
|
ENTRIES_FAILURE,
|
||||||
ENTRIES_REQUEST,
|
ENTRIES_REQUEST,
|
||||||
ENTRIES_SUCCESS,
|
ENTRIES_SUCCESS,
|
||||||
@ -18,6 +19,7 @@ import {
|
|||||||
GROUP_ENTRIES_REQUEST,
|
GROUP_ENTRIES_REQUEST,
|
||||||
GROUP_ENTRIES_SUCCESS,
|
GROUP_ENTRIES_SUCCESS,
|
||||||
SEARCH_ENTRIES_SUCCESS,
|
SEARCH_ENTRIES_SUCCESS,
|
||||||
|
SORT_DIRECTION_ASCENDING,
|
||||||
SORT_ENTRIES_FAILURE,
|
SORT_ENTRIES_FAILURE,
|
||||||
SORT_ENTRIES_REQUEST,
|
SORT_ENTRIES_REQUEST,
|
||||||
SORT_ENTRIES_SUCCESS,
|
SORT_ENTRIES_SUCCESS,
|
||||||
@ -25,6 +27,7 @@ import {
|
|||||||
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
|
import { VIEW_STYLES, VIEW_STYLE_TABLE } from '../constants/views';
|
||||||
import set from '../lib/util/set.util';
|
import set from '../lib/util/set.util';
|
||||||
|
|
||||||
|
import type { ConfigAction } from '../actions/config';
|
||||||
import type { EntriesAction } from '../actions/entries';
|
import type { EntriesAction } from '../actions/entries';
|
||||||
import type { SearchAction } from '../actions/search';
|
import type { SearchAction } from '../actions/search';
|
||||||
import type { ViewStyle } from '../constants/views';
|
import type { ViewStyle } from '../constants/views';
|
||||||
@ -124,9 +127,70 @@ export type EntriesState = {
|
|||||||
|
|
||||||
function entries(
|
function entries(
|
||||||
state: EntriesState = { entries: {}, pages: {}, sort: loadSort(), viewStyle: loadViewStyle() },
|
state: EntriesState = { entries: {}, pages: {}, sort: loadSort(), viewStyle: loadViewStyle() },
|
||||||
action: EntriesAction | SearchAction,
|
action: EntriesAction | SearchAction | ConfigAction,
|
||||||
): EntriesState {
|
): EntriesState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case CONFIG_SUCCESS: {
|
||||||
|
const config = action.payload.config;
|
||||||
|
|
||||||
|
const sort: EntriesState['sort'] = {};
|
||||||
|
const group: EntriesState['group'] = {};
|
||||||
|
const filter: EntriesState['filter'] = {};
|
||||||
|
|
||||||
|
for (const collection of config.collections) {
|
||||||
|
if (collection.sortable_fields && collection.sortable_fields.default) {
|
||||||
|
const key = collection.sortable_fields.default.field;
|
||||||
|
sort[collection.name] = {
|
||||||
|
[key]: {
|
||||||
|
key,
|
||||||
|
direction: collection.sortable_fields.default.direction ?? SORT_DIRECTION_ASCENDING,
|
||||||
|
},
|
||||||
|
} as SortMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.view_filters && collection.view_filters.default) {
|
||||||
|
const defaultViewFilterName = collection.view_filters.default;
|
||||||
|
const defaultViewFilter = collection.view_filters.filters.find(
|
||||||
|
f => f.name === defaultViewFilterName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const collectionFilters: Record<string, FilterMap> = {};
|
||||||
|
if (defaultViewFilter) {
|
||||||
|
collectionFilters[defaultViewFilter.id] = {
|
||||||
|
...defaultViewFilter,
|
||||||
|
active: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
filter[collection.name] = collectionFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.view_groups && collection.view_groups.default) {
|
||||||
|
const defaultViewGroupName = collection.view_groups.default;
|
||||||
|
const defaultViewGroup = collection.view_groups.groups.find(
|
||||||
|
g => g.name === defaultViewGroupName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const collectionGroups: Record<string, GroupMap> = {};
|
||||||
|
if (defaultViewGroup) {
|
||||||
|
collectionGroups[defaultViewGroup.id] = {
|
||||||
|
...defaultViewGroup,
|
||||||
|
active: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
group[collection.name] = collectionGroups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
sort,
|
||||||
|
group,
|
||||||
|
filter,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case ENTRY_REQUEST: {
|
case ENTRY_REQUEST: {
|
||||||
const payload = action.payload;
|
const payload = action.payload;
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import get from 'lodash/get';
|
|||||||
import { SORT_DIRECTION_NONE } from '@staticcms/core/constants';
|
import { SORT_DIRECTION_NONE } from '@staticcms/core/constants';
|
||||||
import { filterNullish } from '@staticcms/core/lib/util/null.util';
|
import { filterNullish } from '@staticcms/core/lib/util/null.util';
|
||||||
|
|
||||||
import type { ViewStyle } from '@staticcms/core/constants/views';
|
|
||||||
import type {
|
import type {
|
||||||
Entries,
|
Entries,
|
||||||
Entry,
|
Entry,
|
||||||
@ -14,6 +13,7 @@ import type {
|
|||||||
SortMap,
|
SortMap,
|
||||||
SortObject,
|
SortObject,
|
||||||
} from '@staticcms/core';
|
} from '@staticcms/core';
|
||||||
|
import type { ViewStyle } from '@staticcms/core/constants/views';
|
||||||
import type { RootState } from '@staticcms/core/store';
|
import type { RootState } from '@staticcms/core/store';
|
||||||
|
|
||||||
export const selectEntriesFilters = (entries: RootState) => {
|
export const selectEntriesFilters = (entries: RootState) => {
|
||||||
|
@ -46,6 +46,24 @@ export const createMockFolderCollectionWithDefaults = <EF extends BaseField>(
|
|||||||
): FolderCollectionWithDefaults<EF> => ({
|
): FolderCollectionWithDefaults<EF> => ({
|
||||||
...createMockFolderCollection(extra, ...fields),
|
...createMockFolderCollection(extra, ...fields),
|
||||||
i18n: extra.i18n,
|
i18n: extra.i18n,
|
||||||
|
view_filters: extra.view_filters
|
||||||
|
? {
|
||||||
|
...extra.view_filters,
|
||||||
|
filters: extra.view_filters.filters.map(f => ({
|
||||||
|
...f,
|
||||||
|
id: `${f.field}__${f.pattern}`,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
view_groups: extra.view_groups
|
||||||
|
? {
|
||||||
|
...extra.view_groups,
|
||||||
|
groups: extra.view_groups.groups.map(g => ({
|
||||||
|
...g,
|
||||||
|
id: `${g.field}__${g.pattern}`,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const createMockCollectionFile = <EF extends BaseField>(
|
export const createMockCollectionFile = <EF extends BaseField>(
|
||||||
@ -102,4 +120,22 @@ export const createMockFilesCollectionWithDefaults = <EF extends BaseField>(
|
|||||||
...createMockFilesCollection(extra),
|
...createMockFilesCollection(extra),
|
||||||
i18n: extra.i18n,
|
i18n: extra.i18n,
|
||||||
files: extra.files,
|
files: extra.files,
|
||||||
|
view_filters: extra.view_filters
|
||||||
|
? {
|
||||||
|
...extra.view_filters,
|
||||||
|
filters: extra.view_filters.filters.map(f => ({
|
||||||
|
...f,
|
||||||
|
id: `${f.field}__${f.pattern}`,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
view_groups: extra.view_groups
|
||||||
|
? {
|
||||||
|
...extra.view_groups,
|
||||||
|
groups: extra.view_groups.groups.map(g => ({
|
||||||
|
...g,
|
||||||
|
id: `${g.field}__${g.pattern}`,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user