decap-cms-core 3.10.0 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/decap-cms-core.js +8 -8
- package/dist/decap-cms-core.js.map +1 -1
- package/dist/esm/bootstrap.js +2 -2
- package/dist/esm/components/App/StatusBar.js +1 -1
- package/dist/esm/components/Collection/CollectionControls.js +3 -2
- package/dist/esm/components/Collection/ViewStyleControl.js +6 -3
- package/dist/esm/components/Editor/EditorControlPane/EditorControl.js +8 -5
- package/dist/esm/components/Editor/EditorNotesPane/AddNoteForm.js +5 -5
- package/dist/esm/components/Editor/EditorNotesPane/EditorNotesPane.js +75 -15
- package/dist/esm/components/Editor/EditorNotesPane/NoteItem.js +21 -24
- package/dist/esm/components/Editor/EditorNotesPane/NotesList.js +4 -4
- package/dist/esm/components/MediaLibrary/MediaLibraryHeader.js +5 -3
- package/dist/esm/components/MediaLibrary/MediaLibraryTop.js +5 -4
- package/dist/esm/components/UI/ErrorBoundary.js +2 -2
- package/dist/esm/components/UI/SettingsDropdown.js +9 -7
- package/package.json +2 -2
- package/src/components/Collection/CollectionControls.js +1 -1
- package/src/components/Collection/ViewStyleControl.js +3 -1
- package/src/components/Editor/EditorControlPane/EditorControl.js +1 -0
- package/src/components/MediaLibrary/MediaLibraryHeader.js +2 -2
- package/src/components/MediaLibrary/MediaLibraryTop.js +1 -0
- package/src/components/UI/SettingsDropdown.js +1 -1
- package/dist/esm/components/Collection/Entries/Pagination.js +0 -132
- package/dist/esm/lib/entryCache.js +0 -145
- package/dist/esm/lib/entryHelpers.js +0 -102
- package/dist/esm/lib/immutableHelpers.js +0 -21
- package/dist/esm/lib/pagination.js +0 -68
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entry Cache Module
|
|
3
|
-
*
|
|
4
|
-
* Provides localStorage-based caching for collection entries to improve performance
|
|
5
|
-
* when navigating between pages, sorting, or filtering.
|
|
6
|
-
*
|
|
7
|
-
* Cache Strategy:
|
|
8
|
-
* - Store fetched entries with timestamps
|
|
9
|
-
* - Invalidate on entry changes (persist, delete)
|
|
10
|
-
* - Time-based expiration (default: 5 minutes)
|
|
11
|
-
* - Collection-specific cache keys
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import localForage from 'decap-cms-lib-util/src/localForage';
|
|
15
|
-
const CACHE_PREFIX = 'decap_entry_cache_';
|
|
16
|
-
const CACHE_EXPIRATION_MS = 5 * 60 * 1000; // 5 minutes
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Generate cache key for a collection
|
|
20
|
-
*/
|
|
21
|
-
function getCacheKey(collectionName) {
|
|
22
|
-
return `${CACHE_PREFIX}${collectionName}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Check if cached data is still valid
|
|
27
|
-
*/
|
|
28
|
-
function isCacheValid(cacheEntry) {
|
|
29
|
-
if (!cacheEntry) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
const age = now - cacheEntry.timestamp;
|
|
34
|
-
return age < CACHE_EXPIRATION_MS;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Get cached entries for a collection
|
|
39
|
-
*
|
|
40
|
-
* @param collectionName - Name of the collection
|
|
41
|
-
* @returns Cached entries or null if cache miss/expired
|
|
42
|
-
*/
|
|
43
|
-
export async function getCachedEntries(collectionName) {
|
|
44
|
-
try {
|
|
45
|
-
const cacheKey = getCacheKey(collectionName);
|
|
46
|
-
const cached = await localForage.getItem(cacheKey);
|
|
47
|
-
if (cached && isCacheValid(cached)) {
|
|
48
|
-
console.log(`[EntryCache] Cache HIT for collection: ${collectionName}`);
|
|
49
|
-
return cached.entries;
|
|
50
|
-
}
|
|
51
|
-
console.log(`[EntryCache] Cache MISS for collection: ${collectionName}`);
|
|
52
|
-
return null;
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.warn('[EntryCache] Error reading cache:', error);
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Store entries in cache
|
|
61
|
-
*
|
|
62
|
-
* @param collectionName - Name of the collection
|
|
63
|
-
* @param entries - Entries to cache
|
|
64
|
-
*/
|
|
65
|
-
export async function setCachedEntries(collectionName, entries) {
|
|
66
|
-
try {
|
|
67
|
-
const cacheKey = getCacheKey(collectionName);
|
|
68
|
-
const cacheEntry = {
|
|
69
|
-
entries,
|
|
70
|
-
timestamp: Date.now(),
|
|
71
|
-
collectionName,
|
|
72
|
-
version: 1
|
|
73
|
-
};
|
|
74
|
-
await localForage.setItem(cacheKey, cacheEntry);
|
|
75
|
-
console.log(`[EntryCache] Cached ${entries.length} entries for collection: ${collectionName}`);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.warn('[EntryCache] Error writing cache:', error);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Invalidate cache for a specific collection
|
|
83
|
-
*
|
|
84
|
-
* Should be called when:
|
|
85
|
-
* - Entry is created
|
|
86
|
-
* - Entry is updated
|
|
87
|
-
* - Entry is deleted
|
|
88
|
-
*
|
|
89
|
-
* @param collectionName - Name of the collection to invalidate
|
|
90
|
-
*/
|
|
91
|
-
export async function invalidateCollectionCache(collectionName) {
|
|
92
|
-
try {
|
|
93
|
-
const cacheKey = getCacheKey(collectionName);
|
|
94
|
-
await localForage.removeItem(cacheKey);
|
|
95
|
-
console.log(`[EntryCache] Invalidated cache for collection: ${collectionName}`);
|
|
96
|
-
} catch (error) {
|
|
97
|
-
console.warn('[EntryCache] Error invalidating cache:', error);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Clear all entry caches
|
|
103
|
-
*
|
|
104
|
-
* Useful for logout or manual cache clearing
|
|
105
|
-
*/
|
|
106
|
-
export async function clearAllEntryCaches() {
|
|
107
|
-
try {
|
|
108
|
-
const keys = await localForage.keys();
|
|
109
|
-
const cacheKeys = keys.filter(key => key.startsWith(CACHE_PREFIX));
|
|
110
|
-
await Promise.all(cacheKeys.map(key => localForage.removeItem(key)));
|
|
111
|
-
console.log(`[EntryCache] Cleared ${cacheKeys.length} collection caches`);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.warn('[EntryCache] Error clearing all caches:', error);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Get cache statistics for debugging
|
|
119
|
-
*/
|
|
120
|
-
export async function getCacheStats() {
|
|
121
|
-
try {
|
|
122
|
-
const keys = await localForage.keys();
|
|
123
|
-
const cacheKeys = keys.filter(key => key.startsWith(CACHE_PREFIX));
|
|
124
|
-
const cacheEntries = await Promise.all(cacheKeys.map(async key => {
|
|
125
|
-
const entry = await localForage.getItem(key);
|
|
126
|
-
return entry;
|
|
127
|
-
}));
|
|
128
|
-
const validCaches = cacheEntries.filter(entry => entry !== null);
|
|
129
|
-
const timestamps = validCaches.map(c => c.timestamp);
|
|
130
|
-
return {
|
|
131
|
-
collections: validCaches.map(c => c.collectionName),
|
|
132
|
-
totalEntries: validCaches.reduce((sum, c) => sum + c.entries.length, 0),
|
|
133
|
-
oldestCache: timestamps.length > 0 ? Math.min(...timestamps) : null,
|
|
134
|
-
newestCache: timestamps.length > 0 ? Math.max(...timestamps) : null
|
|
135
|
-
};
|
|
136
|
-
} catch (error) {
|
|
137
|
-
console.warn('[EntryCache] Error getting cache stats:', error);
|
|
138
|
-
return {
|
|
139
|
-
collections: [],
|
|
140
|
-
totalEntries: 0,
|
|
141
|
-
oldestCache: null,
|
|
142
|
-
newestCache: null
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
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) {
|
|
9
|
-
if (!activeFilters) return false;
|
|
10
|
-
|
|
11
|
-
// Check if it's an Immutable collection with a 'some' method
|
|
12
|
-
if (typeof activeFilters === 'object' &&
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
-
typeof activeFilters.some === 'function') {
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
-
return activeFilters.some(f => f.get('active') === true);
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Check if any groups are active in the Redux state
|
|
23
|
-
*/
|
|
24
|
-
export function hasActiveGroups(activeGroups) {
|
|
25
|
-
if (!activeGroups) return false;
|
|
26
|
-
|
|
27
|
-
// Check if it's an Immutable collection with a 'some' method
|
|
28
|
-
if (typeof activeGroups === 'object' &&
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
typeof activeGroups.some === 'function') {
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
return activeGroups.some(g => g.get('active') === true);
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Check if any sorts are active in the Redux state
|
|
39
|
-
*/
|
|
40
|
-
export function hasActiveSorts(activeSorts) {
|
|
41
|
-
if (!activeSorts) return false;
|
|
42
|
-
|
|
43
|
-
// Check if it's an Immutable collection with a 'size' property
|
|
44
|
-
if (typeof activeSorts === 'object' &&
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
-
typeof activeSorts.size === 'number') {
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
-
return activeSorts.size > 0;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get value from a nested field path (e.g., "data.title" or "data.nested.field")
|
|
55
|
-
*/
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
-
export function getFieldValue(obj, fieldPath) {
|
|
58
|
-
const pathParts = fieldPath.split('.');
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
-
let value = obj;
|
|
61
|
-
for (const part of pathParts) {
|
|
62
|
-
value = value?.[part];
|
|
63
|
-
}
|
|
64
|
-
return value;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Extract active filters from Immutable collection into plain array
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
|
-
export function extractActiveFilters(activeFilters) {
|
|
72
|
-
const filters = [];
|
|
73
|
-
if (!activeFilters) return filters;
|
|
74
|
-
|
|
75
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
-
if (typeof activeFilters.forEach === 'function') {
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
-
activeFilters.forEach(f => {
|
|
79
|
-
if (f.get('active') === true) {
|
|
80
|
-
filters.push({
|
|
81
|
-
pattern: f.get('pattern'),
|
|
82
|
-
field: f.get('field')
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
return filters;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Apply filters to an entry
|
|
92
|
-
*/
|
|
93
|
-
export function matchesFilters(entry, filters) {
|
|
94
|
-
return filters.every(({
|
|
95
|
-
pattern,
|
|
96
|
-
field
|
|
97
|
-
}) => {
|
|
98
|
-
const data = ('data' in entry ? entry.data : entry) || {};
|
|
99
|
-
const value = getFieldValue(data, field);
|
|
100
|
-
return value !== undefined && new RegExp(String(pattern)).test(String(value));
|
|
101
|
-
});
|
|
102
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Map } from 'immutable';
|
|
2
|
-
/**
|
|
3
|
-
* Type guard to check if an object is an Immutable.js Map
|
|
4
|
-
*/
|
|
5
|
-
export function isImmutableMap(obj) {
|
|
6
|
-
return Map.isMap(obj);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Helper to safely get a value from either an Immutable Map or plain object
|
|
11
|
-
*/
|
|
12
|
-
export function getValue(obj, key) {
|
|
13
|
-
if (!obj) return undefined;
|
|
14
|
-
if (isImmutableMap(obj)) {
|
|
15
|
-
return obj.get(key);
|
|
16
|
-
}
|
|
17
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
18
|
-
return obj[key];
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pagination Utilities
|
|
3
|
-
*
|
|
4
|
-
* This module provides helpers for determining if pagination is enabled for a collection,
|
|
5
|
-
* and for retrieving the effective pagination configuration (page size, enabled flag).
|
|
6
|
-
*
|
|
7
|
-
* Principles:
|
|
8
|
-
* - Pagination can be enabled/disabled per collection or globally via config.
|
|
9
|
-
* - If sorting, filtering, or grouping is active, pagination is handled client-side (all entries loaded).
|
|
10
|
-
* - If none are active, server-side pagination is used (only a page of entries loaded at a time).
|
|
11
|
-
* - The effective page size is determined by collection config, then global config, then a default.
|
|
12
|
-
*
|
|
13
|
-
* Usage:
|
|
14
|
-
* - Use isPaginationEnabled(collection, config) to check if pagination should be active.
|
|
15
|
-
* - Use getPaginationConfig(collection, config) to get the effective page size and enabled flag.
|
|
16
|
-
*/
|
|
17
|
-
import { getValue, isImmutableMap } from './immutableHelpers';
|
|
18
|
-
const DEFAULT_PER_PAGE = 100;
|
|
19
|
-
export function isPaginationEnabled(collection, globalConfig) {
|
|
20
|
-
const pagination = isImmutableMap(collection) ? collection.get('pagination') : collection.pagination;
|
|
21
|
-
if (typeof pagination !== 'undefined') {
|
|
22
|
-
if (typeof pagination === 'boolean') return pagination;
|
|
23
|
-
if (pagination && typeof pagination === 'object') {
|
|
24
|
-
const enabled = getValue(pagination, 'enabled');
|
|
25
|
-
return enabled !== false;
|
|
26
|
-
}
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
if (globalConfig?.pagination) {
|
|
30
|
-
if (typeof globalConfig.pagination === 'boolean') return globalConfig.pagination;
|
|
31
|
-
if (typeof globalConfig.pagination === 'object') {
|
|
32
|
-
const enabled = getValue(globalConfig.pagination, 'enabled');
|
|
33
|
-
return enabled !== false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
export function getPaginationConfig(collection, globalConfig) {
|
|
39
|
-
const defaults = {
|
|
40
|
-
enabled: false,
|
|
41
|
-
per_page: DEFAULT_PER_PAGE
|
|
42
|
-
};
|
|
43
|
-
if (globalConfig?.pagination) {
|
|
44
|
-
if (typeof globalConfig.pagination === 'boolean') {
|
|
45
|
-
defaults.enabled = globalConfig.pagination;
|
|
46
|
-
} else if (typeof globalConfig.pagination === 'object') {
|
|
47
|
-
const enabled = getValue(globalConfig.pagination, 'enabled');
|
|
48
|
-
defaults.enabled = enabled !== false;
|
|
49
|
-
const perPage = getValue(globalConfig.pagination, 'per_page');
|
|
50
|
-
defaults.per_page = typeof perPage === 'number' ? perPage : defaults.per_page;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const pagination = isImmutableMap(collection) ? collection.get('pagination') : collection.pagination;
|
|
54
|
-
if (pagination === true) {
|
|
55
|
-
return {
|
|
56
|
-
enabled: true,
|
|
57
|
-
per_page: defaults.per_page
|
|
58
|
-
};
|
|
59
|
-
} else if (typeof pagination === 'object' && pagination !== null) {
|
|
60
|
-
const perPage = getValue(pagination, 'per_page');
|
|
61
|
-
const enabled = getValue(pagination, 'enabled');
|
|
62
|
-
return {
|
|
63
|
-
enabled: enabled !== false,
|
|
64
|
-
per_page: typeof perPage === 'number' ? perPage : defaults.per_page
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return defaults;
|
|
68
|
-
}
|