mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-06 04:10:13 +00:00
Merge pull request #3331 from Fredkiss3/feat/geoip-tag-in-tables
feat: Show GeoIp country flags in site & rules page
This commit is contained in:
@@ -795,10 +795,13 @@ export const COUNTRIES = [
|
|||||||
name: "Serbia",
|
name: "Serbia",
|
||||||
code: "RS"
|
code: "RS"
|
||||||
},
|
},
|
||||||
{
|
// Removed as this is a deprecated ISO country code, not supported anymore
|
||||||
name: "Serbia and Montenegro",
|
// Also the individual flags for Serbia & Montenegro are already included in the list
|
||||||
code: "CS"
|
// more details: https://en.wikipedia.org/wiki/ISO_3166-2:CS
|
||||||
},
|
// {
|
||||||
|
// name: "Serbia and Montenegro",
|
||||||
|
// code: "CS"
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
name: "Seychelles",
|
name: "Seychelles",
|
||||||
code: "SC"
|
code: "SC"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import logger from "@server/logger";
|
|||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { getCountryCodeForIp } from "@server/lib/geoip";
|
||||||
|
|
||||||
const getSiteSchema = z.strictObject({
|
const getSiteSchema = z.strictObject({
|
||||||
siteId: z
|
siteId: z
|
||||||
@@ -47,6 +48,7 @@ type SiteQueryRow = NonNullable<Awaited<ReturnType<typeof query>>>;
|
|||||||
export type GetSiteResponse = SiteQueryRow["sites"] & {
|
export type GetSiteResponse = SiteQueryRow["sites"] & {
|
||||||
newtId: string | null;
|
newtId: string | null;
|
||||||
newtVersion: string | null;
|
newtVersion: string | null;
|
||||||
|
countryCode: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
registry.registerPath({
|
registry.registerPath({
|
||||||
@@ -134,7 +136,10 @@ export async function getSite(
|
|||||||
const data: GetSiteResponse = {
|
const data: GetSiteResponse = {
|
||||||
...site.sites,
|
...site.sites,
|
||||||
newtId: site.newt ? site.newt.newtId : null,
|
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<GetSiteResponse>(res, {
|
return response<GetSiteResponse>(res, {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
InfoSectionTitle
|
InfoSectionTitle
|
||||||
} from "@app/components/InfoSection";
|
} from "@app/components/InfoSection";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import { countryCodeToFlagEmoji } from "@app/lib/countryCodeToFlagEmoji";
|
||||||
|
|
||||||
type SiteInfoCardProps = {};
|
type SiteInfoCardProps = {};
|
||||||
|
|
||||||
@@ -52,7 +53,11 @@ export default function SiteInfoCard({}: SiteInfoCardProps) {
|
|||||||
<InfoSection>
|
<InfoSection>
|
||||||
<InfoSectionTitle>{t("publicIpEndpoint")}</InfoSectionTitle>
|
<InfoSectionTitle>{t("publicIpEndpoint")}</InfoSectionTitle>
|
||||||
<InfoSectionContent>
|
<InfoSectionContent>
|
||||||
{formatPublicEndpoint(site.endpoint)}
|
{formatPublicEndpoint(site.endpoint)}
|
||||||
|
<span className="text-lg">
|
||||||
|
{site.countryCode &&
|
||||||
|
countryCodeToFlagEmoji(site.countryCode)}
|
||||||
|
</span>
|
||||||
</InfoSectionContent>
|
</InfoSectionContent>
|
||||||
</InfoSection>
|
</InfoSection>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ import {
|
|||||||
sortPolicyRulesForResourceOverlay,
|
sortPolicyRulesForResourceOverlay,
|
||||||
type PolicyAccessRule
|
type PolicyAccessRule
|
||||||
} from "./policy-access-rule-utils";
|
} from "./policy-access-rule-utils";
|
||||||
|
import { countryCodeToFlagEmoji } from "@app/lib/countryCodeToFlagEmoji";
|
||||||
|
|
||||||
export type PolicyAccessRulesTableProps = {
|
export type PolicyAccessRulesTableProps = {
|
||||||
rules: PolicyAccessRule[];
|
rules: PolicyAccessRule[];
|
||||||
@@ -490,8 +491,17 @@ export function PolicyAccessRulesTable({
|
|||||||
{
|
{
|
||||||
accessorKey: "value",
|
accessorKey: "value",
|
||||||
header: () => <span className="p-3">{t("value")}</span>,
|
header: () => <span className="p-3">{t("value")}</span>,
|
||||||
cell: ({ row }) =>
|
cell: ({ row }) => {
|
||||||
row.original.match === "COUNTRY" ? (
|
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" ? (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -502,15 +512,22 @@ export function PolicyAccessRulesTable({
|
|||||||
}
|
}
|
||||||
className="w-full min-w-0 justify-between"
|
className="w-full min-w-0 justify-between"
|
||||||
>
|
>
|
||||||
{row.original.value
|
{selectedCountry ? (
|
||||||
? COUNTRIES.find(
|
<>
|
||||||
(c) =>
|
<span>
|
||||||
c.code === row.original.value
|
{selectedCountry.code === "ALL"
|
||||||
)?.name +
|
? "🌍"
|
||||||
" (" +
|
: countryCodeToFlagEmoji(
|
||||||
row.original.value +
|
selectedCountry.code
|
||||||
")"
|
)}
|
||||||
: t("selectCountry")}
|
|
||||||
|
{selectedCountry.name} (
|
||||||
|
{selectedCountry.code})
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
t("selectCountry")
|
||||||
|
)}
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
@@ -540,6 +557,13 @@ export function PolicyAccessRulesTable({
|
|||||||
<Check
|
<Check
|
||||||
className={`mr-2 h-4 w-4 ${row.original.value === country.code ? "opacity-100" : "opacity-0"}`}
|
className={`mr-2 h-4 w-4 ${row.original.value === country.code ? "opacity-100" : "opacity-0"}`}
|
||||||
/>
|
/>
|
||||||
|
<span>
|
||||||
|
{country.code === "ALL"
|
||||||
|
? "🌍"
|
||||||
|
: countryCodeToFlagEmoji(
|
||||||
|
country.code
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
{country.name} (
|
{country.name} (
|
||||||
{country.code})
|
{country.code})
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
@@ -767,7 +791,8 @@ export function PolicyAccessRulesTable({
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "enabled",
|
accessorKey: "enabled",
|
||||||
|
|||||||
Reference in New Issue
Block a user