| @@ -5,33 +5,61 @@ | ||
| 5 | 5 | |
| 6 | 6 | /** |
| 7 | 7 | * WordPress dependencies. |
| 8 | 8 | */ |
| 9 | -import { render, useCallback, useEffect, useRef, useState, WPElement } from '@wordpress/element'; | |
| 9 | +import { dateI18n } from '@wordpress/date'; | |
| 10 | +import { | |
| 11 | + createContext, | |
| 12 | + useCallback, | |
| 13 | + useContext, | |
| 14 | + useEffect, | |
| 15 | + useRef, | |
| 16 | + useState, | |
| 17 | + WPElement, | |
| 18 | +} from '@wordpress/element'; | |
| 10 | 19 | import { __, sprintf } from '@wordpress/i18n'; |
| 11 | 20 | |
| 12 | 21 | /** |
| 13 | 22 | * Internal dependencies. |
| 14 | 23 | */ |
| 15 | -import { autoIndex, lastSyncDateTime, lastSyncFailed, isEpio, indexMeta } from './config'; | |
| 16 | -import { useIndex } from './hooks'; | |
| 24 | +import { useIndex } from './src/hooks'; | |
| 17 | 25 | import { |
| 18 | 26 | clearSyncParam, |
| 19 | 27 | getItemsProcessedFromIndexMeta, |
| 20 | 28 | getItemsTotalFromIndexMeta, |
| 21 | -} from './utilities'; | |
| 22 | -import SyncPage from './components/sync-page'; | |
| 29 | +} from './src/utilities'; | |
| 23 | 30 | |
| 24 | 31 | /** |
| 32 | + * Sync context. | |
| 33 | + */ | |
| 34 | +const Context = createContext(); | |
| 35 | + | |
| 36 | +/** | |
| 25 | 37 | * App component. |
| 26 | 38 | * |
| 39 | + * @param {object} props Component props. | |
| 40 | + * @param {string} props.apiUrl API endpoint URL. | |
| 41 | + * @param {Function} props.children Component children | |
| 42 | + * @param {Array} props.defaultSyncHistory Sync history. | |
| 43 | + * @param {Array} props.defaultSyncTrigger Sync trigger. | |
| 44 | + * @param {object|null} props.indexMeta Details of a sync in progress. | |
| 45 | + * @param {boolean} props.isEpio Whether ElasticPress.io is in use. | |
| 46 | + * @param {string} props.nonce WordPress nonce. | |
| 27 | 47 | * @returns {WPElement} App component. |
| 28 | 48 | */ |
| 29 | -const App = () => { | |
| 49 | +export const SyncProvider = ({ | |
| 50 | + apiUrl, | |
| 51 | + children, | |
| 52 | + defaultSyncHistory, | |
| 53 | + defaultSyncTrigger, | |
| 54 | + indexMeta, | |
| 55 | + isEpio, | |
| 56 | + nonce, | |
| 57 | +}) => { | |
| 30 | 58 | /** |
| 31 | 59 | * Indexing methods. |
| 32 | 60 | */ |
| 33 | - const { cancelIndex, index, indexStatus } = useIndex(); | |
| 61 | + const { cancelIndex, index, indexStatus } = useIndex(apiUrl, nonce); | |
| 34 | 62 | |
| 35 | 63 | /** |
| 36 | 64 | * Message log state. |
| 37 | 65 | */ |
| @@ -37,19 +65,27 @@ | ||
| 37 | 65 | */ |
| 38 | 66 | const [log, setLog] = useState([]); |
| 39 | 67 | |
| 40 | 68 | /** |
| 69 | + * Error types state. | |
| 70 | + */ | |
| 71 | + const [errorCounts, setErrorCounts] = useState([]); | |
| 72 | + | |
| 73 | + /** | |
| 41 | 74 | * Sync state. |
| 42 | 75 | */ |
| 43 | 76 | const [state, setState] = useState({ |
| 77 | + isCli: false, | |
| 44 | 78 | isComplete: false, |
| 45 | 79 | isDeleting: false, |
| 80 | + isFailed: false, | |
| 81 | + isPaused: false, | |
| 46 | 82 | isSyncing: false, |
| 47 | 83 | itemsProcessed: 0, |
| 48 | 84 | itemsTotal: 100, |
| 49 | - lastSyncDateTime, | |
| 50 | - lastSyncFailed, | |
| 51 | 85 | syncStartDateTime: null, |
| 86 | + syncHistory: defaultSyncHistory, | |
| 87 | + syncTrigger: defaultSyncTrigger, | |
| 52 | 88 | }); |
| 53 | 89 | |
| 54 | 90 | /** |
| 55 | 91 | * Current state reference. |
| @@ -66,8 +102,41 @@ | ||
| 66 | 102 | stateRef.current = { ...stateRef.current, ...newState }; |
| 67 | 103 | setState((state) => ({ ...state, ...newState })); |
| 68 | 104 | }; |
| 69 | 105 | |
| 106 | + const countErrors = useCallback( | |
| 107 | + /** | |
| 108 | + * Add up the counts for each error type. | |
| 109 | + * | |
| 110 | + * @param {object} errors Errors returned by the sync request. | |
| 111 | + */ | |
| 112 | + (errors) => { | |
| 113 | + setErrorCounts((errorCounts) => { | |
| 114 | + const newErrorCounts = [...errorCounts]; | |
| 115 | + | |
| 116 | + Object.keys(errors).forEach((e) => { | |
| 117 | + if (!errors[e].solution) { | |
| 118 | + return; | |
| 119 | + } | |
| 120 | + | |
| 121 | + const i = newErrorCounts.findIndex((t) => e === t.type); | |
| 122 | + | |
| 123 | + if (i !== -1) { | |
| 124 | + newErrorCounts[i].count += errors[e].count; | |
| 125 | + } else { | |
| 126 | + newErrorCounts.push({ | |
| 127 | + ...errors[e], | |
| 128 | + type: e, | |
| 129 | + }); | |
| 130 | + } | |
| 131 | + }); | |
| 132 | + | |
| 133 | + return newErrorCounts; | |
| 134 | + }); | |
| 135 | + }, | |
| 136 | + [], | |
| 137 | + ); | |
| 138 | + | |
| 70 | 139 | const logMessage = useCallback( |
| 71 | 140 | /** |
| 72 | 141 | * Log a message. |
| 73 | 142 | * |
| @@ -80,14 +149,36 @@ | ||
| 80 | 149 | |
| 81 | 150 | const messages = Array.isArray(message) ? message : [message]; |
| 82 | 151 | |
| 83 | 152 | for (const message of messages) { |
| 84 | - setLog((log) => [...log, { message, status, isDeleting, id: uuid() }]); | |
| 153 | + setLog((log) => [ | |
| 154 | + ...log, | |
| 155 | + { | |
| 156 | + message, | |
| 157 | + status, | |
| 158 | + dateTime: dateI18n('Y-m-d H:i:s', new Date()), | |
| 159 | + isDeleting, | |
| 160 | + id: uuid(), | |
| 161 | + }, | |
| 162 | + ]); | |
| 85 | 163 | } |
| 86 | 164 | }, |
| 87 | 165 | [], |
| 88 | 166 | ); |
| 89 | 167 | |
| 168 | + const clearLog = useCallback( | |
| 169 | + /** | |
| 170 | + * Clear the log. | |
| 171 | + * | |
| 172 | + * @returns {void} | |
| 173 | + */ | |
| 174 | + () => { | |
| 175 | + setLog([]); | |
| 176 | + setErrorCounts([]); | |
| 177 | + }, | |
| 178 | + [setLog], | |
| 179 | + ); | |
| 180 | + | |
| 90 | 181 | const syncCompleted = useCallback( |
| 91 | 182 | /** |
| 92 | 183 | * Set sync state to completed, with success based on the number of |
| 93 | 184 | * failures in the index totals. |
| @@ -99,11 +190,15 @@ | ||
| 99 | 190 | updateState({ |
| 100 | 191 | isComplete: true, |
| 101 | 192 | isPaused: false, |
| 102 | 193 | isSyncing: false, |
| 103 | - lastSyncDateTime: indexTotals.end_date_time, | |
| 104 | - lastSyncFailed: indexTotals.failed > 0, | |
| 194 | + syncHistory: [indexTotals, ...stateRef.current.syncHistory], | |
| 105 | 195 | }); |
| 196 | + | |
| 197 | + /** | |
| 198 | + * Hide the "just need to sync" notice, if it's present. | |
| 199 | + */ | |
| 200 | + document.querySelector('[data-ep-notice="no_sync"]')?.remove(); | |
| 106 | 201 | }, |
| 107 | 202 | [], |
| 108 | 203 | ); |
| 109 | 204 | |
| @@ -110,29 +205,44 @@ | ||
| 110 | 205 | const syncFailed = useCallback( |
| 111 | 206 | /** |
| 112 | 207 | * Handle an error in the sync request. |
| 113 | 208 | * |
| 114 | - * @param {Error} error Request error. | |
| 209 | + * @param {object|Error} response Request response. | |
| 115 | 210 | * @returns {void} |
| 116 | 211 | */ |
| 117 | - (error) => { | |
| 212 | + (response) => { | |
| 118 | 213 | /** |
| 119 | 214 | * Any running requests are cancelled when a new request is made. |
| 120 | 215 | * We can handle this silently. |
| 121 | 216 | */ |
| 122 | - if (error.name === 'AbortError') { | |
| 217 | + if (response.name === 'AbortError') { | |
| 123 | 218 | return; |
| 124 | 219 | } |
| 125 | 220 | |
| 126 | 221 | /** |
| 127 | - * Log any messages. | |
| 222 | + * Log any error messages. | |
| 128 | 223 | */ |
| 129 | - if (error.message) { | |
| 130 | - logMessage(error.message, 'error'); | |
| 224 | + if (response.message) { | |
| 225 | + logMessage(response.message, 'error'); | |
| 131 | 226 | } |
| 132 | 227 | |
| 228 | + /** | |
| 229 | + * If the error has totals, add to the sync history. | |
| 230 | + */ | |
| 231 | + const syncHistory = response.totals | |
| 232 | + ? [response.totals, ...stateRef.current.syncHistory] | |
| 233 | + : stateRef.current.syncHistory; | |
| 234 | + | |
| 235 | + /** | |
| 236 | + * Log a final message and update the sync state. | |
| 237 | + */ | |
| 133 | 238 | logMessage(__('Sync failed', 'elasticpress'), 'error'); |
| 134 | - updateState({ isSyncing: false }); | |
| 239 | + | |
| 240 | + updateState({ | |
| 241 | + isFailed: true, | |
| 242 | + isSyncing: false, | |
| 243 | + syncHistory, | |
| 244 | + }); | |
| 135 | 245 | }, |
| 136 | 246 | [logMessage], |
| 137 | 247 | ); |
| 138 | 248 | |
| @@ -157,15 +267,15 @@ | ||
| 157 | 267 | ), |
| 158 | 268 | isEpio |
| 159 | 269 | ? __('ElasticPress.io', 'elasticpress') |
| 160 | 270 | : __('Elasticsearch', 'elasticpress'), |
| 161 | - ) | |
| 271 | + ) | |
| 162 | 272 | : __('Sync interrupted by WP-CLI command.', 'elasticpress'); |
| 163 | 273 | |
| 164 | 274 | logMessage(message, 'info'); |
| 165 | 275 | updateState({ isSyncing: false }); |
| 166 | 276 | }, |
| 167 | - [logMessage], | |
| 277 | + [isEpio, logMessage], | |
| 168 | 278 | ); |
| 169 | 279 | |
| 170 | 280 | const syncInProgress = useCallback( |
| 171 | 281 | /** |
| @@ -176,19 +286,35 @@ | ||
| 176 | 286 | */ |
| 177 | 287 | (indexMeta) => { |
| 178 | 288 | updateState({ |
| 179 | 289 | isCli: indexMeta.method === 'cli', |
| 180 | - isComplete: false, | |
| 181 | - isDeleting: indexMeta.put_mapping, | |
| 182 | 290 | isSyncing: true, |
| 183 | 291 | itemsProcessed: getItemsProcessedFromIndexMeta(indexMeta), |
| 184 | 292 | itemsTotal: getItemsTotalFromIndexMeta(indexMeta), |
| 185 | 293 | syncStartDateTime: indexMeta.start_date_time, |
| 294 | + syncTrigger: indexMeta.trigger || null, | |
| 186 | 295 | }); |
| 187 | 296 | }, |
| 188 | 297 | [], |
| 189 | 298 | ); |
| 190 | 299 | |
| 300 | + const syncStopped = useCallback( | |
| 301 | + /** | |
| 302 | + * Set state for a stopped sync. | |
| 303 | + * | |
| 304 | + * @param {object} response Cancel request response. | |
| 305 | + * @returns {void} | |
| 306 | + */ | |
| 307 | + (response) => { | |
| 308 | + const syncHistory = response.data | |
| 309 | + ? [response.data, ...stateRef.current.syncHistory] | |
| 310 | + : stateRef.current.syncHistory; | |
| 311 | + | |
| 312 | + updateState({ syncHistory }); | |
| 313 | + }, | |
| 314 | + [], | |
| 315 | + ); | |
| 316 | + | |
| 191 | 317 | const updateSyncState = useCallback( |
| 192 | 318 | /** |
| 193 | 319 | * Handle the response to a request to index. |
| 194 | 320 | * |
| @@ -195,14 +321,14 @@ | ||
| 195 | 321 | * Updates the application state from the response data and logs any |
| 196 | 322 | * messages. Returns a Promise that resolves if syncing should |
| 197 | 323 | * continue. |
| 198 | 324 | * |
| 199 | - * @param {object} response AJAX response. | |
| 325 | + * @param {object} response API response. | |
| 200 | 326 | * @returns {Promise} Promise that resolves if sync is to continue. |
| 201 | 327 | */ |
| 202 | 328 | (response) => { |
| 203 | 329 | const { isPaused, isSyncing } = stateRef.current; |
| 204 | - const { message, status, totals = [], index_meta: indexMeta } = response.data; | |
| 330 | + const { errors, message, status, totals = [], index_meta: indexMeta } = response.data; | |
| 205 | 331 | |
| 206 | 332 | return new Promise((resolve) => { |
| 207 | 333 | /** |
| 208 | 334 | * Don't continue if syncing has been stopped. |
| @@ -210,9 +336,21 @@ | ||
| 210 | 336 | if (!isSyncing) { |
| 211 | 337 | return; |
| 212 | 338 | } |
| 213 | 339 | |
| 340 | + if (errors) { | |
| 341 | + countErrors(errors); | |
| 342 | + } | |
| 343 | + | |
| 214 | 344 | /** |
| 345 | + * Stop sync if there is an error. | |
| 346 | + */ | |
| 347 | + if (status === 'error') { | |
| 348 | + syncFailed(response.data); | |
| 349 | + return; | |
| 350 | + } | |
| 351 | + | |
| 352 | + /** | |
| 215 | 353 | * Log any messages. |
| 216 | 354 | */ |
| 217 | 355 | if (message) { |
| 218 | 356 | logMessage(message, status); |
| @@ -252,11 +390,29 @@ | ||
| 252 | 390 | */ |
| 253 | 391 | resolve(indexMeta.method); |
| 254 | 392 | }); |
| 255 | 393 | }, |
| 256 | - [syncCompleted, syncInProgress, syncInterrupted, logMessage], | |
| 394 | + [syncCompleted, syncFailed, syncInProgress, syncInterrupted, countErrors, logMessage], | |
| 257 | 395 | ); |
| 258 | 396 | |
| 397 | + const doCancelIndex = useCallback( | |
| 398 | + /** | |
| 399 | + * Cancel a sync. | |
| 400 | + * | |
| 401 | + * @returns {void} | |
| 402 | + */ | |
| 403 | + () => { | |
| 404 | + cancelIndex() | |
| 405 | + .then(syncStopped) | |
| 406 | + .catch((error) => { | |
| 407 | + if (error?.name !== 'AbortError') { | |
| 408 | + throw error; | |
| 409 | + } | |
| 410 | + }); | |
| 411 | + }, | |
| 412 | + [cancelIndex, syncStopped], | |
| 413 | + ); | |
| 414 | + | |
| 259 | 415 | const doIndexStatus = useCallback( |
| 260 | 416 | /** |
| 261 | 417 | * Check the status of a sync. |
| 262 | 418 | * |
| @@ -272,15 +428,15 @@ | ||
| 272 | 428 | ); |
| 273 | 429 | |
| 274 | 430 | const doIndex = useCallback( |
| 275 | 431 | /** |
| 276 | - * Start or continues a sync. | |
| 432 | + * Start or continue a sync. | |
| 277 | 433 | * |
| 278 | - * @param {boolean} isDeleting Whether to delete and sync. | |
| 434 | + * @param {object} args Sync args. | |
| 279 | 435 | * @returns {void} |
| 280 | 436 | */ |
| 281 | - (isDeleting) => { | |
| 282 | - index(isDeleting) | |
| 437 | + (args) => { | |
| 438 | + index(args) | |
| 283 | 439 | .then(updateSyncState) |
| 284 | 440 | .then( |
| 285 | 441 | /** |
| 286 | 442 | * If an existing sync has been found just check its status, |
| @@ -291,9 +447,9 @@ | ||
| 291 | 447 | (method) => { |
| 292 | 448 | if (method === 'cli') { |
| 293 | 449 | doIndexStatus(); |
| 294 | 450 | } else { |
| 295 | - doIndex(isDeleting); | |
| 451 | + doIndex(args); | |
| 296 | 452 | } |
| 297 | 453 | }, |
| 298 | 454 | ) |
| 299 | 455 | .catch(syncFailed); |
| @@ -307,105 +463,76 @@ | ||
| 307 | 463 | * |
| 308 | 464 | * @returns {void} |
| 309 | 465 | */ |
| 310 | 466 | () => { |
| 311 | - updateState({ isComplete: false, isPaused: true, isSyncing: true }); | |
| 467 | + updateState({ isPaused: true, isSyncing: true }); | |
| 312 | 468 | }, |
| 313 | 469 | [], |
| 314 | 470 | ); |
| 315 | 471 | |
| 316 | - const stopSync = useCallback( | |
| 472 | + const resumeSync = useCallback( | |
| 317 | 473 | /** |
| 318 | - * Stop syncing. | |
| 474 | + * Resume syncing. | |
| 319 | 475 | * |
| 476 | + * @param {object} args Sync args. | |
| 320 | 477 | * @returns {void} |
| 321 | 478 | */ |
| 322 | - () => { | |
| 323 | - updateState({ isComplete: false, isPaused: false, isSyncing: false }); | |
| 324 | - cancelIndex(); | |
| 479 | + (args) => { | |
| 480 | + updateState({ isPaused: false, isSyncing: true }); | |
| 481 | + doIndex(args); | |
| 325 | 482 | }, |
| 326 | - [cancelIndex], | |
| 483 | + [doIndex], | |
| 327 | 484 | ); |
| 328 | 485 | |
| 329 | - const resumeSync = useCallback( | |
| 486 | + const startSync = useCallback( | |
| 330 | 487 | /** |
| 331 | - * Resume syncing. | |
| 488 | + * Start syncing. | |
| 332 | 489 | * |
| 490 | + * @param {object} args Sync args. | |
| 333 | 491 | * @returns {void} |
| 334 | 492 | */ |
| 335 | - () => { | |
| 336 | - updateState({ isComplete: false, isPaused: false, isSyncing: true }); | |
| 337 | - doIndex(stateRef.current.isDeleting); | |
| 493 | + (args) => { | |
| 494 | + const { syncHistory } = stateRef.current; | |
| 495 | + const isInitialSync = !syncHistory.length; | |
| 496 | + | |
| 497 | + /** | |
| 498 | + * We should not appear to be deleting if this is the first sync. | |
| 499 | + */ | |
| 500 | + const isDeleting = !!(isInitialSync || args.put_mapping); | |
| 501 | + | |
| 502 | + updateState({ | |
| 503 | + isComplete: false, | |
| 504 | + isFailed: false, | |
| 505 | + isDeleting, | |
| 506 | + isPaused: false, | |
| 507 | + isSyncing: true, | |
| 508 | + }); | |
| 509 | + | |
| 510 | + updateState({ | |
| 511 | + itemsProcessed: 0, | |
| 512 | + syncStartDateTime: Date.now(), | |
| 513 | + syncTrigger: args.trigger || null, | |
| 514 | + }); | |
| 515 | + | |
| 516 | + doIndex(args); | |
| 338 | 517 | }, |
| 339 | 518 | [doIndex], |
| 340 | 519 | ); |
| 341 | 520 | |
| 342 | - const startSync = useCallback( | |
| 521 | + const stopSync = useCallback( | |
| 343 | 522 | /** |
| 344 | 523 | * Stop syncing. |
| 345 | 524 | * |
| 346 | - * @param {boolean} isDeleting Whether to delete and sync. | |
| 347 | 525 | * @returns {void} |
| 348 | 526 | */ |
| 349 | - (isDeleting) => { | |
| 350 | - updateState({ isComplete: false, isDeleting, isPaused: false, isSyncing: true }); | |
| 351 | - updateState({ itemsProcessed: 0, syncStartDateTime: Date.now() }); | |
| 352 | - doIndex(isDeleting); | |
| 527 | + () => { | |
| 528 | + updateState({ isPaused: false, isSyncing: false }); | |
| 529 | + doCancelIndex(); | |
| 353 | 530 | }, |
| 354 | - [doIndex], | |
| 531 | + [doCancelIndex], | |
| 355 | 532 | ); |
| 356 | 533 | |
| 357 | 534 | /** |
| 358 | - * Handle clicking delete and sync button. | |
| 359 | - * | |
| 360 | - * @returns {void} | |
| 361 | - */ | |
| 362 | - const onDelete = async () => { | |
| 363 | - startSync(true); | |
| 364 | - logMessage(__('Starting delete and sync…', 'elasticpress'), 'info'); | |
| 365 | - }; | |
| 366 | - | |
| 367 | - /** | |
| 368 | - * Handle clicking pause button. | |
| 369 | - * | |
| 370 | - * @returns {void} | |
| 371 | - */ | |
| 372 | - const onPause = () => { | |
| 373 | - pauseSync(); | |
| 374 | - logMessage(__('Pausing sync…', 'elasticpress'), 'info'); | |
| 375 | - }; | |
| 376 | - | |
| 377 | - /** | |
| 378 | - * Handle clicking play button. | |
| 379 | - * | |
| 380 | - * @returns {void} | |
| 381 | - */ | |
| 382 | - const onResume = () => { | |
| 383 | - resumeSync(); | |
| 384 | - logMessage(__('Resuming sync…', 'elasticpress'), 'info'); | |
| 385 | - }; | |
| 386 | - | |
| 387 | - /** | |
| 388 | - * Handle clicking stop button. | |
| 389 | - * | |
| 390 | - * @returns {void} | |
| 391 | - */ | |
| 392 | - const onStop = () => { | |
| 393 | - stopSync(); | |
| 394 | - logMessage(__('Sync stopped', 'elasticpress'), 'info'); | |
| 395 | - }; | |
| 396 | - | |
| 397 | - /** | |
| 398 | - * Handle clicking sync button. | |
| 399 | - * | |
| 400 | - * @returns {void} | |
| 401 | - */ | |
| 402 | - const onSync = async () => { | |
| 403 | - startSync(false); | |
| 404 | - logMessage(__('Starting sync…', 'elasticpress'), 'info'); | |
| 405 | - }; | |
| 406 | - | |
| 407 | - /** | |
| 408 | 535 | * Initialize. |
| 409 | 536 | * |
| 410 | 537 | * @returns {void} |
| 411 | 538 | */ |
| @@ -431,39 +558,63 @@ | ||
| 431 | 558 | } else { |
| 432 | 559 | pauseSync(); |
| 433 | 560 | logMessage(__('Sync paused', 'elasticpress'), 'info'); |
| 434 | 561 | } |
| 435 | - | |
| 436 | - return; | |
| 437 | 562 | } |
| 438 | - | |
| 439 | - /** | |
| 440 | - * Start an initial index. | |
| 441 | - */ | |
| 442 | - if (autoIndex) { | |
| 443 | - startSync(true); | |
| 444 | - logMessage(__('Starting delete and sync…', 'elasticpress'), 'info'); | |
| 445 | - } | |
| 446 | 563 | }; |
| 447 | 564 | |
| 448 | 565 | /** |
| 449 | 566 | * Effects. |
| 450 | 567 | */ |
| 451 | - useEffect(init, [doIndexStatus, syncInProgress, logMessage, pauseSync, startSync]); | |
| 568 | + useEffect(init, [doIndexStatus, syncInProgress, indexMeta, logMessage, pauseSync, startSync]); | |
| 452 | 569 | |
| 453 | 570 | /** |
| 454 | - * Render. | |
| 571 | + * Provide state to context. | |
| 455 | 572 | */ |
| 456 | - return ( | |
| 457 | - <SyncPage | |
| 458 | - log={log} | |
| 459 | - onDelete={onDelete} | |
| 460 | - onPause={onPause} | |
| 461 | - onResume={onResume} | |
| 462 | - onStop={onStop} | |
| 463 | - onSync={onSync} | |
| 464 | - {...state} | |
| 465 | - /> | |
| 466 | - ); | |
| 573 | + const { | |
| 574 | + isCli, | |
| 575 | + isComplete, | |
| 576 | + isDeleting, | |
| 577 | + isFailed, | |
| 578 | + isPaused, | |
| 579 | + isSyncing, | |
| 580 | + itemsProcessed, | |
| 581 | + itemsTotal, | |
| 582 | + syncHistory, | |
| 583 | + syncStartDateTime, | |
| 584 | + syncTrigger, | |
| 585 | + } = stateRef.current; | |
| 586 | + | |
| 587 | + // eslint-disable-next-line react/jsx-no-constructed-context-values | |
| 588 | + const contextValue = { | |
| 589 | + clearLog, | |
| 590 | + errorCounts, | |
| 591 | + isCli, | |
| 592 | + isComplete, | |
| 593 | + isDeleting, | |
| 594 | + isFailed, | |
| 595 | + isPaused, | |
| 596 | + isSyncing, | |
| 597 | + itemsProcessed, | |
| 598 | + itemsTotal, | |
| 599 | + syncHistory, | |
| 600 | + log, | |
| 601 | + logMessage, | |
| 602 | + pauseSync, | |
| 603 | + resumeSync, | |
| 604 | + startSync, | |
| 605 | + stopSync, | |
| 606 | + syncStartDateTime, | |
| 607 | + syncTrigger, | |
| 608 | + }; | |
| 609 | + | |
| 610 | + return <Context.Provider value={contextValue}>{children}</Context.Provider>; | |
| 467 | 611 | }; |
| 468 | 612 | |
| 469 | -render(<App />, document.getElementById('ep-sync')); | |
| 613 | +/** | |
| 614 | + * Use the API Search context. | |
| 615 | + * | |
| 616 | + * @returns {object} API Search Context. | |
| 617 | + */ | |
| 618 | +export const useSync = () => { | |
| 619 | + return useContext(Context); | |
| 620 | +}; | |