move to private routes

This commit is contained in:
miloschwartz
2026-03-24 20:27:15 -07:00
parent 212b7a104f
commit 3525b367b3
24 changed files with 1054 additions and 103 deletions

View File

@@ -15,19 +15,27 @@ import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import CreateSiteProvisioningKeyCredenza from "@app/components/CreateSiteProvisioningKeyCredenza";
import EditSiteProvisioningKeyCredenza from "@app/components/EditSiteProvisioningKeyCredenza";
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import { toast } from "@app/hooks/useToast";
import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import moment from "moment";
import { useTranslations } from "next-intl";
import { build } from "@server/build";
import { TierFeature, tierMatrix } from "@server/lib/billing/tierMatrix";
export type SiteProvisioningKeyRow = {
id: string;
key: string;
name: string;
createdAt: string;
lastUsed: string | null;
maxBatchSize: number | null;
numUsed: number;
validUntil: string | null;
};
type SiteProvisioningKeysTableProps = {
@@ -47,8 +55,15 @@ export default function SiteProvisioningKeysTable({
const [rows, setRows] = useState<SiteProvisioningKeyRow[]>(keys);
const api = createApiClient(useEnvContext());
const t = useTranslations();
const { isPaidUser } = usePaidStatus();
const canUseSiteProvisioning =
isPaidUser(tierMatrix[TierFeature.SiteProvisioningKeys]) &&
build !== "oss";
const [isRefreshing, setIsRefreshing] = useState(false);
const [createOpen, setCreateOpen] = useState(false);
const [editOpen, setEditOpen] = useState(false);
const [editingKey, setEditingKey] =
useState<SiteProvisioningKeyRow | null>(null);
useEffect(() => {
setRows(keys);
@@ -121,6 +136,68 @@ export default function SiteProvisioningKeysTable({
return <span className="font-mono">{r.key}</span>;
}
},
{
accessorKey: "maxBatchSize",
friendlyName: t("provisioningKeysMaxBatchSize"),
header: () => (
<span className="p-3">{t("provisioningKeysMaxBatchSize")}</span>
),
cell: ({ row }) => {
const r = row.original;
return (
<span>
{r.maxBatchSize == null
? t("provisioningKeysMaxBatchUnlimited")
: r.maxBatchSize}
</span>
);
}
},
{
accessorKey: "numUsed",
friendlyName: t("provisioningKeysNumUsed"),
header: () => (
<span className="p-3">{t("provisioningKeysNumUsed")}</span>
),
cell: ({ row }) => {
const r = row.original;
return <span>{r.numUsed}</span>;
}
},
{
accessorKey: "validUntil",
friendlyName: t("provisioningKeysValidUntil"),
header: () => (
<span className="p-3">{t("provisioningKeysValidUntil")}</span>
),
cell: ({ row }) => {
const r = row.original;
return (
<span>
{r.validUntil
? moment(r.validUntil).format("lll")
: t("provisioningKeysNoExpiry")}
</span>
);
}
},
{
accessorKey: "lastUsed",
friendlyName: t("provisioningKeysLastUsed"),
header: () => (
<span className="p-3">{t("provisioningKeysLastUsed")}</span>
),
cell: ({ row }) => {
const r = row.original;
return (
<span>
{r.lastUsed
? moment(r.lastUsed).format("lll")
: t("provisioningKeysNeverUsed")}
</span>
);
}
},
{
accessorKey: "createdAt",
friendlyName: t("createdAt"),
@@ -149,6 +226,16 @@ export default function SiteProvisioningKeysTable({
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
disabled={!canUseSiteProvisioning}
onClick={() => {
setEditingKey(r);
setEditOpen(true);
}}
>
{t("edit")}
</DropdownMenuItem>
<DropdownMenuItem
disabled={!canUseSiteProvisioning}
onClick={() => {
setSelected(r);
setIsDeleteModalOpen(true);
@@ -174,6 +261,18 @@ export default function SiteProvisioningKeysTable({
orgId={orgId}
/>
<EditSiteProvisioningKeyCredenza
open={editOpen}
setOpen={(v) => {
setEditOpen(v);
if (!v) {
setEditingKey(null);
}
}}
orgId={orgId}
provisioningKey={editingKey}
/>
{selected && (
<ConfirmDeleteDialog
open={isDeleteModalOpen}
@@ -203,7 +302,12 @@ export default function SiteProvisioningKeysTable({
title={t("provisioningKeys")}
searchPlaceholder={t("searchProvisioningKeys")}
searchColumn="name"
onAdd={() => setCreateOpen(true)}
onAdd={() => {
if (canUseSiteProvisioning) {
setCreateOpen(true);
}
}}
addButtonDisabled={!canUseSiteProvisioning}
onRefresh={refreshData}
isRefreshing={isRefreshing}
addButtonText={t("provisioningKeysAdd")}