Compare commits

..

4 Commits

Author SHA1 Message Date
Owen Schwartz e7fdbf9e85 Merge pull request #3699 from fosrl/dev
1.22.1-s.1
2026-09-04 10:38:39 -04:00
Owen 778a840ed7 Fix react bug not making it possible to complete security form 2026-09-04 10:08:57 -04:00
Owen 9d19195089 Configurable tab title and disable flag for keys 2026-09-04 09:20:20 -04:00
Owen 54bbe82504 Dont log invalid message type
Fixes #3695
2026-09-04 09:06:58 -04:00
14 changed files with 360 additions and 693 deletions
+284 -669
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -33,7 +33,7 @@
},
"dependencies": {
"@asteasolutions/zod-to-openapi": "9.1.0",
"@aws-sdk/client-s3": "3.1123.0",
"@aws-sdk/client-s3": "3.1121.0",
"@devolutions/iron-remote-desktop": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-0.0.0.tgz",
"@devolutions/iron-remote-desktop-rdp": "https://static.pangolin.net/packages/devolutions-iron-remote-desktop-rdp-0.0.1.tgz",
"@headlessui/react": "2.2.10",
@@ -69,7 +69,7 @@
"@simplewebauthn/server": "13.3.3",
"@tailwindcss/forms": "0.5.11",
"@tanstack/react-query": "5.102.8",
"@tanstack/react-table": "9.2.4",
"@tanstack/react-table": "8.21.3",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
@@ -99,7 +99,7 @@
"lucide-react": "1.38.0",
"maxmind": "5.0.7",
"moment": "2.30.1",
"next": "16.3.4",
"next": "16.3.3",
"next-intl": "4.14.1",
"next-themes": "0.4.6",
"nextjs-toploader": "3.9.17",
@@ -110,7 +110,7 @@
"posthog-node": "5.51.4",
"qrcode.react": "4.2.0",
"react": "19.2.8",
"react-day-picker": "10.0.1",
"react-day-picker": "9.14.0",
"react-dom": "19.2.8",
"react-easy-sort": "1.8.0",
"react-hook-form": "7.87.0",
@@ -169,15 +169,15 @@
"esbuild": "0.28.2",
"esbuild-node-externals": "2.0.0",
"eslint": "10.9.1",
"eslint-config-next": "16.3.4",
"eslint-config-next": "16.3.3",
"postcss": "8.5.26",
"prettier": "3.9.6",
"react-email": "6.9.3",
"tailwindcss": "4.3.3",
"tsc-alias": "1.9.3",
"tsc-alias": "1.9.2",
"tsx": "4.23.13",
"typescript": "7.0.2",
"typescript-eslint": "8.69.0"
"typescript": "6.0.3",
"typescript-eslint": "8.68.0"
},
"overrides": {
"esbuild": "0.28.2",
+5
View File
@@ -112,6 +112,11 @@ export class Config {
? "true"
: "false";
process.env.FLAGS_DISABLE_VIRTUAL_API_KEYS_UI = parsedConfig.flags
?.disable_virtual_api_keys_ui
? "true"
: "false";
this.rawConfig = parsedConfig;
}
+1
View File
@@ -442,6 +442,7 @@ export const configSchema = z
disable_config_managed_domains: z.boolean().optional(),
disable_product_help_banners: z.boolean().optional(),
disable_enterprise_features: z.boolean().optional(),
disable_virtual_api_keys_ui: z.boolean().optional(),
enable_acme_cert_sync: z.boolean().optional().default(true),
disable_private_http_placeholder: z
.boolean()
+2 -1
View File
@@ -104,7 +104,8 @@ const processMessage = async (
const handler = messageHandlers[message.type];
if (!handler) {
throw new Error(`Unsupported message type: ${message.type}`);
logger.debug(`No handler found for message type: ${message.type}`);
return;
}
const response = await handler({
+4 -1
View File
@@ -353,7 +353,10 @@ const setupConnection = async (
const handler = messageHandlers[message.type];
if (!handler) {
throw new Error(`Unsupported message type: ${message.type}`);
logger.debug(
`No handler found for message type: ${message.type}`
);
return;
}
const response = await handler({
+6 -1
View File
@@ -76,6 +76,11 @@ export default async function KeysPage(props: KeysPageProps) {
redirect("/");
}
const env = pullEnv();
if (env.flags.disableVirtualApiKeysUi) {
redirect(`/${orgId}`);
}
let keysData: ListMyVirtualApiKeysResponse | null = null;
try {
const res = await internal.get<
@@ -90,7 +95,6 @@ export default async function KeysPage(props: KeysPageProps) {
redirect(`/${orgId}`);
}
const env = pullEnv();
const primaryOrg = orgs.find((o) => o.orgId === orgId)?.isPrimaryOrg;
const isAdminOrOwner = Boolean(overview?.isAdmin || overview?.isOwner);
@@ -106,6 +110,7 @@ export default async function KeysPage(props: KeysPageProps) {
showSidebar={false}
launcherMode
showViewAsAdmin={isAdminOrOwner}
env={env}
>
<UserVirtualApiKeys orgId={orgId} initialData={keysData} />
</Layout>
+1
View File
@@ -83,6 +83,7 @@ export default async function OrgPage(props: OrgPageProps) {
showSidebar={false}
launcherMode
showViewAsAdmin={isAdminOrOwner}
env={env}
>
{overview && launcherData ? (
<ResourceLauncher
@@ -117,6 +117,7 @@ export default function SecurityPage() {
}
function LogRetentionSectionForm({ org }: SectionFormProps) {
const { updateOrg } = useOrgContext();
const form = useForm({
resolver: zodResolver(
SecurityFormSchema.pick({
@@ -173,6 +174,11 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
// Update organization
await api.post(`/org/${org.orgId}`, reqData);
// Update the org context immediately so the dropdowns reflect
// the saved values without waiting on a re-fetch that could
// race a lagging read replica
updateOrg(reqData);
toast({
title: t("orgUpdated"),
description: t("orgUpdatedDescription")
@@ -199,7 +205,10 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
<SettingsSectionForm>
<Form {...form}>
<form
action={formAction}
onSubmit={(e) => {
e.preventDefault();
formAction();
}}
className="grid gap-4"
id="org-log-retention-settings-form"
>
@@ -827,6 +836,7 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
function SecuritySettingsSectionForm({ org }: SectionFormProps) {
const router = useRouter();
const { updateOrg } = useOrgContext();
const form = useForm({
resolver: zodResolver(
SecurityFormSchema.pick({
@@ -899,6 +909,11 @@ function SecuritySettingsSectionForm({ org }: SectionFormProps) {
// Update organization
await api.post(`/org/${org.orgId}`, reqData);
// Update the org context immediately so the dropdowns reflect
// the saved values without waiting on a re-fetch that could
// race a lagging read replica
updateOrg(reqData);
toast({
title: t("orgUpdated"),
description: t("orgUpdatedDescription")
@@ -942,7 +957,10 @@ function SecuritySettingsSectionForm({ org }: SectionFormProps) {
<SettingsSectionForm>
<Form {...form}>
<form
action={formAction}
onSubmit={(e) => {
e.preventDefault();
formAction();
}}
ref={formRef}
id="security-settings-section-form"
className="space-y-4"
@@ -30,9 +30,15 @@ import { normalizePostAuthPath } from "@server/lib/normalizePostAuthPath";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Resource Access"
};
export async function generateMetadata(): Promise<Metadata> {
const env = pullEnv();
const title =
env.branding.resourceAuthPage?.titleText ||
env.branding.appName ||
"Resource Access";
return { title };
}
export const dynamic = "force-dynamic";
+10 -6
View File
@@ -53,17 +53,21 @@ export type OrgNavSectionsOptions = {
};
// Merged from 'user-management-and-resources' branch
export const orgLangingNavItems: SidebarNavItem[] = [
export const orgLangingNavItems = (env?: Env): SidebarNavItem[] => [
{
title: "sidebarAccount",
href: "/{orgId}",
icon: <LayoutGrid className="size-4 flex-none" />
},
{
title: "sidebarMyApiKeys",
href: "/{orgId}/keys",
icon: <KeyRound className="size-4 flex-none" />
}
...(!env?.flags.disableVirtualApiKeysUi
? [
{
title: "sidebarMyApiKeys",
href: "/{orgId}/keys",
icon: <KeyRound className="size-4 flex-none" />
}
]
: [])
];
export const orgNavSections = (
+5 -2
View File
@@ -1,6 +1,7 @@
import React from "react";
import { cn } from "@app/lib/cn";
import { ListUserOrgsResponse } from "@server/routers/org";
import { Env } from "@app/lib/types/env";
import {
orgLangingNavItems,
type CommandBarNavSection,
@@ -25,6 +26,7 @@ interface LayoutProps {
defaultSidebarCollapsed?: boolean;
launcherMode?: boolean;
showViewAsAdmin?: boolean;
env?: Env;
}
export async function Layout({
@@ -38,7 +40,8 @@ export async function Layout({
showTopBar = true,
defaultSidebarCollapsed = false,
launcherMode = false,
showViewAsAdmin = false
showViewAsAdmin = false,
env
}: LayoutProps) {
const allCookies = await cookies();
const sidebarStateCookie = allCookies.get("pangolin-sidebar-state")?.value;
@@ -49,7 +52,7 @@ export async function Layout({
(sidebarStateCookie !== "expanded" && defaultSidebarCollapsed);
const launcherNavItems: SidebarNavItem[] = launcherMode
? orgLangingNavItems
? orgLangingNavItems(env)
: [];
return (
+4
View File
@@ -70,6 +70,10 @@ export function pullEnv(): Env {
: false,
disableEnterpriseFeatures:
process.env.DISABLE_ENTERPRISE_FEATURES === "true"
? true
: false,
disableVirtualApiKeysUi:
process.env.FLAGS_DISABLE_VIRTUAL_API_KEYS_UI === "true"
? true
: false
},
+1
View File
@@ -36,6 +36,7 @@ export type Env = {
usePangolinDns: boolean;
disableProductHelpBanners: boolean;
disableEnterpriseFeatures: boolean;
disableVirtualApiKeysUi: boolean;
};
branding: {
appName?: string;