diff --git a/server/db/countries.ts b/server/db/countries.ts index 749f1183f..c668ca2ae 100644 --- a/server/db/countries.ts +++ b/server/db/countries.ts @@ -795,10 +795,13 @@ export const COUNTRIES = [ name: "Serbia", code: "RS" }, - { - name: "Serbia and Montenegro", - code: "CS" - }, + // Removed as this is a deprecated ISO country code, not supported anymore + // Also the individual flags for Serbia & Montenegro are already included in the list + // more details: https://en.wikipedia.org/wiki/ISO_3166-2:CS + // { + // name: "Serbia and Montenegro", + // code: "CS" + // }, { name: "Seychelles", code: "SC" diff --git a/server/routers/site/getSite.ts b/server/routers/site/getSite.ts index a671a47f9..885e3aa7a 100644 --- a/server/routers/site/getSite.ts +++ b/server/routers/site/getSite.ts @@ -10,6 +10,7 @@ import logger from "@server/logger"; import stoi from "@server/lib/stoi"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; +import { getCountryCodeForIp } from "@server/lib/geoip"; const getSiteSchema = z.strictObject({ siteId: z @@ -47,6 +48,7 @@ type SiteQueryRow = NonNullable>>; export type GetSiteResponse = SiteQueryRow["sites"] & { newtId: string | null; newtVersion: string | null; + countryCode: string | null; }; registry.registerPath({ @@ -134,7 +136,10 @@ export async function getSite( const data: GetSiteResponse = { ...site.sites, newtId: site.newt ? site.newt.newtId : null, - newtVersion: site.newt?.version ?? null + newtVersion: site.newt?.version ?? null, + countryCode: site.sites.endpoint + ? ((await getCountryCodeForIp(site.sites.endpoint)) ?? null) + : null }; return response(res, { diff --git a/src/components/SiteInfoCard.tsx b/src/components/SiteInfoCard.tsx index 21697d697..a5e639c28 100644 --- a/src/components/SiteInfoCard.tsx +++ b/src/components/SiteInfoCard.tsx @@ -9,6 +9,7 @@ import { InfoSectionTitle } from "@app/components/InfoSection"; import { useTranslations } from "next-intl"; +import { countryCodeToFlagEmoji } from "@app/lib/countryCodeToFlagEmoji"; type SiteInfoCardProps = {}; @@ -52,7 +53,11 @@ export default function SiteInfoCard({}: SiteInfoCardProps) { {t("publicIpEndpoint")} - {formatPublicEndpoint(site.endpoint)} + {formatPublicEndpoint(site.endpoint)}  + + {site.countryCode && + countryCodeToFlagEmoji(site.countryCode)} + ) : null; diff --git a/src/components/resource-policy/PolicyAccessRulesTable.tsx b/src/components/resource-policy/PolicyAccessRulesTable.tsx index a701b92ff..b8445a44c 100644 --- a/src/components/resource-policy/PolicyAccessRulesTable.tsx +++ b/src/components/resource-policy/PolicyAccessRulesTable.tsx @@ -74,6 +74,7 @@ import { sortPolicyRulesForResourceOverlay, type PolicyAccessRule } from "./policy-access-rule-utils"; +import { countryCodeToFlagEmoji } from "@app/lib/countryCodeToFlagEmoji"; export type PolicyAccessRulesTableProps = { rules: PolicyAccessRule[]; @@ -490,8 +491,17 @@ export function PolicyAccessRulesTable({ { accessorKey: "value", header: () => {t("value")}, - cell: ({ row }) => - row.original.match === "COUNTRY" ? ( + cell: ({ row }) => { + let selectedCountry: (typeof COUNTRIES)[number] | undefined; + if ( + row.original.match === "COUNTRY" && + row.original.value + ) { + selectedCountry = COUNTRIES.find( + (c) => c.code === row.original.value + ); + } + return row.original.match === "COUNTRY" ? ( @@ -540,6 +557,13 @@ export function PolicyAccessRulesTable({ + + {country.code === "ALL" + ? "🌍" + : countryCodeToFlagEmoji( + country.code + )} + {country.name} ( {country.code}) @@ -767,7 +791,8 @@ export function PolicyAccessRulesTable({ }); }} /> - ) + ); + } }, { accessorKey: "enabled",