decap-cms-core 3.13.0 → 3.14.0
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 +18 -18
- package/dist/decap-cms-core.js.map +1 -1
- package/dist/esm/actions/config.js +14 -1
- package/dist/esm/actions/entries.js +15 -4
- package/dist/esm/backend.js +2 -0
- package/dist/esm/bootstrap.js +2 -2
- package/dist/esm/components/App/App.js +12 -5
- package/dist/esm/components/App/Header.js +18 -18
- package/dist/esm/components/Collection/Entries/EntryCard.js +30 -15
- package/dist/esm/components/Collection/NestedCollection.js +20 -11
- package/dist/esm/components/Editor/EditorPreviewPane/EditorPreviewPane.js +22 -6
- package/dist/esm/components/UI/ErrorBoundary.js +2 -2
- package/dist/esm/components/UI/SettingsDropdown.js +25 -27
- package/dist/esm/constants/configSchema.js +1 -1
- package/dist/esm/lib/registry.js +4 -1
- package/dist/esm/reducers/entryDraft.js +36 -3
- package/index.d.ts +17 -1
- package/package.json +2 -2
- package/src/__tests__/backend.spec.js +214 -0
- package/src/actions/__tests__/config.spec.js +14 -0
- package/src/actions/__tests__/entries.spec.js +36 -1
- package/src/actions/config.ts +13 -1
- package/src/actions/entries.ts +22 -7
- package/src/backend.ts +2 -0
- package/src/components/App/App.js +22 -13
- package/src/components/App/Header.js +36 -11
- package/src/components/Collection/Entries/EntryCard.js +13 -3
- package/src/components/Collection/NestedCollection.js +14 -7
- package/src/components/Collection/__tests__/NestedCollection.spec.js +1 -1
- package/src/components/Collection/__tests__/__snapshots__/NestedCollection.spec.js.snap +0 -68
- package/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +6 -5
- package/src/components/Editor/__tests__/__snapshots__/EditorToolbar.spec.js.snap +104 -72
- package/src/components/UI/SettingsDropdown.js +36 -9
- package/src/constants/__tests__/configSchema.spec.js +9 -6
- package/src/constants/configSchema.js +1 -1
- package/src/lib/__tests__/formatters.spec.js +16 -4
- package/src/lib/__tests__/registry.spec.js +3 -3
- package/src/lib/registry.js +4 -1
- package/src/reducers/__tests__/entryDraft.spec.js +117 -0
- package/src/reducers/entryDraft.js +43 -3
- package/src/types/redux.ts +19 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fromJS, Map } from 'immutable';
|
|
1
|
+
import { fromJS, List, Map } from 'immutable';
|
|
2
2
|
import configureMockStore from 'redux-mock-store';
|
|
3
3
|
import thunk from 'redux-thunk';
|
|
4
4
|
|
|
@@ -99,6 +99,41 @@ describe('entries', () => {
|
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
it('should populate draft entry from repeated URL param', () => {
|
|
103
|
+
const store = mockStore({ mediaLibrary: fromJS({ files: [] }) });
|
|
104
|
+
|
|
105
|
+
const collection = fromJS({
|
|
106
|
+
fields: [{ name: 'post', multiple: true }],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return store
|
|
110
|
+
.dispatch(createEmptyDraft(collection, '?post=2026-05-07-test&post=2026-05-08-test'))
|
|
111
|
+
.then(() => {
|
|
112
|
+
const actions = store.getActions();
|
|
113
|
+
expect(actions).toHaveLength(1);
|
|
114
|
+
|
|
115
|
+
expect(actions[0]).toEqual({
|
|
116
|
+
payload: {
|
|
117
|
+
author: '',
|
|
118
|
+
collection: undefined,
|
|
119
|
+
data: { post: List(['2026-05-07-test', '2026-05-08-test']) },
|
|
120
|
+
meta: {},
|
|
121
|
+
i18n: {},
|
|
122
|
+
isModification: null,
|
|
123
|
+
label: null,
|
|
124
|
+
mediaFiles: [],
|
|
125
|
+
partial: false,
|
|
126
|
+
path: '',
|
|
127
|
+
raw: '',
|
|
128
|
+
slug: '',
|
|
129
|
+
status: '',
|
|
130
|
+
updatedOn: '',
|
|
131
|
+
},
|
|
132
|
+
type: 'DRAFT_CREATE_EMPTY',
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
102
137
|
it('should html escape URL params', () => {
|
|
103
138
|
const store = mockStore({ mediaLibrary: fromJS({ files: [] }) });
|
|
104
139
|
|
package/src/actions/config.ts
CHANGED
|
@@ -308,11 +308,12 @@ export function applyDefaults(originalConfig: CmsConfig) {
|
|
|
308
308
|
collection.folder = trim(folder, '/');
|
|
309
309
|
|
|
310
310
|
if (meta && meta.path) {
|
|
311
|
+
const metaPath = meta.path;
|
|
311
312
|
const metaField = {
|
|
312
313
|
name: 'path',
|
|
313
314
|
meta: true,
|
|
314
315
|
required: true,
|
|
315
|
-
...
|
|
316
|
+
...metaPath,
|
|
316
317
|
};
|
|
317
318
|
collection.fields = [metaField, ...(collection.fields || [])];
|
|
318
319
|
}
|
|
@@ -458,6 +459,17 @@ export async function detectProxyServer(localBackend?: boolean | CmsLocalBackend
|
|
|
458
459
|
? defaultUrl
|
|
459
460
|
: localBackend.url || defaultUrl.replace('localhost', location.hostname);
|
|
460
461
|
|
|
462
|
+
try {
|
|
463
|
+
const { protocol } = new URL(proxyUrl);
|
|
464
|
+
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
465
|
+
console.log(`Decap CMS local_backend url must use http or https, ignoring '${proxyUrl}'`);
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
} catch {
|
|
469
|
+
console.log(`Decap CMS local_backend url '${proxyUrl}' is not a valid URL`);
|
|
470
|
+
return {};
|
|
471
|
+
}
|
|
472
|
+
|
|
461
473
|
try {
|
|
462
474
|
console.log(`Looking for Decap CMS Proxy Server at '${proxyUrl}'`);
|
|
463
475
|
const res = await fetch(`${proxyUrl}`, {
|
package/src/actions/entries.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { fromJS, List, Map } from 'immutable';
|
|
1
|
+
import { fromJS, List, Map, Set } from 'immutable';
|
|
2
2
|
import isEqual from 'lodash/isEqual';
|
|
3
3
|
import { Cursor } from 'decap-cms-lib-util';
|
|
4
4
|
|
|
5
5
|
import { selectCollectionEntriesCursor } from '../reducers/cursors';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
selectFields,
|
|
8
|
+
selectField,
|
|
9
|
+
updateFieldByKey,
|
|
10
|
+
selectDefaultSortField,
|
|
11
|
+
} from '../reducers/collections';
|
|
7
12
|
import { selectIntegration, selectPublishedSlugs } from '../reducers';
|
|
8
13
|
import { getIntegrationProvider } from '../integrations';
|
|
9
14
|
import { currentBackend } from '../backend';
|
|
@@ -38,7 +43,6 @@ import type {
|
|
|
38
43
|
import type { EntryValue } from '../valueObjects/Entry';
|
|
39
44
|
import type { Backend } from '../backend';
|
|
40
45
|
import type AssetProxy from '../valueObjects/AssetProxy';
|
|
41
|
-
import type { Set } from 'immutable';
|
|
42
46
|
|
|
43
47
|
/*
|
|
44
48
|
* Constant Declarations
|
|
@@ -740,10 +744,21 @@ function getMetaFields(fields: EntryFields) {
|
|
|
740
744
|
export function createEmptyDraft(collection: Collection, search: string) {
|
|
741
745
|
return async (dispatch: ThunkDispatch<State, {}, AnyAction>, getState: () => State) => {
|
|
742
746
|
const params = new URLSearchParams(search);
|
|
743
|
-
params.
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
);
|
|
747
|
+
const uniqueKeys = Set([...params.keys()]).toArray();
|
|
748
|
+
|
|
749
|
+
uniqueKeys.forEach(key => {
|
|
750
|
+
const field = selectField(collection, key);
|
|
751
|
+
const isMultiple = field?.get('multiple', false);
|
|
752
|
+
const values = params.getAll(key);
|
|
753
|
+
|
|
754
|
+
collection = updateFieldByKey(collection, key, field => {
|
|
755
|
+
if (isMultiple) {
|
|
756
|
+
const allValues = values.flatMap(v => v.split(',')).map(processValue);
|
|
757
|
+
return field.set('default', List(allValues));
|
|
758
|
+
} else {
|
|
759
|
+
return field.set('default', processValue(values[values.length - 1]));
|
|
760
|
+
}
|
|
761
|
+
});
|
|
747
762
|
});
|
|
748
763
|
|
|
749
764
|
const fields = collection.get('fields', List());
|
package/src/backend.ts
CHANGED
|
@@ -1184,6 +1184,7 @@ export class Backend {
|
|
|
1184
1184
|
);
|
|
1185
1185
|
|
|
1186
1186
|
const collectionName = collection.get('name');
|
|
1187
|
+
const hasSubfolders = collection.get('nested')?.get('subfolders') !== false;
|
|
1187
1188
|
|
|
1188
1189
|
const updatedOptions = { unpublished, status };
|
|
1189
1190
|
const opts = {
|
|
@@ -1191,6 +1192,7 @@ export class Backend {
|
|
|
1191
1192
|
commitMessage,
|
|
1192
1193
|
collectionName,
|
|
1193
1194
|
useWorkflow,
|
|
1195
|
+
hasSubfolders,
|
|
1194
1196
|
...updatedOptions,
|
|
1195
1197
|
};
|
|
1196
1198
|
|
|
@@ -156,6 +156,7 @@ class App extends React.Component {
|
|
|
156
156
|
openMediaLibrary,
|
|
157
157
|
t,
|
|
158
158
|
showMediaButton,
|
|
159
|
+
location,
|
|
159
160
|
} = this.props;
|
|
160
161
|
|
|
161
162
|
if (config === null) {
|
|
@@ -177,22 +178,30 @@ class App extends React.Component {
|
|
|
177
178
|
const defaultPath = getDefaultPath(collections);
|
|
178
179
|
const hasWorkflow = publishMode === EDITORIAL_WORKFLOW;
|
|
179
180
|
|
|
181
|
+
// Work out if this is an editor route, following the same URL matching as the router.
|
|
182
|
+
// - /collections/:name/entries/*
|
|
183
|
+
// - /collections/:name/new
|
|
184
|
+
const [, base, , view] = location.pathname.split('/');
|
|
185
|
+
const isEditorRoute = base === 'collections' && (view === 'entries' || view === 'new');
|
|
186
|
+
|
|
180
187
|
return (
|
|
181
188
|
<>
|
|
182
189
|
<Notifications />
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
{!isEditorRoute && (
|
|
191
|
+
<Header
|
|
192
|
+
user={user}
|
|
193
|
+
collections={collections}
|
|
194
|
+
onCreateEntryClick={createNewEntry}
|
|
195
|
+
onLogoutClick={logoutUser}
|
|
196
|
+
openMediaLibrary={openMediaLibrary}
|
|
197
|
+
hasWorkflow={hasWorkflow}
|
|
198
|
+
displayUrl={config.display_url}
|
|
199
|
+
logoUrl={config.logo_url} // Deprecated, replaced by `logo.src`
|
|
200
|
+
logo={config.logo}
|
|
201
|
+
isTestRepo={config.backend.name === 'test-repo'}
|
|
202
|
+
showMediaButton={showMediaButton}
|
|
203
|
+
/>
|
|
204
|
+
)}
|
|
196
205
|
<AppMainContainer>
|
|
197
206
|
{isFetching && <TopBarProgress />}
|
|
198
207
|
<Switch>
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
DropdownItem,
|
|
12
12
|
StyledDropdownButton,
|
|
13
13
|
colors,
|
|
14
|
-
lengths,
|
|
15
14
|
shadows,
|
|
16
15
|
buttons,
|
|
17
16
|
zIndex,
|
|
@@ -32,12 +31,14 @@ function AppHeader(props) {
|
|
|
32
31
|
<header
|
|
33
32
|
css={css`
|
|
34
33
|
${shadows.dropMain};
|
|
35
|
-
position: sticky;
|
|
36
34
|
width: 100%;
|
|
37
|
-
top: 0;
|
|
38
35
|
background-color: ${colors.foreground};
|
|
39
36
|
z-index: ${zIndex.zIndex300};
|
|
40
|
-
|
|
37
|
+
|
|
38
|
+
@media (min-height: 500px) {
|
|
39
|
+
position: sticky;
|
|
40
|
+
top: 0;
|
|
41
|
+
}
|
|
41
42
|
`}
|
|
42
43
|
{...props}
|
|
43
44
|
/>
|
|
@@ -46,11 +47,15 @@ function AppHeader(props) {
|
|
|
46
47
|
|
|
47
48
|
const AppHeaderContent = styled.div`
|
|
48
49
|
display: flex;
|
|
49
|
-
|
|
50
|
-
min-width: 800px;
|
|
51
|
-
max-width: 1440px;
|
|
50
|
+
flex-direction: column-reverse;
|
|
52
51
|
padding: 0 12px;
|
|
53
52
|
margin: 0 auto;
|
|
53
|
+
|
|
54
|
+
@media (min-width: 800px) {
|
|
55
|
+
max-width: 1440px;
|
|
56
|
+
flex-direction: row;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
}
|
|
54
59
|
`;
|
|
55
60
|
|
|
56
61
|
const AppHeaderButton = styled.button`
|
|
@@ -58,14 +63,27 @@ const AppHeaderButton = styled.button`
|
|
|
58
63
|
background: none;
|
|
59
64
|
color: #7b8290;
|
|
60
65
|
font-family: inherit;
|
|
61
|
-
font-size:
|
|
66
|
+
font-size: 13px;
|
|
67
|
+
line-height: 1;
|
|
62
68
|
font-weight: 500;
|
|
63
69
|
display: inline-flex;
|
|
64
|
-
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 2px;
|
|
72
|
+
padding: 0 10px 10px;
|
|
65
73
|
align-items: center;
|
|
74
|
+
text-align: center;
|
|
75
|
+
|
|
76
|
+
@media (min-width: 400px) {
|
|
77
|
+
flex-direction: row;
|
|
78
|
+
gap: 4px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@media (min-width: 500px) {
|
|
82
|
+
font-size: 16px;
|
|
83
|
+
padding: 16px 20px;
|
|
84
|
+
}
|
|
66
85
|
|
|
67
86
|
${Icon} {
|
|
68
|
-
margin-right: 4px;
|
|
69
87
|
color: #b3b9c4;
|
|
70
88
|
}
|
|
71
89
|
|
|
@@ -93,14 +111,16 @@ const AppHeaderButton = styled.button`
|
|
|
93
111
|
const AppHeaderNavLink = AppHeaderButton.withComponent(NavLink);
|
|
94
112
|
|
|
95
113
|
const AppHeaderActions = styled.div`
|
|
96
|
-
display:
|
|
114
|
+
display: flex;
|
|
97
115
|
align-items: center;
|
|
116
|
+
justify-content: space-between;
|
|
98
117
|
`;
|
|
99
118
|
|
|
100
119
|
const AppHeaderQuickNewButton = styled(StyledDropdownButton)`
|
|
101
120
|
${buttons.button};
|
|
102
121
|
${buttons.medium};
|
|
103
122
|
${buttons.gray};
|
|
123
|
+
white-space: nowrap;
|
|
104
124
|
margin-right: 8px;
|
|
105
125
|
|
|
106
126
|
&:after {
|
|
@@ -112,6 +132,11 @@ const AppHeaderNavList = styled.ul`
|
|
|
112
132
|
display: flex;
|
|
113
133
|
margin: 0;
|
|
114
134
|
list-style: none;
|
|
135
|
+
justify-content: space-around;
|
|
136
|
+
|
|
137
|
+
@media (min-width: 800px) {
|
|
138
|
+
justify-content: flex-start;
|
|
139
|
+
}
|
|
115
140
|
`;
|
|
116
141
|
|
|
117
142
|
const AppHeaderLogo = styled.li`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import styled from '@emotion/styled';
|
|
3
3
|
import { connect } from 'react-redux';
|
|
4
4
|
import { Link } from 'react-router-dom';
|
|
@@ -86,7 +86,7 @@ const CardBody = styled.div`
|
|
|
86
86
|
}
|
|
87
87
|
`;
|
|
88
88
|
|
|
89
|
-
const
|
|
89
|
+
const StyledImage = styled.div`
|
|
90
90
|
background-image: url(${props => props.src});
|
|
91
91
|
background-position: center center;
|
|
92
92
|
background-size: cover;
|
|
@@ -131,6 +131,16 @@ const WorkflowBadge = styled.span`
|
|
|
131
131
|
}};
|
|
132
132
|
`;
|
|
133
133
|
|
|
134
|
+
function CardImage({ getAsset, value, field }) {
|
|
135
|
+
const [asset, setAsset] = useState(null);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
setAsset(value ? getAsset(value, field) : null);
|
|
139
|
+
}, [value, field, getAsset]);
|
|
140
|
+
|
|
141
|
+
return asset ? <StyledImage src={asset.toString()} /> : null;
|
|
142
|
+
}
|
|
143
|
+
|
|
134
144
|
function EntryCard({
|
|
135
145
|
path,
|
|
136
146
|
summary,
|
|
@@ -192,7 +202,7 @@ function EntryCard({
|
|
|
192
202
|
</TitleIcons>
|
|
193
203
|
</CardHeading>
|
|
194
204
|
</CardBody>
|
|
195
|
-
{image ? <CardImage
|
|
205
|
+
{image ? <CardImage getAsset={getAsset} value={image} field={imageField} /> : null}
|
|
196
206
|
</GridCardLink>
|
|
197
207
|
</GridCard>
|
|
198
208
|
);
|
|
@@ -67,18 +67,25 @@ const TreeNavLink = styled(NavLink)`
|
|
|
67
67
|
`};
|
|
68
68
|
`;
|
|
69
69
|
|
|
70
|
-
function getNodeTitle(node) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
function getNodeTitle(node, collection) {
|
|
71
|
+
// Backward compatibility: when `nested.subfolders` is true(default) or undefined,
|
|
72
|
+
// directory nodes should use the title of their index entry.
|
|
73
|
+
// Otherwise, use the folder name already stored in `node.title`.
|
|
74
|
+
const subfolders = collection.getIn(['nested', 'subfolders']) !== false;
|
|
75
|
+
if (!node.isRoot && node.isDir && subfolders) {
|
|
76
|
+
const indexChild = node.children.find(child => !child.isDir);
|
|
77
|
+
if (indexChild && indexChild.title) {
|
|
78
|
+
return indexChild.title;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return node.title;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
function TreeNode(props) {
|
|
78
85
|
const { collection, treeData, depth = 0, onToggle } = props;
|
|
79
86
|
const collectionName = collection.get('name');
|
|
80
87
|
|
|
81
|
-
const sortedData = sortBy(treeData, getNodeTitle);
|
|
88
|
+
const sortedData = sortBy(treeData, node => getNodeTitle(node, collection));
|
|
82
89
|
const subfolders = collection.get('nested')?.get('subfolders') !== false;
|
|
83
90
|
return sortedData.map(node => {
|
|
84
91
|
const leaf =
|
|
@@ -93,7 +100,7 @@ function TreeNode(props) {
|
|
|
93
100
|
if (depth > 0) {
|
|
94
101
|
to = `${to}/filter${node.path}`;
|
|
95
102
|
}
|
|
96
|
-
const title = getNodeTitle(node);
|
|
103
|
+
const title = getNodeTitle(node, collection);
|
|
97
104
|
|
|
98
105
|
const hasChildren =
|
|
99
106
|
depth === 0 ||
|
|
@@ -138,20 +138,6 @@ exports[`NestedCollection should render connected component 1`] = `
|
|
|
138
138
|
margin-right: 4px;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
.emotion-6 {
|
|
142
|
-
position: relative;
|
|
143
|
-
top: 2px;
|
|
144
|
-
color: #fff;
|
|
145
|
-
width: 0;
|
|
146
|
-
height: 0;
|
|
147
|
-
border: 5px solid transparent;
|
|
148
|
-
border-radius: 2px;
|
|
149
|
-
border-left: 6px solid currentColor;
|
|
150
|
-
border-right: 0;
|
|
151
|
-
color: currentColor;
|
|
152
|
-
left: 2px;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
141
|
<a
|
|
156
142
|
class="emotion-0 emotion-1"
|
|
157
143
|
data-testid="/a"
|
|
@@ -169,9 +155,6 @@ exports[`NestedCollection should render connected component 1`] = `
|
|
|
169
155
|
>
|
|
170
156
|
File 1
|
|
171
157
|
</div>
|
|
172
|
-
<div
|
|
173
|
-
class="emotion-6 emotion-7"
|
|
174
|
-
/>
|
|
175
158
|
</div>
|
|
176
159
|
</a>
|
|
177
160
|
.emotion-0 {
|
|
@@ -224,20 +207,6 @@ exports[`NestedCollection should render connected component 1`] = `
|
|
|
224
207
|
margin-right: 4px;
|
|
225
208
|
}
|
|
226
209
|
|
|
227
|
-
.emotion-6 {
|
|
228
|
-
position: relative;
|
|
229
|
-
top: 2px;
|
|
230
|
-
color: #fff;
|
|
231
|
-
width: 0;
|
|
232
|
-
height: 0;
|
|
233
|
-
border: 5px solid transparent;
|
|
234
|
-
border-radius: 2px;
|
|
235
|
-
border-left: 6px solid currentColor;
|
|
236
|
-
border-right: 0;
|
|
237
|
-
color: currentColor;
|
|
238
|
-
left: 2px;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
210
|
<a
|
|
242
211
|
class="emotion-0 emotion-1"
|
|
243
212
|
data-testid="/b"
|
|
@@ -255,9 +224,6 @@ exports[`NestedCollection should render connected component 1`] = `
|
|
|
255
224
|
>
|
|
256
225
|
File 2
|
|
257
226
|
</div>
|
|
258
|
-
<div
|
|
259
|
-
class="emotion-6 emotion-7"
|
|
260
|
-
/>
|
|
261
227
|
</div>
|
|
262
228
|
</a>
|
|
263
229
|
</DocumentFragment>
|
|
@@ -401,20 +367,6 @@ exports[`NestedCollection should render correctly with nested entries 1`] = `
|
|
|
401
367
|
margin-right: 4px;
|
|
402
368
|
}
|
|
403
369
|
|
|
404
|
-
.emotion-6 {
|
|
405
|
-
position: relative;
|
|
406
|
-
top: 2px;
|
|
407
|
-
color: #fff;
|
|
408
|
-
width: 0;
|
|
409
|
-
height: 0;
|
|
410
|
-
border: 5px solid transparent;
|
|
411
|
-
border-radius: 2px;
|
|
412
|
-
border-left: 6px solid currentColor;
|
|
413
|
-
border-right: 0;
|
|
414
|
-
color: currentColor;
|
|
415
|
-
left: 2px;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
370
|
<a
|
|
419
371
|
class="emotion-0 emotion-1"
|
|
420
372
|
data-testid="/a"
|
|
@@ -432,9 +384,6 @@ exports[`NestedCollection should render correctly with nested entries 1`] = `
|
|
|
432
384
|
>
|
|
433
385
|
File 1
|
|
434
386
|
</div>
|
|
435
|
-
<div
|
|
436
|
-
class="emotion-6 emotion-7"
|
|
437
|
-
/>
|
|
438
387
|
</div>
|
|
439
388
|
</a>
|
|
440
389
|
.emotion-0 {
|
|
@@ -487,20 +436,6 @@ exports[`NestedCollection should render correctly with nested entries 1`] = `
|
|
|
487
436
|
margin-right: 4px;
|
|
488
437
|
}
|
|
489
438
|
|
|
490
|
-
.emotion-6 {
|
|
491
|
-
position: relative;
|
|
492
|
-
top: 2px;
|
|
493
|
-
color: #fff;
|
|
494
|
-
width: 0;
|
|
495
|
-
height: 0;
|
|
496
|
-
border: 5px solid transparent;
|
|
497
|
-
border-radius: 2px;
|
|
498
|
-
border-left: 6px solid currentColor;
|
|
499
|
-
border-right: 0;
|
|
500
|
-
color: currentColor;
|
|
501
|
-
left: 2px;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
439
|
<a
|
|
505
440
|
class="emotion-0 emotion-1"
|
|
506
441
|
data-testid="/b"
|
|
@@ -518,9 +453,6 @@ exports[`NestedCollection should render correctly with nested entries 1`] = `
|
|
|
518
453
|
>
|
|
519
454
|
File 2
|
|
520
455
|
</div>
|
|
521
|
-
<div
|
|
522
|
-
class="emotion-6 emotion-7"
|
|
523
|
-
/>
|
|
524
456
|
</div>
|
|
525
457
|
</a>
|
|
526
458
|
</DocumentFragment>
|
|
@@ -224,17 +224,18 @@ export class PreviewPane extends React.Component {
|
|
|
224
224
|
* This function exists entirely to expose collections from outside of this entry
|
|
225
225
|
*
|
|
226
226
|
*/
|
|
227
|
-
getCollection = async (collectionName,
|
|
227
|
+
getCollection = async (collectionName, slugToLoad) => {
|
|
228
228
|
const { state } = this.props;
|
|
229
229
|
const selectedCollection = state.collections.get(collectionName);
|
|
230
230
|
|
|
231
|
-
if (typeof
|
|
231
|
+
if (typeof slugToLoad === 'undefined') {
|
|
232
232
|
const entries = await getAllEntries(state, selectedCollection);
|
|
233
|
-
|
|
233
|
+
|
|
234
|
+
return entries.map(({ data, slug, path }) => Map({ data, slug, path }));
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
const
|
|
237
|
-
return Map(
|
|
237
|
+
const { data, slug, path } = await tryLoadEntry(state, selectedCollection, slugToLoad);
|
|
238
|
+
return Map({ data, slug, path });
|
|
238
239
|
};
|
|
239
240
|
|
|
240
241
|
render() {
|