-
-
+
+
+
+ {t("name")}
+
+ {blueprint.name}
+
+
{t("status")}
@@ -121,6 +127,8 @@ export default function BlueprintDetailsForm({
+
+
{blueprint.message && (
@@ -138,60 +146,39 @@ export default function BlueprintDetailsForm({
-
-
- {t("blueprintInfo")}
-
-
-
- (
-
- {t("name")}
-
-
-
-
-
- )}
- />
-
- (
-
-
- {t("parsedContents")}
-
-
-
-
-
-
-
-
- )}
- />
-
+ (
+
+
+ {t("parsedContents")}
+
+
+
+
+
+
+
+
+ )}
+ />
diff --git a/src/components/BlueprintsTable.tsx b/src/components/BlueprintsTable.tsx
index 0fa05d75..8031e506 100644
--- a/src/components/BlueprintsTable.tsx
+++ b/src/components/BlueprintsTable.tsx
@@ -32,35 +32,6 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
const router = useRouter();
const columns: ExtendedColumnDef
[] = [
- {
- accessorKey: "createdAt",
- friendlyName: t("appliedAt"),
- header: ({ column }) => {
- return (
-
- );
- },
- cell: ({ row }) => {
- return (
-
- );
- }
- },
{
accessorKey: "name",
enableHiding: false,
@@ -79,7 +50,32 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
);
}
},
-
+ {
+ accessorKey: "createdAt",
+ friendlyName: t("appliedAt"),
+ header: ({ column }) => {
+ return (
+
+ );
+ },
+ cell: ({ row }) => {
+ return (
+
+ );
+ }
+ },
{
accessorKey: "source",
friendlyName: t("source"),
@@ -104,7 +100,7 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
API
-
+
);
@@ -114,7 +110,7 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
Newt CLI
-
+
);
@@ -174,7 +170,7 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) {
href={`/${orgId}/settings/blueprints/${row.original.blueprintId}`}
>
diff --git a/src/components/ClientResourcesTable.tsx b/src/components/ClientResourcesTable.tsx
index 758b6e12..023ef00c 100644
--- a/src/components/ClientResourcesTable.tsx
+++ b/src/components/ClientResourcesTable.tsx
@@ -100,7 +100,7 @@ export default function ClientResourcesTable({
) => {
try {
await api
- .delete(`/org/${orgId}/site/${siteId}/resource/${resourceId}`)
+ .delete(`/site-resource/${resourceId}`)
.then(() => {
startTransition(() => {
router.refresh();
@@ -327,6 +327,7 @@ export default function ClientResourcesTable({
setOpen={setIsEditDialogOpen}
resource={editingResource}
orgId={orgId}
+ sites={sites}
onSuccess={() => {
router.refresh();
setEditingResource(null);
diff --git a/src/components/CreateBlueprintForm.tsx b/src/components/CreateBlueprintForm.tsx
index 617f3026..2b58f34f 100644
--- a/src/components/CreateBlueprintForm.tsx
+++ b/src/components/CreateBlueprintForm.tsx
@@ -127,7 +127,7 @@ export default function CreateBlueprintForm({
-
+
)}
/>
-
- (
-
-
- {t("contents")}
-
-
- {t(
- "blueprintContentsDescription"
- )}
-
-
-
-
-
-
-
-
- )}
- />
+
+ (
+
+ {t("contents")}
+
+ {t("blueprintContentsDescription")}
+
+
+
+
+
+
+
+
+ )}
+ />
diff --git a/src/components/CreateInternalResourceDialog.tsx b/src/components/CreateInternalResourceDialog.tsx
index 894315b8..00e8ce96 100644
--- a/src/components/CreateInternalResourceDialog.tsx
+++ b/src/components/CreateInternalResourceDialog.tsx
@@ -395,9 +395,10 @@ export default function CreateInternalResourceDialog({
}
const response = await api.put>(
- `/org/${orgId}/site/${data.siteId}/resource`,
+ `/org/${orgId}/site-resource`,
{
name: data.name,
+ siteId: data.siteId,
mode: data.mode,
// protocol: data.protocol,
// proxyPort: data.mode === "port" ? data.proxyPort : undefined,
@@ -548,7 +549,7 @@ export default function CreateInternalResourceDialog({
{t(
- "createInternalResourceDialogSite"
+ "site"
)}
@@ -572,7 +573,7 @@ export default function CreateInternalResourceDialog({
field.value
)?.name
: t(
- "createInternalResourceDialogSelectSite"
+ "selectSite"
)}
@@ -582,13 +583,13 @@ export default function CreateInternalResourceDialog({
{t(
- "createInternalResourceDialogNoSitesFound"
+ "noSitesFound"
)}
diff --git a/src/components/EditInternalResourceDialog.tsx b/src/components/EditInternalResourceDialog.tsx
index cfd4fbc1..5d5745c7 100644
--- a/src/components/EditInternalResourceDialog.tsx
+++ b/src/components/EditInternalResourceDialog.tsx
@@ -41,6 +41,22 @@ import { Tag, TagInput } from "@app/components/tags/tag-input";
import { UserType } from "@server/types/UserTypes";
import { useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
import { orgQueries, resourceQueries } from "@app/lib/queries";
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList
+} from "@app/components/ui/command";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger
+} from "@app/components/ui/popover";
+import { cn } from "@app/lib/cn";
+import { ListSitesResponse } from "@server/routers/site";
+import { Check, ChevronsUpDown } from "lucide-react";
// import { InfoPopup } from "@app/components/ui/info-popup";
// Helper to validate port range string format
@@ -118,6 +134,8 @@ const getPortStringFromMode = (mode: PortMode, customValue: string): string | un
return customValue;
};
+type Site = ListSitesResponse["sites"][0];
+
type InternalResourceData = {
id: number;
name: string;
@@ -141,6 +159,7 @@ type EditInternalResourceDialogProps = {
setOpen: (val: boolean) => void;
resource: InternalResourceData;
orgId: string;
+ sites: Site[];
onSuccess?: () => void;
};
@@ -149,6 +168,7 @@ export default function EditInternalResourceDialog({
setOpen,
resource,
orgId,
+ sites,
onSuccess
}: EditInternalResourceDialogProps) {
const t = useTranslations();
@@ -161,6 +181,7 @@ export default function EditInternalResourceDialog({
.string()
.min(1, t("editInternalResourceDialogNameRequired"))
.max(255, t("editInternalResourceDialogNameMaxLength")),
+ siteId: z.number().int().positive(),
mode: z.enum(["host", "cidr", "port"]),
// protocol: z.enum(["tcp", "udp"]).nullish(),
// proxyPort: z.int().positive().min(1, t("editInternalResourceDialogProxyPortMin")).max(65535, t("editInternalResourceDialogProxyPortMax")).nullish(),
@@ -349,10 +370,15 @@ export default function EditInternalResourceDialog({
: ""
);
+ const availableSites = sites.filter(
+ (site) => site.type === "newt" && site.subnet
+ );
+
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
name: resource.name,
+ siteId: resource.siteId,
mode: resource.mode || "host",
// protocol: (resource.protocol as "tcp" | "udp" | null | undefined) ?? undefined,
// proxyPort: resource.proxyPort ?? undefined,
@@ -421,9 +447,10 @@ export default function EditInternalResourceDialog({
// Update the site resource
await api.post(
- `/org/${orgId}/site/${resource.siteId}/resource/${resource.id}`,
+ `/site-resource/${resource.id}`,
{
name: data.name,
+ siteId: data.siteId,
mode: data.mode,
// protocol: data.mode === "port" ? data.protocol : null,
// proxyPort: data.mode === "port" ? data.proxyPort : null,
@@ -504,6 +531,7 @@ export default function EditInternalResourceDialog({
if (resourceChanged) {
form.reset({
name: resource.name,
+ siteId: resource.siteId,
mode: resource.mode || "host",
destination: resource.destination || "",
alias: resource.alias ?? null,
@@ -559,6 +587,7 @@ export default function EditInternalResourceDialog({
// reset only on close
form.reset({
name: resource.name,
+ siteId: resource.siteId,
mode: resource.mode || "host",
// protocol: (resource.protocol as "tcp" | "udp" | null | undefined) ?? undefined,
// proxyPort: resource.proxyPort ?? undefined,
@@ -636,6 +665,99 @@ export default function EditInternalResourceDialog({
)}
/>
+ (
+
+
+ {t(
+ "site"
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ {t(
+ "noSitesFound"
+ )}
+
+
+ {availableSites.map(
+ (
+ site
+ ) => (
+ {
+ field.onChange(
+ site.siteId
+ );
+ }}
+ >
+
+ {
+ site.name
+ }
+
+ )
+ )}
+
+
+
+
+
+
+
+ )}
+ />
+
-
+
diff --git a/src/components/SidebarNav.tsx b/src/components/SidebarNav.tsx
index 8e593b96..389f3978 100644
--- a/src/components/SidebarNav.tsx
+++ b/src/components/SidebarNav.tsx
@@ -112,7 +112,7 @@ function CollapsibleNavItem({