diff --git a/mailpoet/assets/css/src/components-automation-analytics/tabs/automation_flow.scss b/mailpoet/assets/css/src/components-automation-analytics/tabs/automation_flow.scss
index 18aef429b6..1f974266dc 100644
--- a/mailpoet/assets/css/src/components-automation-analytics/tabs/automation_flow.scss
+++ b/mailpoet/assets/css/src/components-automation-analytics/tabs/automation_flow.scss
@@ -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;
diff --git a/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/components/tabs/automation_flow/step_footer.tsx b/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/components/tabs/automation_flow/step_footer.tsx
index 560333dddb..0aab9c1f36 100644
--- a/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/components/tabs/automation_flow/step_footer.tsx
+++ b/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/components/tabs/automation_flow/step_footer.tsx
@@ -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 (
+
+
+ {formattedPercent} ({formattedValue})
+
+ {
+ // translators: "failed" as in "100 automation runs failed at this step".
+ __('failed', 'mailpoet')
+ }
+
+
+
+ );
+}
+
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 (
-
-
-
+ <>
+
+
+
+
+ >
);
}
diff --git a/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/store/types.ts b/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/store/types.ts
index 4cf30a3068..797eb01be4 100644
--- a/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/store/types.ts
+++ b/mailpoet/assets/js/src/automation/integrations/mailpoet/analytics/store/types.ts
@@ -156,6 +156,7 @@ export type SubscriberSection = Section & {
export type StepFlowData = {
total: number;
waiting: Record | undefined;
+ failed: Record | undefined;
flow: Record | undefined;
};
export type AutomationFlowSectionData = SectionData & {
diff --git a/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Controller/StepStatisticController.php b/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Controller/StepStatisticController.php
index 56df9752d1..9d1a8c953e 100644
--- a/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Controller/StepStatisticController.php
+++ b/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Controller/StepStatisticController.php
@@ -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(),
diff --git a/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Endpoints/AutomationFlowEndpoint.php b/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Endpoints/AutomationFlowEndpoint.php
index ad630e9dc8..57d3dc3974 100644
--- a/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Endpoints/AutomationFlowEndpoint.php
+++ b/mailpoet/lib/Automation/Integrations/MailPoet/Analytics/Endpoints/AutomationFlowEndpoint.php
@@ -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;
}