refactor(dns-fe): tighten resolved-records card

- Drop the no-op useMemo that invalidated on every refresh anyway;
  toRecordList is now called inline.
- Collapse three near-identical Stack > Typography pairs in the
  meta row into a [{label, value}].map block.
- Use MUI native p/m props on the records <ul> Stack instead of
  packing padding/margin into sx; only listStyle: "none" stays in
  sx (no MUI shorthand).
- Surface the matched flag — when an expected value is configured
  and the resolved records didn't match, render a "Did not match
  expected value" hint in red next to the resolvedAt timestamp so
  the user understands why the monitor went down without leaving
  the detail page.
- 16 locales: add the new pages.uptime.details.dns.notMatched key
  with machine translations.
This commit is contained in:
gorkem-bwl
2026-05-05 23:13:03 -04:00
parent c1a8d4c5ec
commit e082529176
17 changed files with 74 additions and 59 deletions
@@ -1,4 +1,3 @@
import { useMemo } from "react";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";
@@ -26,27 +25,27 @@ const formatRecord = (recordType: DnsRecordType, record: unknown): string => {
return JSON.stringify(record);
};
const toRecordList = (recordType: DnsRecordType, results: unknown): string[] => {
if (!Array.isArray(results)) return [];
return (results as unknown[]).map((r) => formatRecord(recordType, r));
};
const toRecordList = (recordType: DnsRecordType, results: unknown): string[] =>
Array.isArray(results) ? results.map((r) => formatRecord(recordType, r)) : [];
export const DnsResolvedRecordsCard = ({ resolution }: Props) => {
const theme = useTheme();
const { t } = useTranslation();
const uiTimezone = useSelector((state: RootState) => state.ui.timezone);
const records = useMemo(
() => toRecordList(resolution.recordType, resolution.results),
[resolution.recordType, resolution.results]
);
const records = toRecordList(resolution.recordType, resolution.results);
const resolvedAtFormatted = formatDateWithTz(
resolution.resolvedAt,
"ddd, MMM D, YYYY, HH:mm",
uiTimezone
);
const meta: { label: string; value: string }[] = [
{ label: t("pages.uptime.details.dns.recordType"), value: resolution.recordType },
{ label: t("pages.uptime.details.dns.dnsServer"), value: resolution.dnsServer },
{ label: t("pages.uptime.details.dns.hostname"), value: resolution.hostname },
];
return (
<BaseBox padding={theme.spacing(LAYOUT.LG)}>
<Stack gap={theme.spacing(LAYOUT.SM)}>
@@ -58,12 +57,26 @@ export const DnsResolvedRecordsCard = ({ resolution }: Props) => {
flexWrap="wrap"
>
<Typography variant="h2">{t("pages.uptime.details.dns.title")}</Typography>
<Typography
variant="body2"
color={theme.palette.text.secondary}
<Stack
direction="row"
gap={theme.spacing(LAYOUT.SM)}
alignItems="baseline"
>
{t("pages.uptime.details.dns.resolvedAt", { time: resolvedAtFormatted })}
</Typography>
{!resolution.matched && (
<Typography
variant="body2"
color={theme.palette.error.main}
>
{t("pages.uptime.details.dns.notMatched")}
</Typography>
)}
<Typography
variant="body2"
color={theme.palette.text.secondary}
>
{t("pages.uptime.details.dns.resolvedAt", { time: resolvedAtFormatted })}
</Typography>
</Stack>
</Stack>
<Stack
@@ -71,33 +84,17 @@ export const DnsResolvedRecordsCard = ({ resolution }: Props) => {
gap={theme.spacing(LAYOUT.LG)}
flexWrap="wrap"
>
<Stack>
<Typography
variant="caption"
color={theme.palette.text.secondary}
>
{t("pages.uptime.details.dns.recordType")}
</Typography>
<Typography variant="body1">{resolution.recordType}</Typography>
</Stack>
<Stack>
<Typography
variant="caption"
color={theme.palette.text.secondary}
>
{t("pages.uptime.details.dns.dnsServer")}
</Typography>
<Typography variant="body1">{resolution.dnsServer}</Typography>
</Stack>
<Stack>
<Typography
variant="caption"
color={theme.palette.text.secondary}
>
{t("pages.uptime.details.dns.hostname")}
</Typography>
<Typography variant="body1">{resolution.hostname}</Typography>
</Stack>
{meta.map(({ label, value }) => (
<Stack key={label}>
<Typography
variant="caption"
color={theme.palette.text.secondary}
>
{label}
</Typography>
<Typography variant="body1">{value}</Typography>
</Stack>
))}
</Stack>
<Stack gap={theme.spacing(LAYOUT.XXS)}>
@@ -119,7 +116,9 @@ export const DnsResolvedRecordsCard = ({ resolution }: Props) => {
<Stack
component="ul"
gap={theme.spacing(LAYOUT.XXS)}
sx={{ listStyle: "none", padding: 0, margin: 0 }}
p={0}
m={0}
sx={{ listStyle: "none" }}
>
{records.map((record, idx) => (
<Typography
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "اسم المضيف",
"records_one": "سجل {{count}}",
"records_other": "{{count}} سجلات",
"noRecords": "لا توجد سجلات مُعادة"
"noRecords": "لا توجد سجلات مُعادة",
"notMatched": "لم تتطابق مع القيمة المتوقعة"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Název hostitele",
"records_one": "{{count}} záznam",
"records_other": "{{count}} záznamů",
"noRecords": "Nebyly vráceny žádné záznamy"
"noRecords": "Nebyly vráceny žádné záznamy",
"notMatched": "Neodpovídá očekávané hodnotě"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Hostname",
"records_one": "{{count}} Eintrag",
"records_other": "{{count}} Einträge",
"noRecords": "Keine Einträge zurückgegeben"
"noRecords": "Keine Einträge zurückgegeben",
"notMatched": "Stimmt nicht mit dem erwarteten Wert überein"
}
}
}
+2 -1
View File
@@ -1511,7 +1511,8 @@
"hostname": "Hostname",
"records_one": "{{count}} record",
"records_other": "{{count}} records",
"noRecords": "No records returned"
"noRecords": "No records returned",
"notMatched": "Did not match expected value"
}
}
}
+2 -1
View File
@@ -1466,7 +1466,8 @@
"hostname": "Nombre de host",
"records_one": "{{count}} registro",
"records_other": "{{count}} registros",
"noRecords": "No se devolvieron registros"
"noRecords": "No se devolvieron registros",
"notMatched": "No coincide con el valor esperado"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Isäntänimi",
"records_one": "{{count}} tietue",
"records_other": "{{count}} tietuetta",
"noRecords": "Tietueita ei palautettu"
"noRecords": "Tietueita ei palautettu",
"notMatched": "Ei vastaa odotettua arvoa"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Nom d'hôte",
"records_one": "{{count}} enregistrement",
"records_other": "{{count}} enregistrements",
"noRecords": "Aucun enregistrement renvoyé"
"noRecords": "Aucun enregistrement renvoyé",
"notMatched": "Ne correspond pas à la valeur attendue"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "ホスト名",
"records_one": "{{count}} 件のレコード",
"records_other": "{{count}} 件のレコード",
"noRecords": "レコードは返されませんでした"
"noRecords": "レコードは返されませんでした",
"notMatched": "期待値と一致しませんでした"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Hostname",
"records_one": "{{count}} registro",
"records_other": "{{count}} registros",
"noRecords": "Nenhum registro retornado"
"noRecords": "Nenhum registro retornado",
"notMatched": "Não corresponde ao valor esperado"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Имя хоста",
"records_one": "{{count}} запись",
"records_other": "{{count}} записей",
"noRecords": "Записи не возвращены"
"noRecords": "Записи не возвращены",
"notMatched": "Не соответствует ожидаемому значению"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "ชื่อโฮสต์",
"records_one": "{{count}} เรกคอร์ด",
"records_other": "{{count}} เรกคอร์ด",
"noRecords": "ไม่มีเรกคอร์ดที่ส่งกลับ"
"noRecords": "ไม่มีเรกคอร์ดที่ส่งกลับ",
"notMatched": "ไม่ตรงกับค่าที่คาดไว้"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Ana bilgisayar adı",
"records_one": "{{count}} kayıt",
"records_other": "{{count}} kayıt",
"noRecords": "Kayıt döndürülmedi"
"noRecords": "Kayıt döndürülmedi",
"notMatched": "Beklenen değerle eşleşmedi"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Ім'я хоста",
"records_one": "{{count}} запис",
"records_other": "{{count}} записів",
"noRecords": "Записи не повернуто"
"noRecords": "Записи не повернуто",
"notMatched": "Не відповідає очікуваному значенню"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "Tên máy chủ",
"records_one": "{{count}} bản ghi",
"records_other": "{{count}} bản ghi",
"noRecords": "Không có bản ghi được trả về"
"noRecords": "Không có bản ghi được trả về",
"notMatched": "Không khớp với giá trị mong đợi"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "主机名",
"records_one": "{{count}} 条记录",
"records_other": "{{count}} 条记录",
"noRecords": "未返回任何记录"
"noRecords": "未返回任何记录",
"notMatched": "未匹配期望值"
}
}
}
+2 -1
View File
@@ -1452,7 +1452,8 @@
"hostname": "主機名稱",
"records_one": "{{count}} 筆記錄",
"records_other": "{{count}} 筆記錄",
"noRecords": "沒有返回任何記錄"
"noRecords": "沒有返回任何記錄",
"notMatched": "未符合期望值"
}
}
}