PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 4.0.0
GiveWP – Donation Plugin and Fundraising Platform v4.0.0
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / MigrationLog / Admin / Migrations / index.js
give / src / MigrationLog / Admin / Migrations Last commit date
api.js 4 years ago index.js 1 year ago styles.module.scss 4 years ago
index.js
379 lines
1 import {useState} from 'react';
2 import classNames from 'classnames';
3 import {Card, Label, Notice, Spinner, Pagination, Table, Button, Modal} from '@givewp/components';
4 import API, {useMigrationFetcher, getEndpoint} from './api';
5
6 import styles from './styles.module.scss';
7
8 import {__} from '@wordpress/i18n';
9
10 const Migrations = () => {
11 const [state, setState] = useState({
12 initialLoad: false,
13 currentPage: 1,
14 sortColumn: 'run_order',
15 sortDirection: 'asc',
16 pages: 0,
17 showOptions: false,
18 isSorting: false,
19 });
20
21 const [migrationModal, setMigrationModal] = useState({
22 visible: false,
23 });
24
25 const [migrationRunModal, setMigrationRunModal] = useState({
26 visible: false,
27 });
28
29 const parameters = {
30 page: state.currentPage,
31 sort: state.sortColumn,
32 direction: state.sortDirection,
33 };
34
35 const {data, isLoading, isError, mutate} = useMigrationFetcher(getEndpoint('/get-migrations', parameters), {
36 onSuccess: ({response}) => {
37 setState((previousState) => {
38 return {
39 ...previousState,
40 initialLoad: true,
41 pages: response.pages,
42 currentPage: state.currentPage > response.pages ? 1 : state.currentPage,
43 showOptions: response.showOptions,
44 isSorting: false,
45 };
46 });
47 },
48 });
49
50 const runMigration = () => {
51 setMigrationRunModal((previousState) => {
52 return {
53 ...previousState,
54 visible: true,
55 running: true,
56 };
57 });
58
59 let url = '/run-migration';
60
61 if (migrationRunModal.isBatchMigration) {
62 url = migrationRunModal.status === 'incomplete'
63 ? '/reschedule-failed-actions'
64 : '/run-batch-migration'
65 }
66
67 API.post(url, {id: migrationRunModal.id})
68 .then((response) => {
69 if (response.data.status) {
70 closeMigrationRunModal();
71 } else {
72 setMigrationRunModal((previousState) => {
73 return {
74 ...previousState,
75 type: 'error',
76 error: true,
77 errorMessage: response.data.message,
78 };
79 });
80 }
81 // Invalidate the cache
82 mutate(getEndpoint('/get-migrations', parameters));
83 })
84 .catch(() => {
85 setMigrationRunModal((previousState) => {
86 return {
87 ...previousState,
88 type: 'error',
89 error: true,
90 };
91 });
92 });
93 };
94
95 const openMigrationModal = (migration) => {
96 setMigrationModal({
97 visible: true,
98 id: migration.id,
99 status: migration.status,
100 error: migration.error,
101 last_run: migration.last_run,
102 });
103 };
104
105 const closeMigrationModal = () => {
106 setMigrationModal({visible: false});
107 };
108
109 const openMigrationRunModal = (migration) => {
110 setMigrationRunModal({
111 id: migration.id,
112 visible: true,
113 type: 'warning',
114 isBatchMigration: migration.isBatchMigration,
115 status: migration.status,
116 });
117 };
118
119 const closeMigrationRunModal = () => {
120 setMigrationRunModal({visible: false});
121 };
122
123 const setSortDirectionForColumn = (column, direction) => {
124 setState((previousState) => {
125 return {
126 ...previousState,
127 sortColumn: column,
128 sortDirection: direction,
129 isSorting: true,
130 };
131 });
132 };
133
134 const setCurrentPage = (currentPage) => {
135 setState((previousState) => {
136 return {
137 ...previousState,
138 currentPage,
139 };
140 });
141 };
142
143 const getMigrationModal = () => {
144 return (
145 <Modal visible={migrationModal.visible} type="error" handleClose={closeMigrationModal}>
146 <Modal.Title>
147 <strong>{__('Migration Failed', 'give')}</strong>
148
149 <Modal.CloseIcon onClick={closeMigrationModal} />
150 </Modal.Title>
151
152 <Modal.Section title={__('Migration ID', 'give')} content={migrationModal.id} />
153 <Modal.Section title={__('Last run', 'give')} content={migrationModal.last_run ?? __('n/a', 'give')} />
154
155 <Modal.AdditionalContext type={migrationModal.status} context={migrationModal.error} />
156 </Modal>
157 );
158 };
159
160 const getMigrationRunModal = () => {
161 return (
162 <Modal
163 visible={migrationRunModal.visible}
164 type={migrationRunModal.type}
165 handleClose={closeMigrationRunModal}
166 >
167 {migrationRunModal.running ? (
168 <Modal.Content align="center">
169 {migrationRunModal.error ? (
170 <>
171 <Modal.CloseIcon onClick={closeMigrationRunModal} />
172 <h2>{__('Database update failed!', 'give')}</h2>
173 {migrationRunModal.errorMessage && (
174 <Modal.Content align="center">{migrationRunModal.errorMessage}</Modal.Content>
175 )}
176 <Modal.Content align="center">
177 {__('Check migration details for more information', 'give')}
178 </Modal.Content>
179 </>
180 ) : (
181 <>
182 <Spinner />
183 <div style={{marginTop: 20}}>{__('Running Update', 'give')}</div>
184 </>
185 )}
186 </Modal.Content>
187 ) : (
188 <>
189 <Modal.Title>
190 <span className={classNames(styles.titleIcon, styles.warning)}>
191 <span className="dashicons dashicons-warning" />
192 </span>
193 {__('Create a Backup Before Running Database Update', 'give')}
194 </Modal.Title>
195
196 <Modal.Content>
197 <strong style={{marginRight: 5}}>{__('Notice', 'give')}:</strong>
198 {__(
199 'We strongly recommend you create a complete backup of your WordPress files and database prior to performing an update. We are not responsible for any misuse, deletions, white screens, fatal errors, or any other issue resulting from the use of this plugin.',
200 'give',
201 )}
202 </Modal.Content>
203
204 <Modal.Content>
205 <button style={{marginRight: 20}} className="button button-primary" onClick={runMigration}>
206 {__('Confirm', 'give')}
207 </button>
208 <button className="button" onClick={closeMigrationRunModal}>
209 {__('Cancel', 'give')}
210 </button>
211 </Modal.Content>
212 </>
213 )}
214 </Modal>
215 );
216 };
217
218 const columns = [
219 {
220 key: 'status',
221 label: __('Status', 'give'),
222 sort: true,
223 sortCallback: (direction) => setSortDirectionForColumn('status', direction),
224 styles: {
225 maxWidth: 150,
226 },
227 },
228 {
229 key: 'title',
230 label: __('Migration Title', 'give'),
231 sort: true,
232 sortCallback: (direction) => setSortDirectionForColumn('title', direction),
233 styles: {
234 overflowWrap: 'break-word',
235 wordWrap: 'break-word',
236 wordBreak: 'break-all',
237 },
238 },
239 {
240 key: 'last_run',
241 label: __('Last run', 'give'),
242 sort: true,
243 sortCallback: (direction) => setSortDirectionForColumn('last_run', direction),
244 styles: {
245 maxWidth: 200,
246 },
247 },
248 {
249 key: 'source',
250 label: __('Source', 'give'),
251 sort: true,
252 sortCallback: (direction) => setSortDirectionForColumn('source', direction),
253 styles: {
254 maxWidth: 200,
255 },
256 },
257 {
258 key: 'run_order',
259 label: __('Run Order', 'give'),
260 sort: true,
261 sortCallback: (direction) => setSortDirectionForColumn('run_order', direction),
262 styles: {
263 maxWidth: 150,
264 },
265 },
266 {
267 key: 'actions',
268 label: __('Actions', 'give'),
269 append: true,
270 styles: {
271 maxWidth: 100,
272 },
273 },
274 {
275 key: 'details',
276 label: __('Details', 'give'),
277 append: true,
278 styles: {
279 maxWidth: 100,
280 textAlign: 'center',
281 justifyContent: 'center',
282 },
283 },
284 ];
285
286 const columnFilters = {
287 status: (type) => <Label type={type}/>,
288 actions: (type, migration) => {
289 if (!state.showOptions) {
290 return null;
291 }
292
293 if (migration.status === 'failed' || migration.status === 'running') {
294 return null;
295 }
296
297 return (
298 <button className="button" onClick={() => openMigrationRunModal(migration)}>
299 {migration.status === 'incomplete' ? __('Continue Update', 'give') : __('Re-run Update', 'give')}
300 </button>
301 );
302 },
303 details: (value, migration) => {
304 if (!migration.error.length) {
305 return null;
306 }
307
308 return (
309 <Button
310 onClick={(e) => {
311 e.preventDefault();
312 openMigrationModal(migration);
313 }}
314 icon={true}
315 >
316 <span className="dashicons dashicons-visibility" />
317 </Button>
318 );
319 },
320 };
321
322 // Initial load
323 if (!state.initialLoad && isLoading) {
324 return (
325 <Notice>
326 <Spinner />
327 <h2>{__('Loading updates activity', 'give')}</h2>
328 </Notice>
329 );
330 }
331
332 // Is error?
333 if (isError) {
334 return (
335 <Notice>
336 <h2>{__('Something went wrong!', 'give')}</h2>
337 <div>
338 Try to{' '}
339 <a onClick={() => window.location.reload()} href="#">
340 reload
341 </a>{' '}
342 the browser
343 </div>
344 </Notice>
345 );
346 }
347
348 return (
349 <>
350 <Card>
351 <Table
352 columns={columns}
353 data={data}
354 columnFilters={columnFilters}
355 isLoading={isLoading}
356 isSorting={state.isSorting}
357 stripped={false}
358 />
359 </Card>
360
361 <div className={styles.footerRow}>
362 <div className={styles.pagination}>
363 <Pagination
364 currentPage={state.currentPage}
365 setPage={setCurrentPage}
366 totalPages={state.pages}
367 disabled={isLoading}
368 />
369 </div>
370 </div>
371
372 {migrationModal.visible && getMigrationModal()}
373 {migrationRunModal.visible && getMigrationRunModal()}
374 </>
375 );
376 };
377
378 export default Migrations;
379