mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-01 23:46:38 +00:00
Provisioning room basics done
This commit is contained in:
56
src/app/[orgId]/settings/provisioning/keys/page.tsx
Normal file
56
src/app/[orgId]/settings/provisioning/keys/page.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
||||
import SiteProvisioningKeysTable, {
|
||||
SiteProvisioningKeyRow
|
||||
} from "../../../../../components/SiteProvisioningKeysTable";
|
||||
import { ListSiteProvisioningKeysResponse } from "@server/routers/siteProvisioning/types";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { TierFeature, tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
|
||||
type ProvisioningKeysPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
};
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function ProvisioningKeysPage(
|
||||
props: ProvisioningKeysPageProps
|
||||
) {
|
||||
const params = await props.params;
|
||||
const t = await getTranslations();
|
||||
|
||||
let siteProvisioningKeys: ListSiteProvisioningKeysResponse["siteProvisioningKeys"] =
|
||||
[];
|
||||
try {
|
||||
const res = await internal.get<
|
||||
AxiosResponse<ListSiteProvisioningKeysResponse>
|
||||
>(
|
||||
`/org/${params.orgId}/site-provisioning-keys`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
siteProvisioningKeys = res.data.data.siteProvisioningKeys;
|
||||
} catch (e) {}
|
||||
|
||||
const rows: SiteProvisioningKeyRow[] = siteProvisioningKeys.map((k) => ({
|
||||
name: k.name,
|
||||
id: k.siteProvisioningKeyId,
|
||||
key: `${k.siteProvisioningKeyId}••••••••••••••••••••${k.lastChars}`,
|
||||
createdAt: k.createdAt,
|
||||
lastUsed: k.lastUsed,
|
||||
maxBatchSize: k.maxBatchSize,
|
||||
numUsed: k.numUsed,
|
||||
validUntil: k.validUntil
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix[TierFeature.SiteProvisioningKeys]}
|
||||
/>
|
||||
|
||||
<SiteProvisioningKeysTable keys={rows} orgId={params.orgId} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
38
src/app/[orgId]/settings/provisioning/layout.tsx
Normal file
38
src/app/[orgId]/settings/provisioning/layout.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { HorizontalTabs } from "@app/components/HorizontalTabs";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
interface ProvisioningLayoutProps {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ orgId: string }>;
|
||||
}
|
||||
|
||||
export default async function ProvisioningLayout({
|
||||
children,
|
||||
params
|
||||
}: ProvisioningLayoutProps) {
|
||||
const { orgId } = await params;
|
||||
const t = await getTranslations();
|
||||
|
||||
const navItems = [
|
||||
{
|
||||
title: t("provisioningKeys"),
|
||||
href: `/${orgId}/settings/provisioning/keys`
|
||||
},
|
||||
{
|
||||
title: t("pendingSites"),
|
||||
href: `/${orgId}/settings/provisioning/pending`
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={t("provisioningManage")}
|
||||
description={t("provisioningDescription")}
|
||||
/>
|
||||
|
||||
<HorizontalTabs items={navItems}>{children}</HorizontalTabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,60 +1,10 @@
|
||||
import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import SiteProvisioningKeysTable, {
|
||||
SiteProvisioningKeyRow
|
||||
} from "../../../../components/SiteProvisioningKeysTable";
|
||||
import { ListSiteProvisioningKeysResponse } from "@server/routers/siteProvisioning/types";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { TierFeature, tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
type ProvisioningPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
};
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function ProvisioningPage(props: ProvisioningPageProps) {
|
||||
const params = await props.params;
|
||||
const t = await getTranslations();
|
||||
|
||||
let siteProvisioningKeys: ListSiteProvisioningKeysResponse["siteProvisioningKeys"] =
|
||||
[];
|
||||
try {
|
||||
const res = await internal.get<
|
||||
AxiosResponse<ListSiteProvisioningKeysResponse>
|
||||
>(
|
||||
`/org/${params.orgId}/site-provisioning-keys`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
siteProvisioningKeys = res.data.data.siteProvisioningKeys;
|
||||
} catch (e) {}
|
||||
|
||||
const rows: SiteProvisioningKeyRow[] = siteProvisioningKeys.map((k) => ({
|
||||
name: k.name,
|
||||
id: k.siteProvisioningKeyId,
|
||||
key: `${k.siteProvisioningKeyId}••••••••••••••••••••${k.lastChars}`,
|
||||
createdAt: k.createdAt,
|
||||
lastUsed: k.lastUsed,
|
||||
maxBatchSize: k.maxBatchSize,
|
||||
numUsed: k.numUsed,
|
||||
validUntil: k.validUntil
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={t("provisioningKeysManage")}
|
||||
description={t("provisioningKeysDescription")}
|
||||
/>
|
||||
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix[TierFeature.SiteProvisioningKeys]}
|
||||
/>
|
||||
|
||||
<SiteProvisioningKeysTable keys={rows} orgId={params.orgId} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
redirect(`/${params.orgId}/settings/provisioning/keys`);
|
||||
}
|
||||
82
src/app/[orgId]/settings/provisioning/pending/page.tsx
Normal file
82
src/app/[orgId]/settings/provisioning/pending/page.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import { ListSitesResponse } from "@server/routers/site";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { SiteRow } from "@app/components/SitesTable";
|
||||
import PendingSitesTable from "@app/components/PendingSitesTable";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
type PendingSitesPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
searchParams: Promise<Record<string, string>>;
|
||||
};
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function PendingSitesPage(props: PendingSitesPageProps) {
|
||||
const params = await props.params;
|
||||
|
||||
const incomingSearchParams = new URLSearchParams(await props.searchParams);
|
||||
incomingSearchParams.set("status", "pending");
|
||||
|
||||
let sites: ListSitesResponse["sites"] = [];
|
||||
let pagination: ListSitesResponse["pagination"] = {
|
||||
total: 0,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await internal.get<AxiosResponse<ListSitesResponse>>(
|
||||
`/org/${params.orgId}/sites?${incomingSearchParams.toString()}`,
|
||||
await authCookieHeader()
|
||||
);
|
||||
const responseData = res.data.data;
|
||||
sites = responseData.sites;
|
||||
pagination = responseData.pagination;
|
||||
} catch (e) {}
|
||||
|
||||
const t = await getTranslations();
|
||||
|
||||
function formatSize(mb: number, type: string): string {
|
||||
if (type === "local") {
|
||||
return "-";
|
||||
}
|
||||
if (mb >= 1024 * 1024) {
|
||||
return t("terabytes", { count: (mb / (1024 * 1024)).toFixed(2) });
|
||||
} else if (mb >= 1024) {
|
||||
return t("gigabytes", { count: (mb / 1024).toFixed(2) });
|
||||
} else {
|
||||
return t("megabytes", { count: mb.toFixed(2) });
|
||||
}
|
||||
}
|
||||
|
||||
const siteRows: SiteRow[] = sites.map((site) => ({
|
||||
name: site.name,
|
||||
id: site.siteId,
|
||||
nice: site.niceId.toString(),
|
||||
address: site.address?.split("/")[0],
|
||||
mbIn: formatSize(site.megabytesIn || 0, site.type),
|
||||
mbOut: formatSize(site.megabytesOut || 0, site.type),
|
||||
orgId: params.orgId,
|
||||
type: site.type as any,
|
||||
online: site.online,
|
||||
newtVersion: site.newtVersion || undefined,
|
||||
newtUpdateAvailable: site.newtUpdateAvailable || false,
|
||||
exitNodeName: site.exitNodeName || undefined,
|
||||
exitNodeEndpoint: site.exitNodeEndpoint || undefined,
|
||||
remoteExitNodeId: (site as any).remoteExitNodeId || undefined
|
||||
}));
|
||||
|
||||
return (
|
||||
<PendingSitesTable
|
||||
sites={siteRows}
|
||||
orgId={params.orgId}
|
||||
rowCount={pagination.total}
|
||||
pagination={{
|
||||
pageIndex: pagination.page - 1,
|
||||
pageSize: pagination.pageSize
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ export default async function SitesPage(props: SitesPageProps) {
|
||||
const params = await props.params;
|
||||
|
||||
const searchParams = new URLSearchParams(await props.searchParams);
|
||||
searchParams.set("status", "accepted");
|
||||
|
||||
let sites: ListSitesResponse["sites"] = [];
|
||||
let pagination: ListSitesResponse["pagination"] = {
|
||||
|
||||
Reference in New Issue
Block a user