-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
feat: Index fields #7382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Index fields #7382
Changes from all commits
380bc60
618b6ed
fc355a0
4c99ad1
db6b1b0
a9e5828
2552d93
4df5976
b307868
991c208
532d30d
08c19a8
01f6db2
25d15f4
362ac96
3f1b3a3
38a80b5
f32a871
05b15c4
0a8af08
b5dc663
9f216b4
72df729
3b497a5
573204a
6d08159
578dc4b
ec04105
a0a219d
b3b3c55
45de5cf
51ae2df
58a68ec
edf033c
5338816
5f1ac72
a6875d0
fc42467
c413866
af9309b
02caeaa
3d8fe14
9308a58
4efba64
c7b4ad2
1801c14
8fc9cf3
80195fc
cc7dc84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import '../utils/dismiss-local-backup'; | ||
| import { | ||
| login, | ||
| createPostAndPublish, | ||
| assertPublishedEntry, | ||
| } from '../utils/steps'; | ||
|
|
||
| const indexFileEntry = { | ||
| title: 'Index Page', | ||
| body: 'This is the index page content.', | ||
| }; | ||
|
|
||
| const regularEntry = { | ||
| title: 'Regular Post', | ||
| body: 'This is a regular post content.', | ||
| }; | ||
|
|
||
| const backend = 'test'; | ||
|
|
||
| describe('Index File Feature', () => { | ||
| before(() => { | ||
| Cypress.config('defaultCommandTimeout', 4000); | ||
| cy.task('setupBackend', { backend, options: { publish_mode: 'simple' } }); | ||
| }); | ||
|
|
||
| after(() => { | ||
| cy.task('teardownBackend', { backend }); | ||
| }); | ||
|
|
||
| it('successfully loads with index file configured', () => { | ||
| login(); | ||
| }); | ||
|
|
||
| it('can create and publish an index file entry', () => { | ||
| login(); | ||
| createPostAndPublish(indexFileEntry); | ||
| assertPublishedEntry(indexFileEntry); | ||
| }); | ||
|
|
||
| it('can create and publish a regular entry alongside index file', () => { | ||
| login(); | ||
| createPostAndPublish(regularEntry); | ||
| assertPublishedEntry(regularEntry); | ||
| }); | ||
|
|
||
| it('displays correct entry type in list when index file exists', () => { | ||
| login(); | ||
| // Verify that entries list loads and displays both regular and index entries | ||
| cy.contains('a', 'New Post'); | ||
| cy.get('[data-testid="list-control"]').should('exist'); | ||
| }); | ||
|
|
||
| it('can distinguish between index and regular entries in editor', () => { | ||
| login(); | ||
| // Navigate to entries list | ||
| cy.contains('a', 'Writing in').click(); | ||
| // Should see entries listed | ||
| cy.get('[class*="entrylist"]').should('exist'); | ||
| }); | ||
|
|
||
| it('can edit and republish index file entry', () => { | ||
| login(); | ||
| createPostAndPublish(indexFileEntry); | ||
|
|
||
| // Navigate to entries list | ||
| cy.contains('a', 'Writing in').click(); | ||
| cy.contains(indexFileEntry.title).click(); | ||
|
|
||
| // Update content | ||
| const updatedTitle = 'Updated Index Page'; | ||
| cy.get('input[name="title"]').clear(); | ||
| cy.get('input[name="title"]').type(updatedTitle); | ||
| cy.get('textarea[name="body"]').clear(); | ||
| cy.get('textarea[name="body"]').type('Updated index content.'); | ||
|
|
||
| // Publish changes | ||
| cy.contains('button', 'Publish').click(); | ||
| cy.contains('Published to').should('exist'); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,11 +16,11 @@ import { SortDirection } from '../types/redux'; | |||||||||||||||||||||||||||||||||||||
| import { waitForMediaLibraryToLoad, loadMedia } from './mediaLibrary'; | ||||||||||||||||||||||||||||||||||||||
| import { waitUntil } from './waitUntil'; | ||||||||||||||||||||||||||||||||||||||
| import { selectIsFetching, selectEntriesSortFields, selectEntryByPath } from '../reducers/entries'; | ||||||||||||||||||||||||||||||||||||||
| import { selectCustomPath } from '../reducers/entryDraft'; | ||||||||||||||||||||||||||||||||||||||
| import { navigateToEntry } from '../routing/history'; | ||||||||||||||||||||||||||||||||||||||
| import { getProcessSegment } from '../lib/formatters'; | ||||||||||||||||||||||||||||||||||||||
| import { hasI18n, duplicateDefaultI18nFields, serializeI18n, I18N, I18N_FIELD } from '../lib/i18n'; | ||||||||||||||||||||||||||||||||||||||
| import { addNotification } from './notifications'; | ||||||||||||||||||||||||||||||||||||||
| import { selectCustomPath } from '../reducers/entryDraft'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import type { ImplementationMediaFile } from 'decap-cms-lib-util'; | ||||||||||||||||||||||||||||||||||||||
| import type { AnyAction } from 'redux'; | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -34,6 +34,7 @@ import type { | |||||||||||||||||||||||||||||||||||||
| ViewFilter, | ||||||||||||||||||||||||||||||||||||||
| ViewGroup, | ||||||||||||||||||||||||||||||||||||||
| Entry, | ||||||||||||||||||||||||||||||||||||||
| Entries, | ||||||||||||||||||||||||||||||||||||||
| } from '../types/redux'; | ||||||||||||||||||||||||||||||||||||||
| import type { EntryValue } from '../valueObjects/Entry'; | ||||||||||||||||||||||||||||||||||||||
| import type { Backend } from '../backend'; | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -389,7 +390,8 @@ export function draftDuplicateEntry(entry: EntryMap) { | |||||||||||||||||||||||||||||||||||||
| type: DRAFT_CREATE_DUPLICATE_FROM_ENTRY, | ||||||||||||||||||||||||||||||||||||||
| payload: createEntry(entry.get('collection'), '', '', { | ||||||||||||||||||||||||||||||||||||||
| data: entry.get('data'), | ||||||||||||||||||||||||||||||||||||||
| i18n: entry.get('i18n'), | ||||||||||||||||||||||||||||||||||||||
| meta: entry.get('meta').toJS(), | ||||||||||||||||||||||||||||||||||||||
| i18n: entry.get('i18n').toJS(), | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| mediaFiles: entry.get('mediaFiles').toJS(), | ||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -1019,6 +1021,19 @@ function getPathError( | |||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| function getExistingEntry( | ||||||||||||||||||||||||||||||||||||||
| entries: Entries, | ||||||||||||||||||||||||||||||||||||||
| collection: Collection, | ||||||||||||||||||||||||||||||||||||||
| path: string, | ||||||||||||||||||||||||||||||||||||||
| path_type: string, | ||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||
| const customPath = selectCustomPath(collection, fromJS({ entry: { meta: { path, path_type } } })); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1028
to
+1030
|
||||||||||||||||||||||||||||||||||||||
| path_type: string, | |
| ) { | |
| const customPath = selectCustomPath(collection, fromJS({ entry: { meta: { path, path_type } } })); | |
| pathType: string, | |
| ) { | |
| const customPath = selectCustomPath( | |
| collection, | |
| fromJS({ entry: { meta: { path, path_type: pathType } } }), | |
| ); |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name uses snake_case (path_type) which is inconsistent with JavaScript/TypeScript naming conventions. While this matches the data property name, for local variables camelCase (pathType) is more conventional in JavaScript/TypeScript code.
| path_type: string, | |
| ) { | |
| const customPath = selectCustomPath(collection, fromJS({ entry: { meta: { path, path_type } } })); | |
| pathType: string, | |
| ) { | |
| const customPath = selectCustomPath( | |
| collection, | |
| fromJS({ entry: { meta: { path, path_type: pathType } } }), | |
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, calling
.toJS()onentry.get('meta')may fail if meta is undefined. While meta is more commonly present, it's safer to add a check or provide a fallback value to avoid potential runtime errors.