PluginProbe
Code Snippets / 3.10.1
Code Snippets v3.10.1
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 / ImportMenu / UploadForm / SelectSnippets / SelectSnippets.tsx

SelectSnippets.tsx in Code Snippets 3.10.1, at js/components/ImportMenu/UploadForm/SelectSnippets/SelectSnippets.tsx

180 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useEffect, useRef, useState } from 'react'
2 import { __, sprintf } from '@wordpress/i18n'
3 import { useRestAPI } from '../../../../hooks/useRestAPI'
4 import { unpackErrorResponse } from '../../../../utils/errors'
5 import { REST_BASES } from '../../../../utils/restAPI'
6 import { isNetworkAdmin } from '../../../../utils/screen'
7 import { Button } from '../../../common/Button'
8 import { ImportCard } from '../../common/ImportCard'
9 import { useSelection } from '../../../../hooks/useSelection'
10 import { SnippetSelectionTable } from './SnippetSelectionTable'
11 import type { FormEventHandler, ReactNode } from 'react'
12 import type { UseSelection } from '../../../../hooks/useSelection'
13 import type { ImportResult } from './ImportResultDisplay'
14 import type { ImportableSnippetSchema } from '../../../../types/schema/ImportableSnippetSchema'
15 import type { DuplicateAction } from '../SelectFiles/DuplicateActionSelector'
16
17 export interface SnippetImportRequest {
18 snippets: ImportableSnippetSchema[]
19 duplicate_action: 'ignore' | 'replace' | 'skip'
20 network?: boolean
21 }
22
23 export interface SnippetImportResponse {
24 imported: number
25 imported_ids: number[]
26 message: string
27 }
28
29 interface ReturnLinkProps {
30 onCancel: VoidFunction
31 clearSelection: VoidFunction
32 }
33
34 const ReturnLink: React.FC<ReturnLinkProps> = ({ onCancel, clearSelection }) =>
35 <div className="return-link">
36 <Button link onClick={() => {
37 clearSelection()
38 onCancel()
39 }}>
40 {__('← Upload Different Files', 'code-snippets')}
41 </Button>
42 </div>
43
44 interface SelectAllButtonProps {
45 selectAll: VoidFunction
46 isAllSelected: boolean
47 }
48
49 const SelectAllButton: React.FC<SelectAllButtonProps> = ({ selectAll, isAllSelected }) =>
50 <Button onClick={selectAll}>
51 {isAllSelected
52 ? __('Deselect All', 'code-snippets')
53 : __('Select All', 'code-snippets')}
54 </Button>
55
56 interface SubmitButtonProps {
57 isImporting: boolean
58 selectedCount: number
59 }
60
61 const SubmitButton: React.FC<SubmitButtonProps> = ({ isImporting, selectedCount }) =>
62 <Button type="submit" primary disabled={0 === selectedCount || isImporting}>
63 {isImporting
64 ? __('Importing…', 'code-snippets')
65 // translators: %d: number of selected snippets.
66 : sprintf(__('Import Selected (%d)', 'code-snippets'), selectedCount)}
67 </Button>
68
69 interface SelectSnippetsFormProps {
70 isImporting: boolean
71 availableSnippets: ImportableSnippetSchema[]
72 snippetSelection: UseSelection<ImportableSnippetSchema, ImportableSnippetSchema['table_data']['id']>
73 }
74
75 const SelectSnippetsForm: React.FC<SelectSnippetsFormProps> = ({ availableSnippets, snippetSelection, isImporting }) =>
76 <>
77 <div className="tablenav top">
78 <div>
79 <h2>{// translators: %d: number of available snippets.
80 sprintf(__('Available snippets (%d)', 'code-snippets'), availableSnippets.length)}</h2>
81 <p>{__('Select the snippets you would like to import.', 'code-snippets')}</p>
82 </div>
83 <div className="table-actions">
84 <SelectAllButton selectAll={snippetSelection.selectAll} isAllSelected={snippetSelection.isAllSelected} />
85 <SubmitButton isImporting={isImporting} selectedCount={snippetSelection.selectedItems.size} />
86 </div>
87 </div>
88
89 <SnippetSelectionTable snippets={availableSnippets} selection={snippetSelection} />
90
91 <div className="tablenav bottom">
92 <SelectAllButton selectAll={snippetSelection.selectAll} isAllSelected={snippetSelection.isAllSelected} />
93 <SubmitButton isImporting={isImporting} selectedCount={snippetSelection.selectedItems.size} />
94 </div>
95 </>
96
97 interface SubmitFormProps {
98 children: ReactNode
99 duplicateAction: DuplicateAction
100 setImportResult: (result: ImportResult | undefined) => void
101 snippetSelection: UseSelection<ImportableSnippetSchema, ImportableSnippetSchema['table_data']['id']>
102 setIsImporting: (isImporting: boolean) => void
103 }
104
105 const SubmitForm: React.FC<SubmitFormProps> = ({ children, duplicateAction, setImportResult, setIsImporting, snippetSelection }) => {
106 const { api } = useRestAPI()
107
108 const buildRequest = (): SnippetImportRequest | undefined => {
109 const snippetsToImport = snippetSelection.getSelectedItems()
110
111 if (0 === snippetsToImport.length) {
112 alert(__('Please select snippets to import.', 'code-snippets'))
113 return undefined
114 }
115
116 return {
117 snippets: snippetsToImport,
118 duplicate_action: duplicateAction,
119 network: isNetworkAdmin()
120 }
121 }
122
123 const handleImportSelected: FormEventHandler<HTMLFormElement> = event => {
124 event.preventDefault()
125 const request = buildRequest()
126
127 if (request) {
128 setIsImporting(true)
129 setImportResult(undefined)
130
131 api
132 .post<SnippetImportResponse, SnippetImportRequest>(`${REST_BASES.importFiles}/import`, request)
133 .then(({ message, imported }) => {
134 setImportResult({ step: 'select', success: true, message, imported })
135 })
136 .catch((error: unknown) => {
137 console.error('Import error:', error)
138 setImportResult({ step: 'select', success: false, message: unpackErrorResponse(error) })
139 })
140 .finally(() => setIsImporting(false))
141 }
142 }
143
144 return <form onSubmit={handleImportSelected}>{children}</form>
145 }
146
147 export interface SelectSnippetsStepProps {
148 onCancel: VoidFunction
149 duplicateAction: DuplicateAction
150 setImportResult: (result: ImportResult | undefined) => void
151 availableSnippets: ImportableSnippetSchema[]
152 }
153
154 export const SelectSnippets: React.FC<SelectSnippetsStepProps> = ({
155 onCancel,
156 setImportResult,
157 duplicateAction,
158 availableSnippets
159 }) => {
160 const snippetSelection = useSelection(availableSnippets, snippet => snippet.table_data.id)
161 const [isImporting, setIsImporting] = useState(false)
162
163 const selectSectionRef = useRef<HTMLDivElement>(null)
164
165 useEffect(() => {
166 if (selectSectionRef.current) {
167 selectSectionRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' })
168 }
169 }, [selectSectionRef])
170
171 return (
172 <ImportCard ref={selectSectionRef} className="import-select-card snippets-table-card">
173 <SubmitForm {...{ duplicateAction, snippetSelection, setImportResult, setIsImporting }}>
174 <ReturnLink onCancel={onCancel} clearSelection={snippetSelection.clearSelection} />
175 <SelectSnippetsForm isImporting={isImporting} snippetSelection={snippetSelection} availableSnippets={availableSnippets} />
176 </SubmitForm>
177 </ImportCard>
178 )
179 }
180