Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/js/components/ManageMenu/SnippetsTable/SnippetsListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { getTableColumns } from './TableColumns'
import { useFilteredSnippets } from './WithFilteredSnippetsContext'
import { INDEX_STATUS, useSnippetsFilters } from './WithSnippetsTableFilters'
import { BULK_ACTIONS, TRASHED_BULK_ACTIONS, useApplyBulkAction } from './useApplyBulkAction'
import type { ListTableAction } from '../../common/ListTable'
import type { ListTableAction, ListTableSortDirection } from '../../common/ListTable'
import type { SnippetsTableAction } from './useApplyBulkAction'
import type { Snippet } from '../../../types/Snippet'
import type { SnippetView } from '../../../types/SnippetView'
Expand Down Expand Up @@ -141,6 +141,7 @@ const SnippetsView: React.FC<SnippetsViewProps> = ({
: <ListTable
items={snippets}
getKey={snippet => snippet.id}
initialSort={getInitialSort()}
className={classnames({ 'truncate-row-values': truncateRowValues })}
columns={columns}
actions={actions}
Expand All @@ -155,6 +156,23 @@ const SnippetsView: React.FC<SnippetsViewProps> = ({
/>
}

/**
* The "Snippets List Order" setting names a default ordering for the table,
* which sorting is now expressed through columns. Map one to the other so the
* setting still decides how the list opens; clicking a heading overrides it for
* the rest of the visit, as it does for any other starting order.
*/
const LIST_ORDER_SORTS: Record<string, { columnId: string, direction: ListTableSortDirection }> = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to encode a table – just partition on - and pass the first half as the column ID, the second as the direction.

'priority-asc': { columnId: 'priority', direction: 'asc' },
'name-asc': { columnId: 'name', direction: 'asc' },
'name-desc': { columnId: 'name', direction: 'desc' },
'modified-desc': { columnId: 'date', direction: 'desc' },
'modified-asc': { columnId: 'date', direction: 'asc' }
}

const getInitialSort = () =>
LIST_ORDER_SORTS[window.CODE_SNIPPETS_MANAGE?.listOrder ?? ''] ?? undefined

export interface SnippetsListTableProps {
snippetView: SnippetView
setSnippetView: (view: SnippetView) => void
Expand Down
14 changes: 12 additions & 2 deletions src/js/components/common/ListTable/ListTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,30 @@ export interface ListTableProps<T, K extends Key, A extends string> extends List
items: T[]
beforeTable?: ReactNode
selectAllControl?: boolean

/** Column and direction to sort by before the reader touches a heading. */
initialSort?: { columnId: string, direction: ListTableSortDirection }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is better passed as separate values instead of an object?

}

export const ListTable = <T, K extends Key, A extends string = never>({
items,
getKey,
totalPages,
pageSearchParam = 'paged',
initialSort,
...tableProps
}: ListTableProps<T, K, A>) => {
const [sortColumn, setSortColumn] = useState<ListTableColumn<T>>()
const [sortColumn, setSortColumn] = useState<ListTableColumn<T> | undefined>(
() => initialSort
? tableProps.columns.find(column => column.id === initialSort.columnId && column.sortedValue)
: undefined
)
const [currentPage, setCurrentPage] = useState(
() => pageSearchParam && Number(fetchQueryParam(pageSearchParam)) || 1
)
const [sortDirection, setSortDirection] = useState<ListTableSortDirection>('asc')
const [sortDirection, setSortDirection] = useState<ListTableSortDirection>(
() => initialSort?.direction ?? 'asc'
)

const visibleItems: T[] = useMemo(
() => pageItems(sortTableItems(items, sortColumn, sortDirection), { currentPage, totalPages }),
Expand Down
1 change: 1 addition & 0 deletions src/js/types/Window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ declare global {
snippetsList?: Snippet[]
hasNetworkCap: boolean
hiddenColumns: string[]
listOrder?: string
truncateRowValues: number | string
snippetsPerPage: number
typeCounts?: Record<string, number>
Expand Down
1 change: 1 addition & 0 deletions src/php/Admin/Menus/Manage/Manage_Menu_Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public function enqueue( array $script_dependencies, array $style_dependencies )
'supportsZipDownloads' => class_exists( 'ZipArchive' ),
'editorTheme' => get_setting( 'editor', 'theme' ),
'typeCounts' => $this->get_snippet_type_counts(),
'listOrder' => get_setting( 'general', 'list_order' ),
];

if ( $this->screen_options->is_manage_table_view() ) {
Expand Down
39 changes: 39 additions & 0 deletions tests/e2e/code-snippets-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,42 @@ test.describe('Manage table Screen Options', () => {
await page.waitForLoadState('networkidle')
})
})

test.describe('Snippets list order setting', () => {
const PREFIX = 'E2E Order Test'
const names = ['E2E Order Test Alpha', 'E2E Order Test Zulu']

test.beforeAll(async () => {
await SnippetsTestHelper.cleanupSnippetsByPrefix(PREFIX)
for (const name of names) {
await SnippetsTestHelper.createSnippetViaCli({ name, active: false, type: 'php' })
}
})

test.afterAll(async () => {
await SnippetsTestHelper.cleanupSnippetsByPrefix(PREFIX)
await SnippetsTestHelper.setListOrder('priority-asc')
})

const firstMatchingName = async (page: Page): Promise<string> => {
const rows = page.locator(`${SELECTORS.SNIPPET_ROW}:has(a${SELECTORS.SNIPPET_NAME_LINK})`)
await rows.first().waitFor()
const all = await rows.locator(`a${SELECTORS.SNIPPET_NAME_LINK}`).allInnerTexts()
return all.find(name => name.startsWith(PREFIX)) ?? ''
}

// The setting describes itself as the default order for this screen, so it
// decides how the table opens. Sorting moved to the column headings during
// the admin rewrite and the setting was left reading nothing at all.
test('Snippets List Order decides the order the table opens in', async ({ page }) => {
const helper = new SnippetsTestHelper(page)

await SnippetsTestHelper.setListOrder('name-asc')
await helper.navigateToSnippetsAdmin()
expect(await firstMatchingName(page)).toBe('E2E Order Test Alpha')

await SnippetsTestHelper.setListOrder('name-desc')
await helper.navigateToSnippetsAdmin()
expect(await firstMatchingName(page)).toBe('E2E Order Test Zulu')
})
})
4 changes: 4 additions & 0 deletions tests/e2e/helpers/SnippetsTestHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export class SnippetsTestHelper {
await wpCli(['eval', php])
}

static async setListOrder(order: string): Promise<void> {
await wpCli(['eval', `\\Code_Snippets\\Settings\\update_setting('general', 'list_order', '${order}');`])
}

static async setSnippetsPerPage(perPage: number): Promise<void> {
const php = `
$user = get_user_by('login', 'admin');
Expand Down
1 change: 1 addition & 0 deletions tests/unit/Admin/Menus/Manage/Manage_Menu_Assets_Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function test_enqueue_localizes_manage_data(): void {
'supportsZipDownloads',
'editorTheme',
'typeCounts',
'listOrder',
'snippetsList',
],
array_keys( $localized )
Expand Down
Loading