Show failed runs per step
[MAILPOET-5460]
This commit is contained in:
@ -38,6 +38,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet-automation-analytics-step-failed {
|
||||
bottom: 0;
|
||||
display: none;
|
||||
grid-column: 1 / -1;
|
||||
justify-content: center;
|
||||
left: -100px;
|
||||
position: absolute;
|
||||
|
||||
&:after {
|
||||
border-top: 1px dashed $color-gutenberg-grey-600;
|
||||
content: '';
|
||||
height: 0;
|
||||
left: 100%;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
p {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
.mailpoet-automation-analytics-step-failed {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet-automation-analytics-step-footer {
|
||||
background: $color-wp-gray-0;
|
||||
border-top: 1px solid $color-poet-gray-dividers;
|
||||
@ -47,10 +80,17 @@
|
||||
margin-bottom: -12px;
|
||||
margin-left: -12px;
|
||||
width: calc(100% + 24px);
|
||||
z-index: 1;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 6px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mailpoet-automation-analytics-step-footer,
|
||||
.mailpoet-automation-analytics-step-failed {
|
||||
p {
|
||||
margin: 0;
|
||||
|
||||
a {
|
||||
color: $color-gutenberg-grey-800;
|
||||
|
@ -7,6 +7,52 @@ import { locale } from '../../../config';
|
||||
import { Step } from '../../../../../../editor/components/automation/types';
|
||||
import { openTab } from '../../../navigation/open_tab';
|
||||
|
||||
const compactFormatter = Intl.NumberFormat(locale.toString(), {
|
||||
notation: 'compact',
|
||||
});
|
||||
const percentFormatter = Intl.NumberFormat(locale.toString(), {
|
||||
style: 'percent',
|
||||
});
|
||||
|
||||
function FailedStep({ step }: { step: Step }): JSX.Element | null {
|
||||
const { section } = useSelect(
|
||||
(s) =>
|
||||
({
|
||||
section: s(storeName).getSection('automation_flow'),
|
||||
} as {
|
||||
section: AutomationFlowSection;
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const { data } = section;
|
||||
|
||||
const failed = data.step_data?.failed;
|
||||
const value = failed !== undefined ? failed[step.id] ?? 0 : 0;
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const percent =
|
||||
data.step_data.total > 0
|
||||
? Math.round((value / data.step_data.total) * 100)
|
||||
: 0;
|
||||
const formattedValue = compactFormatter.format(value);
|
||||
const formattedPercent = percentFormatter.format(percent / 100);
|
||||
return (
|
||||
<div className="mailpoet-automation-analytics-step-failed">
|
||||
<p>
|
||||
{formattedPercent} ({formattedValue})
|
||||
<span>
|
||||
{
|
||||
// translators: "failed" as in "100 automation runs failed at this step".
|
||||
__('failed', 'mailpoet')
|
||||
}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function StepFooter({ step }: { step: Step }): JSX.Element | null {
|
||||
const { section } = useSelect(
|
||||
(s) =>
|
||||
@ -29,37 +75,36 @@ export function StepFooter({ step }: { step: Step }): JSX.Element | null {
|
||||
? Math.round((value / data.step_data.total) * 100)
|
||||
: 0;
|
||||
|
||||
const formattedValue = Intl.NumberFormat(locale.toString(), {
|
||||
notation: 'compact',
|
||||
}).format(value);
|
||||
const formattedPercent = Intl.NumberFormat(locale.toString(), {
|
||||
style: 'percent',
|
||||
}).format(percent / 100);
|
||||
const formattedValue = compactFormatter.format(value);
|
||||
const formattedPercent = percentFormatter.format(percent / 100);
|
||||
return (
|
||||
<Tooltip text={__('View subscribers', 'mailpoet')}>
|
||||
<div className="mailpoet-automation-analytics-step-footer">
|
||||
<p>
|
||||
<a
|
||||
href={addQueryArgs(window.location.href, {
|
||||
tab: 'automation-subscribers',
|
||||
})}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
openTab('subscribers', {
|
||||
filters: { status: [], step: [step.id] },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{formattedPercent} ({formattedValue}){' '}
|
||||
<span>
|
||||
{
|
||||
// translators: "waiting" as in "100 people are waiting for this step".
|
||||
__('waiting', 'mailpoet')
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<>
|
||||
<FailedStep step={step} />
|
||||
<Tooltip text={__('View subscribers', 'mailpoet')}>
|
||||
<div className="mailpoet-automation-analytics-step-footer">
|
||||
<p>
|
||||
<a
|
||||
href={addQueryArgs(window.location.href, {
|
||||
tab: 'automation-subscribers',
|
||||
})}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
openTab('subscribers', {
|
||||
filters: { status: [], step: [step.id] },
|
||||
});
|
||||
}}
|
||||
>
|
||||
{formattedPercent} ({formattedValue}){' '}
|
||||
<span>
|
||||
{
|
||||
// translators: "waiting" as in "100 people are waiting for this step".
|
||||
__('waiting', 'mailpoet')
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ export type SubscriberSection = Section & {
|
||||
export type StepFlowData = {
|
||||
total: number;
|
||||
waiting: Record<string, number> | undefined;
|
||||
failed: Record<string, number> | undefined;
|
||||
flow: Record<string, number> | undefined;
|
||||
};
|
||||
export type AutomationFlowSectionData = SectionData & {
|
||||
|
@ -45,6 +45,25 @@ class StepStatisticController {
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getFailedStatistics(Automation $automation, Query $query): array {
|
||||
$rawData = $this->automationRunStorage->getAutomationStepStatisticForTimeFrame(
|
||||
$automation->getId(),
|
||||
AutomationRun::STATUS_FAILED,
|
||||
$query->getAfter(),
|
||||
$query->getBefore()
|
||||
);
|
||||
|
||||
$data = [];
|
||||
foreach ($automation->getSteps() as $step) {
|
||||
foreach ($rawData as $rawDatum) {
|
||||
if ($rawDatum['next_step_id'] === $step->getId()) {
|
||||
$data[$step->getId()] = (int)$rawDatum['count'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getFlowStatistics(Automation $automation, Query $query): array {
|
||||
$statistics = $this->automationRunLogStorage->getAutomationRunStatisticsForAutomationInTimeFrame(
|
||||
$automation->getId(),
|
||||
|
@ -65,6 +65,7 @@ class AutomationFlowEndpoint extends Endpoint {
|
||||
);
|
||||
|
||||
$waitingData = $this->stepStatisticController->getWaitingStatistics($automation, $query);
|
||||
$failedData = $this->stepStatisticController->getFailedStatistics($automation, $query);
|
||||
try {
|
||||
$flowData = $this->stepStatisticController->getFlowStatistics($automation, $query);
|
||||
} catch (\Throwable $e) {
|
||||
@ -76,6 +77,9 @@ class AutomationFlowEndpoint extends Endpoint {
|
||||
if ($waitingData) {
|
||||
$stepData['waiting'] = $waitingData;
|
||||
}
|
||||
if ($failedData) {
|
||||
$stepData['failed'] = $failedData;
|
||||
}
|
||||
if ($flowData) {
|
||||
$stepData['flow'] = $flowData;
|
||||
}
|
||||
|
Reference in New Issue
Block a user