fix(test-dispatch): fall back to tracker defaults, surface soft errors
- dispatch_test_notification now resolves tracking_config / template_config
from the tracker's default_* fields when the per-link override is unset,
matching what load_link_data does for the real watcher. Previously
periodic/scheduled/memory tests silently failed with "no template
defined" whenever the user configured the template config at the
tracker level instead of on each link (the UI's normal default).
- Distinguish the two missing-template cases in the returned error
("no template config linked" vs. "slot missing in linked config").
- Frontend testTrackerTarget now treats {success:false,error:"..."} in a
2xx body as a failure — previously any 2xx flashed a success snack so
users never saw the real reason their test didn't deliver.
This commit is contained in:
@@ -358,8 +358,19 @@
|
|||||||
if (ttTesting[key]) return;
|
if (ttTesting[key]) return;
|
||||||
ttTesting = { ...ttTesting, [key]: testType };
|
ttTesting = { ...ttTesting, [key]: testType };
|
||||||
try {
|
try {
|
||||||
await api(`/notification-trackers/${trackerId}/targets/${ttId}/test/${testType}?locale=${getLocale()}`, { method: 'POST' });
|
// The endpoint returns 200 OK with ``{success: false, error: "..."}``
|
||||||
snackSuccess(t('snack.targetTestSent'));
|
// on soft failures (missing template slot, no matching assets,
|
||||||
|
// provider unreachable, etc.), so checking for a thrown exception
|
||||||
|
// is not enough. Surface ``error`` as a snackError when present.
|
||||||
|
const res = await api<{ success?: boolean; error?: string; target?: string }>(
|
||||||
|
`/notification-trackers/${trackerId}/targets/${ttId}/test/${testType}?locale=${getLocale()}`,
|
||||||
|
{ method: 'POST' },
|
||||||
|
);
|
||||||
|
if (res && res.success === false) {
|
||||||
|
snackError(res.error || t('common.error'));
|
||||||
|
} else {
|
||||||
|
snackSuccess(t('snack.targetTestSent'));
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
snackError(err.message);
|
snackError(err.message);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -55,17 +55,21 @@ async def dispatch_test_notification(
|
|||||||
provider_config = dict(provider.config)
|
provider_config = dict(provider.config)
|
||||||
collection_ids = list(tracker.collection_ids or [])
|
collection_ids = list(tracker.collection_ids or [])
|
||||||
|
|
||||||
# Load tracking config
|
# Resolve tracking config: per-link override, else the tracker's default.
|
||||||
|
# The real watcher applies this fallback in ``load_link_data`` — tests
|
||||||
|
# must use the same logic or the user's per-tracker defaults look broken.
|
||||||
|
tracking_config_id = tt.tracking_config_id or tracker.default_tracking_config_id
|
||||||
tracking_config = None
|
tracking_config = None
|
||||||
if tt.tracking_config_id:
|
if tracking_config_id:
|
||||||
tracking_config = await session.get(TrackingConfig, tt.tracking_config_id)
|
tracking_config = await session.get(TrackingConfig, tracking_config_id)
|
||||||
|
|
||||||
# Load template slots keyed by EventType.SCHEDULED_MESSAGE.value
|
# Same fallback for template config.
|
||||||
|
template_config_id = tt.template_config_id or tracker.default_template_config_id
|
||||||
template_config = None
|
template_config = None
|
||||||
template_slots: dict[str, dict[str, str]] | None = None
|
template_slots: dict[str, dict[str, str]] | None = None
|
||||||
slot_name = _TEST_TYPE_SLOT_MAP.get(test_type, test_type)
|
slot_name = _TEST_TYPE_SLOT_MAP.get(test_type, test_type)
|
||||||
if tt.template_config_id:
|
if template_config_id:
|
||||||
template_config = await session.get(TemplateConfig, tt.template_config_id)
|
template_config = await session.get(TemplateConfig, template_config_id)
|
||||||
if template_config:
|
if template_config:
|
||||||
slot_result = await session.exec(
|
slot_result = await session.exec(
|
||||||
select(TemplateSlot).where(
|
select(TemplateSlot).where(
|
||||||
@@ -97,10 +101,21 @@ async def dispatch_test_notification(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not template_slots:
|
if not template_slots:
|
||||||
|
if not template_config_id:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"error": (
|
||||||
|
"This tracker has no Template Config linked (neither on the "
|
||||||
|
"tracker's default nor on this target link). Assign one in the "
|
||||||
|
"tracker settings and make sure it defines a "
|
||||||
|
f"'{slot_name}' slot."
|
||||||
|
),
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
"error": (
|
"error": (
|
||||||
f"No '{slot_name}' template defined for this target's template config "
|
f"No '{slot_name}' template defined in the linked Template Config "
|
||||||
|
f"'{template_config.name if template_config else template_config_id}' "
|
||||||
f"(locale: {locale}). Add the slot under Template Configs."
|
f"(locale: {locale}). Add the slot under Template Configs."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user