Skip to content

Commit

Permalink
Finalize report loading via Ajax
Browse files Browse the repository at this point in the history
  • Loading branch information
oscarssanchez committed Feb 26, 2025
1 parent 63e055e commit a3e3ff6
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 88 deletions.
131 changes: 96 additions & 35 deletions assets/js/status-report/components/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
*/
import { Button, Flex, FlexItem } from '@wordpress/components';
import { useCopyToClipboard } from '@wordpress/compose';
import { WPElement, useState } from '@wordpress/element';
import { useState, WPElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies.
*/
import Report from './reports/report';
import { useSettingsScreen } from '../../settings-screen';
import { loadGroupAjax } from '../utilities';

/**
* Styles.
Expand All @@ -23,90 +22,152 @@ import '../style.css';
*
* @param {object} props Component props.
* @param {string} props.plainTextReport Plain text report.
* @param {object} props.reports Status reports.
* @param {object} props.reports Reports.
*
* @returns {WPElement} Reports component.
*/
export default ({ plainTextReport, reports }) => {
const { createNotice } = useSettingsScreen();
const [updatedReports, setUpdatedReports] = useState(reports);
const [updatedPlainTextReport, setUpdatedPlainTextReport] = useState(plainTextReport);
const [generatedReport, setGeneratedReport] = useState(false);

const ref = useCopyToClipboard(updatedPlainTextReport, () => {
createNotice({
status: 'success',
content: __('Report copied to clipboard.', 'elasticpress'),
});
});

const [reportText, setReportText] = useState(null);
const downloadUrl = `data:text/plain;charset=utf-8,${encodeURIComponent(plainTextReport)}`;
const downloadUrl = `data:text/plain;charset=utf-8,${encodeURIComponent(updatedPlainTextReport)}`;

/**
* Copy to clipboard button ref.
* Convert report data to plain text.
*
* @param {string} title Report title.
* @param {Array} groups Report groups.
*
* @type {object}
* @returns {string} Plain text report.
*/
const ref = useCopyToClipboard(reportText, () => {
createNotice(
'success',
__(
'The status report has been copied to the clipboard. You can now paste it into a text editor.',
'elasticpress',
),
);
});
const toPlainTextReport = (title, groups) => {
let output = `## ${title} ##\n\n`;
groups.forEach((group) => {
output += `### ${group.title} ###\n`;
Object.entries(group.fields).forEach(([slug, field]) => {
const value = field.value ?? '';
output += `${slug}: ${value}\n`;
});
output += `\n`;
});
return output;
};

/**
* Handle loading and building report plain text.
* Load a group report data via AJAX
*
* @param {string} id Group ID.
*
*
* @returns {Promise} Group data.
*/
const loadGroupAjax = async (id) => {
const { ajaxurl } = window;

const data = new FormData();
data.append('action', 'ep_load_groups');
data.append('report', id);
return fetch(ajaxurl, { method: 'POST', body: data });
};

/**
* Handle report loading.
*
* @returns {void}
*/
const handleReportLoading = async () => {
if (reportText) {
if (generatedReport) {
return;
}

const ajaxReportPromises = Object.entries(reports)
const newReports = { ...reports };

const ajaxTasks = Object.entries(newReports)
.filter(([key, reportData]) => reportData.is_ajax_report) // eslint-disable-line no-unused-vars
.map(async ([key]) => {
.map(async ([key, reportData]) => {
const response = await loadGroupAjax(key);
const jsonData = await response.json();
return jsonData;
const data = await response.json();
newReports[key] = {
...reportData,
groups: data,
};
});

const text = await Promise.all(ajaxReportPromises).then((ajaxReportTexts) => {
return JSON.stringify(ajaxReportTexts, null, 2);
});
await Promise.all(ajaxTasks);

setUpdatedReports(newReports);

setReportText(text);
const additionalText = Object.entries(newReports)
.filter(([key, reportData]) => reportData.is_ajax_report) // eslint-disable-line no-unused-vars
.map(
(
[key, reportData], // eslint-disable-line no-unused-vars
) => toPlainTextReport(reportData.title, reportData.groups || []),
)
.join('\n');

const combinedReport = `${plainTextReport}\n\n${additionalText}`;
setUpdatedPlainTextReport(combinedReport);

setGeneratedReport(true);
};

return (
<>
<p>
{__(
'This screen provides a list of information related to ElasticPress and synced content that can be helpful during troubleshooting. This list can also be copy/pasted and shared as needed.',
'This screen provides a list of information related to ElasticPress and synced content that can be helpful during troubleshooting. As the process can be resource-intensive, you must click the "Generate Full Status Report" button to generate a full report list. This list can also be copied and shared as needed.',
'elasticpress',
)}
</p>
<p>
<Flex justify="start">
<FlexItem>
<Button
download="elasticpress-report.txt"
disabled={generatedReport}
onClick={handleReportLoading}
href={reportText ? null : downloadUrl}
variant="primary"
>
{__('Generate Full Status Report', 'elasticpress')}
</Button>
</FlexItem>
<FlexItem>
<Button
disabled={!generatedReport}
download="elasticpress-report.txt"
href={downloadUrl}
variant="primary"
>
{__('Download status report', 'elasticpress')}
</Button>
</FlexItem>
<FlexItem>
<Button ref={ref} onClick={handleReportLoading} variant="secondary">
<Button disabled={!generatedReport} ref={ref} variant="secondary">
{__('Copy status report to clipboard', 'elasticpress')}
</Button>
</FlexItem>
</Flex>
</p>
{Object.entries(reports).map(

{Object.entries(updatedReports).map(
([key, { actions, groups, messages, title, is_ajax_report }]) => (
<Report
key={key}
id={key}
title={title}
actions={actions}
groups={groups}
id={key}
key={key}
is_ajax_report={is_ajax_report}
messages={messages}
title={title}
is_ajax_report={is_ajax_report}
/>
),
)}
Expand Down
44 changes: 9 additions & 35 deletions assets/js/status-report/components/reports/report.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
/**
* WordPress dependencies.
*/
import { Button } from '@wordpress/components';
import { WPElement, useState } from '@wordpress/element';
import { WPElement } from '@wordpress/element';

/**
* Internal dependencies.
*/
// import ReportHeader from './report/header';
import ReportContent from './report/content';
import ReportPendingContent from './report/pendingContent';
import ReportContainer from './report/container';
import { loadGroupAjax } from '../../utilities';

/**
* Report components.
Expand All @@ -30,40 +29,15 @@ export default ({ actions, groups, id, messages, title, is_ajax_report }) => {
return null;
}

const [group, setGroup] = useState(false);

const loadAjax = async () => {
const request = await loadGroupAjax(id);
request.json().then((response) => {
setGroup(response);
});
};

if (is_ajax_report) {
if (!group) {
return (
<ReportContainer id={id} title={title} messages={messages}>
<Button variant="primary" onClick={loadAjax}>
Load Report
</Button>
</ReportContainer>
);
}

return (
<ReportContainer id={id} title={title} actions={actions} messages={messages}>
{group.map(({ fields, title }) => (
<ReportContent key={title} fields={fields} title={title} />
))}
</ReportContainer>
);

}
return (
<ReportContainer id={id} title={title} actions={actions} messages={messages}>
{groups.map(({ fields, title }) => (
<ReportContent key={title} fields={fields} title={title} />
))}
{is_ajax_report && groups.length < 1 ? (
<ReportPendingContent />
) : (
groups.map(({ fields, title }) => (
<ReportContent key={title} fields={fields} title={title} />
))
)}
</ReportContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* WordPress dependencies.
*/
import { PanelBody } from '@wordpress/components';
import { WPElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import Value from './value';

/**
* Field value component.
*
* @param {object} props Component props.

Check warning on line 12 in assets/js/status-report/components/reports/report/pendingContent.js

View workflow job for this annotation

GitHub Actions / ES and Style Lint

@param "props" does not match an existing function parameter
* @param {string} props.title Title.
*
* @returns {WPElement} Value component.
*/
export default () => {
return (
<PanelBody title={__('Pending generation', 'elasticpress')}>
<table cellPadding="0" cellSpacing="0" className="wp-list-table widefat striped">
<tbody>
<tr>
<td>
<Value
value={__(
'To see this report, please generate a full report first by clicking the "Generate Full Status Report" button.',
'elasticpress',
)}
/>
</td>
</tr>
</tbody>
</table>
</PanelBody>
);
};
16 changes: 0 additions & 16 deletions assets/js/status-report/utilities.js

This file was deleted.

6 changes: 4 additions & 2 deletions includes/classes/Screen/StatusReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public function admin_enqueue_scripts() {
$title = $report['title'];
$groups = $report['groups'];

if ( $report['is_ajax_report'] ) {
continue;
}

$plain_text_reports[] = $this->render_copy_paste_report( $title, $groups );
}

Expand All @@ -85,8 +89,6 @@ public function admin_enqueue_scripts() {

/**
* AJAX action to load an individual report group.
*
* @return
*/
public function action_wp_ajax_ep_load_groups() {
$post = wp_unslash( $_POST );
Expand Down

0 comments on commit a3e3ff6

Please sign in to comment.