Skip to content

Commit 52444da

Browse files
committed
chore: refactor
1 parent 8b02688 commit 52444da

File tree

5 files changed

+177
-166
lines changed

5 files changed

+177
-166
lines changed

packages/decap-cms-core/src/actions/entries.ts

Lines changed: 21 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ import { navigateToEntry } from '../routing/history';
2222
import { getProcessSegment } from '../lib/formatters';
2323
import { hasI18n, duplicateDefaultI18nFields, serializeI18n, I18N, I18N_FIELD } from '../lib/i18n';
2424
import { isPaginationEnabled } from '../lib/pagination';
25+
import {
26+
hasActiveFilters,
27+
hasActiveGroups,
28+
hasActiveSorts,
29+
extractActiveFilters,
30+
matchesFilters,
31+
getFieldValue,
32+
} from '../lib/entryHelpers';
2533
import { addNotification } from './notifications';
2634

2735
import type { ImplementationMediaFile } from 'decap-cms-lib-util';
@@ -240,38 +248,9 @@ export function sortByField(
240248

241249
// Check if filtering is active - if so, apply filters first
242250
const activeFilters = state.entries.getIn(['filter', collectionName]);
243-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
244-
const hasActiveFilters =
245-
activeFilters &&
246-
typeof (activeFilters as any).some === 'function' &&
247-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
248-
(activeFilters as any).some((f: any) => f.get('active') === true);
249-
250-
if (hasActiveFilters) {
251-
entries = entries.filter(entry => {
252-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
253-
const filters: any[] = [];
254-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
255-
(activeFilters as any).forEach((f: any) => {
256-
if (f.get('active') === true) {
257-
filters.push({
258-
pattern: f.get('pattern'),
259-
field: f.get('field'),
260-
});
261-
}
262-
});
263-
264-
return filters.every(({ pattern, field }) => {
265-
const data = entry.data || {};
266-
const fieldParts = field.split('.');
267-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
268-
let value: any = data;
269-
for (const part of fieldParts) {
270-
value = value?.[part];
271-
}
272-
return value !== undefined && new RegExp(String(pattern)).test(String(value));
273-
});
274-
});
251+
if (hasActiveFilters(activeFilters)) {
252+
const filters = extractActiveFilters(activeFilters);
253+
entries = entries.filter(entry => matchesFilters(entry, filters));
275254
}
276255

277256
// Sort entries by the specified field
@@ -282,13 +261,7 @@ export function sortByField(
282261
entries,
283262
[
284263
entry => {
285-
// dataPath is a string like "data.title" or "updatedOn"
286-
const pathParts = dataPath.split('.');
287-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
288-
let value: any = entry;
289-
for (const part of pathParts) {
290-
value = value?.[part];
291-
}
264+
const value = getFieldValue(entry, dataPath);
292265
// Handle case-insensitive string sorting
293266
return typeof value === 'string' ? value.toLowerCase() : value;
294267
},
@@ -298,14 +271,8 @@ export function sortByField(
298271

299272
// Check if grouping is active - if so, use GROUP_ENTRIES_SUCCESS to avoid pagination
300273
const activeGroups = state.entries.getIn(['group', collectionName]);
301-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
302-
const hasActiveGroups =
303-
activeGroups &&
304-
typeof (activeGroups as any).some === 'function' &&
305-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
306-
(activeGroups as any).some((g: any) => g.get('active') === true);
307274

308-
if (hasActiveGroups) {
275+
if (hasActiveGroups(activeGroups)) {
309276
dispatch({
310277
type: GROUP_ENTRIES_SUCCESS,
311278
payload: {
@@ -421,14 +388,9 @@ export function filterByField(collection: Collection, filter: ViewFilter) {
421388

422389
// Check if sorting is active - if so, apply sort after filtering
423390
const activeSorts = updatedState.entries.getIn(['sort', collection.get('name')]);
424-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
425-
const hasActiveSort =
426-
activeSorts &&
427-
typeof (activeSorts as any).size === 'number' &&
428-
(activeSorts as any).size > 0;
429391

430392
let finalEntries = filteredEntries;
431-
if (hasActiveSort) {
393+
if (hasActiveSorts(activeSorts)) {
432394
// eslint-disable-next-line @typescript-eslint/no-explicit-any
433395
const sortField = (activeSorts as any).valueSeq().first();
434396
const sortKey = sortField.get('key');
@@ -440,12 +402,7 @@ export function filterByField(collection: Collection, filter: ViewFilter) {
440402
filteredEntries,
441403
[
442404
entry => {
443-
const pathParts = dataPath.split('.');
444-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
445-
let value: any = entry;
446-
for (const part of pathParts) {
447-
value = value?.[part];
448-
}
405+
const value = getFieldValue(entry, dataPath);
449406
return typeof value === 'string' ? value.toLowerCase() : value;
450407
},
451408
],
@@ -455,14 +412,8 @@ export function filterByField(collection: Collection, filter: ViewFilter) {
455412

456413
// Check if grouping is active - if so, use GROUP_ENTRIES_SUCCESS to avoid pagination
457414
const activeGroups = updatedState.entries.getIn(['group', collection.get('name')]);
458-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
459-
const hasActiveGroups =
460-
activeGroups &&
461-
typeof (activeGroups as any).some === 'function' &&
462-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
463-
(activeGroups as any).some((g: any) => g.get('active') === true);
464415

465-
if (hasActiveGroups) {
416+
if (hasActiveGroups(activeGroups)) {
466417
dispatch({
467418
type: GROUP_ENTRIES_SUCCESS,
468419
payload: {
@@ -543,49 +494,16 @@ export function groupByField(collection: Collection, group: ViewGroup) {
543494

544495
// Check if filtering is active - if so, apply filters
545496
const activeFilters = updatedState.entries.getIn(['filter', collection.get('name')]);
546-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
547-
const hasActiveFilters =
548-
activeFilters &&
549-
typeof (activeFilters as any).some === 'function' &&
550-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
551-
(activeFilters as any).some((f: any) => f.get('active') === true);
552-
553-
if (hasActiveFilters) {
554-
entries = entries.filter(entry => {
555-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
556-
const filters: any[] = [];
557-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
558-
(activeFilters as any).forEach((f: any) => {
559-
if (f.get('active') === true) {
560-
filters.push({
561-
pattern: f.get('pattern'),
562-
field: f.get('field'),
563-
});
564-
}
565-
});
566497

567-
return filters.every(({ pattern, field }) => {
568-
const data = entry.data || {};
569-
const fieldParts = field.split('.');
570-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
571-
let value: any = data;
572-
for (const part of fieldParts) {
573-
value = value?.[part];
574-
}
575-
return value !== undefined && new RegExp(String(pattern)).test(String(value));
576-
});
577-
});
498+
if (hasActiveFilters(activeFilters)) {
499+
const filters = extractActiveFilters(activeFilters);
500+
entries = entries.filter(entry => matchesFilters(entry, filters));
578501
}
579502

580503
// Check if sorting is active - if so, apply sort
581504
const activeSorts = updatedState.entries.getIn(['sort', collection.get('name')]);
582-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
583-
const hasActiveSort =
584-
activeSorts &&
585-
typeof (activeSorts as any).size === 'number' &&
586-
(activeSorts as any).size > 0;
587505

588-
if (hasActiveSort) {
506+
if (hasActiveSorts(activeSorts)) {
589507
// eslint-disable-next-line @typescript-eslint/no-explicit-any
590508
const sortField = (activeSorts as any).valueSeq().first();
591509
const sortKey = sortField.get('key');
@@ -597,12 +515,7 @@ export function groupByField(collection: Collection, group: ViewGroup) {
597515
entries,
598516
[
599517
entry => {
600-
const pathParts = dataPath.split('.');
601-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
602-
let value: any = entry;
603-
for (const part of pathParts) {
604-
value = value?.[part];
605-
}
518+
const value = getFieldValue(entry, dataPath);
606519
return typeof value === 'string' ? value.toLowerCase() : value;
607520
},
608521
],

packages/decap-cms-core/src/components/Collection/Entries/EntriesCollection.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,25 +113,15 @@ export class EntriesCollection extends React.Component {
113113
sortByField,
114114
} = this.props;
115115

116-
console.log('[EntriesCollection] componentDidMount', {
117-
collectionName: collection.get('name'),
118-
sortExists: !!sort,
119-
sortSize: sort ? sort.size : 0,
120-
entriesLoaded,
121-
});
122-
123116
// If sort state exists on mount, re-trigger sort to populate sortedIds
124117
if (sort && sort.size > 0) {
125-
console.log('[EntriesCollection] Re-triggering sort on mount', sort.toJS());
126118
sort.forEach((value, key) => {
127119
const direction = value.get('direction');
128-
console.log('[EntriesCollection] Triggering sortByField', { key, direction });
129120
sortByField(collection, key, direction);
130121
});
131122
}
132123

133124
if (collection && !entriesLoaded) {
134-
console.log('[EntriesCollection] Loading entries (not loaded yet)');
135125
loadEntries(collection);
136126
}
137127

@@ -293,14 +283,6 @@ function mapStateToProps(state, ownProps) {
293283
: selectEntriesPageSize(state.entries, collection.get('name'));
294284
const totalCount = selectEntriesTotalCount(state.entries, collection.get('name'));
295285

296-
console.log('[mapStateToProps] Pagination', {
297-
collectionName: collection.get('name'),
298-
paginationEnabled,
299-
configPageSize: paginationConfig?.per_page,
300-
reduxPageSize: selectEntriesPageSize(state.entries, collection.get('name')),
301-
finalPageSize: pageSize,
302-
});
303-
304286
// Sort state
305287
const sort = selectEntriesSort(state.entries, collection.get('name'));
306288

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Utility functions for working with entries, filters, sorts, and groups
3+
*/
4+
5+
/**
6+
* Check if any filters are active in the Redux state
7+
*/
8+
export function hasActiveFilters(activeFilters: unknown): boolean {
9+
if (!activeFilters) return false;
10+
11+
// Check if it's an Immutable collection with a 'some' method
12+
if (
13+
typeof activeFilters === 'object' &&
14+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15+
typeof (activeFilters as any).some === 'function'
16+
) {
17+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18+
return (activeFilters as any).some((f: any) => f.get('active') === true);
19+
}
20+
21+
return false;
22+
}
23+
24+
/**
25+
* Check if any groups are active in the Redux state
26+
*/
27+
export function hasActiveGroups(activeGroups: unknown): boolean {
28+
if (!activeGroups) return false;
29+
30+
// Check if it's an Immutable collection with a 'some' method
31+
if (
32+
typeof activeGroups === 'object' &&
33+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34+
typeof (activeGroups as any).some === 'function'
35+
) {
36+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
37+
return (activeGroups as any).some((g: any) => g.get('active') === true);
38+
}
39+
40+
return false;
41+
}
42+
43+
/**
44+
* Check if any sorts are active in the Redux state
45+
*/
46+
export function hasActiveSorts(activeSorts: unknown): boolean {
47+
if (!activeSorts) return false;
48+
49+
// Check if it's an Immutable collection with a 'size' property
50+
if (
51+
typeof activeSorts === 'object' &&
52+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
53+
typeof (activeSorts as any).size === 'number'
54+
) {
55+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
56+
return (activeSorts as any).size > 0;
57+
}
58+
59+
return false;
60+
}
61+
62+
/**
63+
* Get value from a nested field path (e.g., "data.title" or "data.nested.field")
64+
*/
65+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
66+
export function getFieldValue(obj: any, fieldPath: string): unknown {
67+
const pathParts = fieldPath.split('.');
68+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
69+
let value: any = obj;
70+
for (const part of pathParts) {
71+
value = value?.[part];
72+
}
73+
return value;
74+
}
75+
76+
/**
77+
* Extract active filters from Immutable collection into plain array
78+
*/
79+
export interface FilterDefinition {
80+
pattern: string | RegExp;
81+
field: string;
82+
}
83+
84+
export function extractActiveFilters(activeFilters: unknown): FilterDefinition[] {
85+
const filters: FilterDefinition[] = [];
86+
87+
if (!activeFilters) return filters;
88+
89+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
90+
if (typeof (activeFilters as any).forEach === 'function') {
91+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
92+
(activeFilters as any).forEach((f: any) => {
93+
if (f.get('active') === true) {
94+
filters.push({
95+
pattern: f.get('pattern'),
96+
field: f.get('field'),
97+
});
98+
}
99+
});
100+
}
101+
102+
return filters;
103+
}
104+
105+
/**
106+
* Apply filters to an entry
107+
*/
108+
export function matchesFilters(
109+
entry: Record<string, unknown> | { data?: Record<string, unknown> },
110+
filters: FilterDefinition[],
111+
): boolean {
112+
return filters.every(({ pattern, field }) => {
113+
const data = ('data' in entry ? entry.data : entry) || {};
114+
const value = getFieldValue(data as Record<string, unknown>, field);
115+
return value !== undefined && new RegExp(String(pattern)).test(String(value));
116+
});
117+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Type guard to check if an object is an Immutable.js Map
3+
*/
4+
export function isImmutableMap(obj: unknown): boolean {
5+
return (
6+
typeof obj === 'object' && obj !== null && typeof (obj as { get?: unknown }).get === 'function'
7+
);
8+
}
9+
10+
/**
11+
* Helper to safely get a value from either an Immutable Map or plain object
12+
*/
13+
export function getValue<T = unknown>(obj: unknown, key: string): T | undefined {
14+
if (!obj) return undefined;
15+
16+
if (isImmutableMap(obj)) {
17+
return (obj as { get: (k: string) => T }).get(key);
18+
}
19+
20+
if (typeof obj === 'object' && obj !== null) {
21+
return (obj as Record<string, unknown>)[key] as T;
22+
}
23+
24+
return undefined;
25+
}

0 commit comments

Comments
 (0)