PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / ManageMenu / SnippetsTable / SnippetsListTable.tsx

SnippetsListTable.tsx in Code Snippets 3.10.2, at js/components/ManageMenu/SnippetsTable/SnippetsListTable.tsx

223 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __ } from '@wordpress/i18n'
2 import React, { useEffect, useMemo, useState } from 'react'
3 import classnames from 'classnames'
4 import { getSnippetType, isSnippetActive } from '../../../utils/snippets/snippets'
5 import { buildUrl } from '../../../utils/urls'
6 import { ListTable } from '../../common/ListTable'
7 import { SnippetViewToggle } from '../../common/SnippetViewToggle'
8 import { SnippetsCardGrid } from './SnippetsCardGrid'
9 import { SnippetsTableNavigation, SnippetsTableToolbar } from './SnippetsTableControls'
10 import { SearchResultsIndicator } from './SnippetsTableSearch'
11 import { getTableColumns } from './TableColumns'
12 import { useFilteredSnippets } from './WithFilteredSnippetsContext'
13 import { INDEX_STATUS, useSnippetsFilters } from './WithSnippetsTableFilters'
14 import { BULK_ACTIONS, TRASHED_BULK_ACTIONS, useApplyBulkAction } from './useApplyBulkAction'
15 import type { ListTableAction, ListTableSortDirection } from '../../common/ListTable'
16 import type { SnippetsTableAction } from './useApplyBulkAction'
17 import type { Snippet } from '../../../types/Snippet'
18 import type { SnippetView } from '../../../types/SnippetView'
19 import type { ReactNode } from 'react'
20
21 interface ManageTableSettings {
22 hiddenColumns: Set<string>
23 truncateRowValues: boolean
24 }
25
26 const useManageTableSettings = (): ManageTableSettings => {
27 const [hiddenColumns, setHiddenColumns] = useState(
28 () => new Set(window.CODE_SNIPPETS_MANAGE?.hiddenColumns ?? [])
29 )
30 const [truncateRowValues, setTruncateRowValues] = useState(
31 () => 0 !== Number(window.CODE_SNIPPETS_MANAGE?.truncateRowValues ?? 1)
32 )
33
34 useEffect(() => {
35 const screenOptions = document.getElementById('adv-settings')
36
37 if (!screenOptions) {
38 return
39 }
40
41 const updateHiddenColumns = () => {
42 setHiddenColumns(
43 new Set(Array.from(screenOptions.querySelectorAll<HTMLInputElement>(
44 '.hide-column-tog:not(:checked)'
45 ))
46 .map(toggle => toggle.value))
47 )
48
49 setTruncateRowValues(
50 screenOptions.querySelector<HTMLInputElement>(
51 '#snippets-table-truncate-row-values'
52 )?.checked ?? true
53 )
54 }
55
56 updateHiddenColumns()
57 screenOptions.addEventListener('change', updateHiddenColumns)
58
59 return () => {
60 screenOptions.removeEventListener('change', updateHiddenColumns)
61 }
62 }, [])
63
64 return { hiddenColumns, truncateRowValues }
65 }
66
67 const NoItemsMessage = () => {
68 const { currentType, currentTag, searchQuery } = useSnippetsFilters()
69 const emptyMessage = currentType
70 ? __("You don't have snippets of this type yet.", 'code-snippets')
71 : __("You don't have any snippets yet.", 'code-snippets')
72
73 return searchQuery || currentTag
74 ? <>
75 {__('No snippets were found matching the current search query.', 'code-snippets')}
76 {__(' Please enter a new query or use the "Clear Filters" button above.', 'code-snippets')}
77 </>
78 : <>
79 {emptyMessage}{' '}
80 <a href={buildUrl(window.CODE_SNIPPETS?.urls.addNew, { type: currentType })}>
81 {__('Add a new snippet.', 'code-snippets')}
82 </a>
83 </>
84 }
85
86 const getRowClassName = (
87 snippet: Snippet,
88 activeByCondition: Map<Snippet['id'], Snippet[]>
89 ): string =>
90 classnames(
91 'snippet',
92 `snippet ${isSnippetActive(snippet, activeByCondition) ? 'active' : 'inactive'}-snippet`,
93 `${getSnippetType(snippet)}-snippet`,
94 `${snippet.scope}-snippet`,
95 {
96 'trashed-snippet': snippet.trashed
97 }
98 )
99
100 interface SnippetsViewProps {
101 snippetView: SnippetView
102 setSnippetView: (view: SnippetView) => void
103 snippets: Snippet[]
104 actions: ListTableAction<SnippetsTableAction>[]
105 doAction: (action: SnippetsTableAction | undefined, selected: Set<Snippet['id']>) => Promise<void>
106 extraTableNav: (which: 'top' | 'bottom') => ReactNode
107 hiddenColumns: Set<string>
108 truncateRowValues: boolean
109 }
110
111 const SnippetsView: React.FC<SnippetsViewProps> = ({
112 snippetView,
113 setSnippetView,
114 snippets,
115 actions,
116 doAction,
117 extraTableNav,
118 hiddenColumns,
119 truncateRowValues
120 }) => {
121 const { activeByCondition } = useFilteredSnippets()
122 const columns = useMemo(() => getTableColumns(hiddenColumns), [hiddenColumns])
123 const itemsPerPage = window.CODE_SNIPPETS_MANAGE?.snippetsPerPage
124 const pageCount = itemsPerPage && Math.ceil(snippets.length / itemsPerPage)
125 const endTableNav = (which: 'top' | 'bottom') =>
126 'top' === which
127 ? <SnippetViewToggle snippetView={snippetView} setSnippetView={setSnippetView} />
128 : null
129
130 return 'card' === snippetView
131 ? <SnippetsCardGrid
132 snippets={snippets}
133 actions={actions}
134 doAction={doAction}
135 itemsPerPage={itemsPerPage}
136 extraTableNav={extraTableNav}
137 endTableNav={endTableNav}
138 noItems={<NoItemsMessage />}
139 beforeGrid={<SearchResultsIndicator />}
140 />
141 : <ListTable
142 items={snippets}
143 getKey={snippet => snippet.id}
144 initialSort={getInitialSort()}
145 className={classnames({ 'truncate-row-values': truncateRowValues })}
146 columns={columns}
147 actions={actions}
148 doAction={doAction}
149 totalPages={pageCount}
150 extraTableNav={extraTableNav}
151 selectAllControl
152 endTableNav={endTableNav}
153 rowClassName={snippet => getRowClassName(snippet, activeByCondition)}
154 noItems={<NoItemsMessage />}
155 beforeTable={<SearchResultsIndicator />}
156 />
157 }
158
159 /**
160 * The "Snippets List Order" setting names a default ordering for the table,
161 * which sorting is now expressed through columns. Map one to the other so the
162 * setting still decides how the list opens; clicking a heading overrides it for
163 * the rest of the visit, as it does for any other starting order.
164 */
165 const LIST_ORDER_SORTS: Record<string, { columnId: string, direction: ListTableSortDirection }> = {
166 'priority-asc': { columnId: 'priority', direction: 'asc' },
167 'name-asc': { columnId: 'name', direction: 'asc' },
168 'name-desc': { columnId: 'name', direction: 'desc' },
169 'modified-desc': { columnId: 'date', direction: 'desc' },
170 'modified-asc': { columnId: 'date', direction: 'asc' }
171 }
172
173 const getInitialSort = () =>
174 LIST_ORDER_SORTS[window.CODE_SNIPPETS_MANAGE?.listOrder ?? ''] ?? undefined
175
176 export interface SnippetsListTableProps {
177 snippetView: SnippetView
178 setSnippetView: (view: SnippetView) => void
179 }
180
181 export const SnippetsListTable: React.FC<SnippetsListTableProps> = ({
182 snippetView,
183 setSnippetView
184 }) => {
185 const { snippetsByStatus } = useFilteredSnippets()
186 const { currentStatus, setCurrentStatus } = useSnippetsFilters()
187 const { hiddenColumns, truncateRowValues } = useManageTableSettings()
188
189 const currentSnippets = useMemo(
190 () => snippetsByStatus.get(currentStatus) ?? [],
191 [snippetsByStatus, currentStatus]
192 )
193 const applyBulkAction = useApplyBulkAction(currentSnippets)
194
195 useEffect(() => {
196 if (INDEX_STATUS !== currentStatus && !snippetsByStatus.has(currentStatus)) {
197 setCurrentStatus(INDEX_STATUS)
198 }
199 }, [currentStatus, setCurrentStatus, snippetsByStatus])
200
201 const extraTableNav = (which: 'top' | 'bottom') =>
202 <SnippetsTableNavigation which={which} visibleSnippets={snippetsByStatus.get('all') ?? []} />
203
204 return (
205 <>
206 <SnippetsTableToolbar />
207
208 <div className="snippets-list-view">
209 <SnippetsView
210 snippetView={snippetView}
211 setSnippetView={setSnippetView}
212 snippets={currentSnippets}
213 actions={'trashed' === currentStatus ? TRASHED_BULK_ACTIONS : BULK_ACTIONS}
214 doAction={applyBulkAction}
215 extraTableNav={extraTableNav}
216 hiddenColumns={hiddenColumns}
217 truncateRowValues={truncateRowValues}
218 />
219 </div>
220 </>
221 )
222 }
223