Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd96c7311d |
@@ -1,5 +1,5 @@
|
|||||||
# FROM node:24.18.1-slim AS base
|
# FROM node:24.18.1-slim AS base
|
||||||
FROM public.ecr.aws/docker/library/node:24.18.1-slim AS base
|
FROM public.ecr.aws/docker/library/node:26.8.1-slim AS base
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ FROM base AS builder
|
|||||||
RUN npm ci --omit=dev
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
# FROM node:24.18.1-slim AS runner
|
# FROM node:24.18.1-slim AS runner
|
||||||
FROM public.ecr.aws/docker/library/node:24.18.1-slim AS runner
|
FROM public.ecr.aws/docker/library/node:26.8.1-slim AS runner
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.18.1-alpine
|
FROM node:26.8.1-alpine
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { encrypt } from "@server/lib/crypto";
|
|||||||
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||||
import { generateCA } from "@server/lib/sshCA";
|
import { generateCA } from "@server/lib/sshCA";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import * as yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
type GenerateOrgCaKeysArgs = {
|
type GenerateOrgCaKeysArgs = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { encrypt, decrypt } from "@server/lib/crypto";
|
|||||||
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import * as yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
type RotateServerSecretArgs = {
|
type RotateServerSecretArgs = {
|
||||||
"old-secret": string;
|
"old-secret": string;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
@@ -112,11 +112,6 @@ export class Config {
|
|||||||
? "true"
|
? "true"
|
||||||
: "false";
|
: "false";
|
||||||
|
|
||||||
process.env.FLAGS_DISABLE_VIRTUAL_API_KEYS_UI = parsedConfig.flags
|
|
||||||
?.disable_virtual_api_keys_ui
|
|
||||||
? "true"
|
|
||||||
: "false";
|
|
||||||
|
|
||||||
this.rawConfig = parsedConfig;
|
this.rawConfig = parsedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -442,7 +442,6 @@ export const configSchema = z
|
|||||||
disable_config_managed_domains: z.boolean().optional(),
|
disable_config_managed_domains: z.boolean().optional(),
|
||||||
disable_product_help_banners: z.boolean().optional(),
|
disable_product_help_banners: z.boolean().optional(),
|
||||||
disable_enterprise_features: 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),
|
enable_acme_cert_sync: z.boolean().optional().default(true),
|
||||||
disable_private_http_placeholder: z
|
disable_private_http_placeholder: z
|
||||||
.boolean()
|
.boolean()
|
||||||
|
|||||||
@@ -104,8 +104,7 @@ const processMessage = async (
|
|||||||
|
|
||||||
const handler = messageHandlers[message.type];
|
const handler = messageHandlers[message.type];
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
logger.debug(`No handler found for message type: ${message.type}`);
|
throw new Error(`Unsupported message type: ${message.type}`);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await handler({
|
const response = await handler({
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import config from "@server/lib/config";
|
|
||||||
|
|
||||||
// Mirrors the optional fields on the olm client's TunnelConfig - any field
|
|
||||||
// present here overrides the value the olm client is otherwise locally
|
|
||||||
// configured with; an absent field leaves the client's own config alone.
|
|
||||||
export type OlmDnsConfig = {
|
|
||||||
upstreamDns?: string[];
|
|
||||||
overrideDns?: boolean;
|
|
||||||
tunnelDns?: boolean;
|
|
||||||
matchDomains?: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function buildOlmDnsConfig(): OlmDnsConfig | undefined {
|
|
||||||
return {
|
|
||||||
upstreamDns: undefined,
|
|
||||||
overrideDns: undefined,
|
|
||||||
tunnelDns: undefined,
|
|
||||||
matchDomains: undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,6 @@ import { encodeHexLowerCase } from "@oslojs/encoding";
|
|||||||
import { sha256 } from "@oslojs/crypto/sha2";
|
import { sha256 } from "@oslojs/crypto/sha2";
|
||||||
import { getUserDeviceName } from "@server/db/names";
|
import { getUserDeviceName } from "@server/db/names";
|
||||||
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
||||||
import { buildOlmDnsConfig } from "./dnsConfig";
|
|
||||||
import { OlmErrorCodes, sendOlmError } from "./error";
|
import { OlmErrorCodes, sendOlmError } from "./error";
|
||||||
import { handleFingerprintInsertion } from "./fingerprintingUtils";
|
import { handleFingerprintInsertion } from "./fingerprintingUtils";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
@@ -513,7 +512,6 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
|||||||
tunnelIP: `${clientSubnet.split("/")[0]}/${exitNode.address.split("/")[1]}` // we need to use the exit node's subnet mask here because the client will be using the exit node's subnet mask for its routing table so we can address it
|
tunnelIP: `${clientSubnet.split("/")[0]}/${exitNode.address.split("/")[1]}` // we need to use the exit node's subnet mask here because the client will be using the exit node's subnet mask for its routing table so we can address it
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
dnsConfig: buildOlmDnsConfig(),
|
|
||||||
chainId: chainId
|
chainId: chainId
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -353,10 +353,7 @@ const setupConnection = async (
|
|||||||
|
|
||||||
const handler = messageHandlers[message.type];
|
const handler = messageHandlers[message.type];
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
logger.debug(
|
throw new Error(`Unsupported message type: ${message.type}`);
|
||||||
`No handler found for message type: ${message.type}`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await handler({
|
const response = await handler({
|
||||||
|
|||||||
@@ -76,11 +76,6 @@ export default async function KeysPage(props: KeysPageProps) {
|
|||||||
redirect("/");
|
redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
const env = pullEnv();
|
|
||||||
if (env.flags.disableVirtualApiKeysUi) {
|
|
||||||
redirect(`/${orgId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let keysData: ListMyVirtualApiKeysResponse | null = null;
|
let keysData: ListMyVirtualApiKeysResponse | null = null;
|
||||||
try {
|
try {
|
||||||
const res = await internal.get<
|
const res = await internal.get<
|
||||||
@@ -95,6 +90,7 @@ export default async function KeysPage(props: KeysPageProps) {
|
|||||||
redirect(`/${orgId}`);
|
redirect(`/${orgId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const env = pullEnv();
|
||||||
const primaryOrg = orgs.find((o) => o.orgId === orgId)?.isPrimaryOrg;
|
const primaryOrg = orgs.find((o) => o.orgId === orgId)?.isPrimaryOrg;
|
||||||
const isAdminOrOwner = Boolean(overview?.isAdmin || overview?.isOwner);
|
const isAdminOrOwner = Boolean(overview?.isAdmin || overview?.isOwner);
|
||||||
|
|
||||||
@@ -110,7 +106,6 @@ export default async function KeysPage(props: KeysPageProps) {
|
|||||||
showSidebar={false}
|
showSidebar={false}
|
||||||
launcherMode
|
launcherMode
|
||||||
showViewAsAdmin={isAdminOrOwner}
|
showViewAsAdmin={isAdminOrOwner}
|
||||||
env={env}
|
|
||||||
>
|
>
|
||||||
<UserVirtualApiKeys orgId={orgId} initialData={keysData} />
|
<UserVirtualApiKeys orgId={orgId} initialData={keysData} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ export default async function OrgPage(props: OrgPageProps) {
|
|||||||
showSidebar={false}
|
showSidebar={false}
|
||||||
launcherMode
|
launcherMode
|
||||||
showViewAsAdmin={isAdminOrOwner}
|
showViewAsAdmin={isAdminOrOwner}
|
||||||
env={env}
|
|
||||||
>
|
>
|
||||||
{overview && launcherData ? (
|
{overview && launcherData ? (
|
||||||
<ResourceLauncher
|
<ResourceLauncher
|
||||||
|
|||||||
@@ -13,12 +13,7 @@ import { StrategyOption, StrategySelect } from "@app/components/StrategySelect";
|
|||||||
import HeaderTitle from "@app/components/SettingsSectionTitle";
|
import HeaderTitle from "@app/components/SettingsSectionTitle";
|
||||||
import { Button } from "@app/components/ui/button";
|
import { Button } from "@app/components/ui/button";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import {
|
import { useActionState, useRef, useState } from "react";
|
||||||
useActionState,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
startTransition
|
|
||||||
} from "react";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -523,12 +518,9 @@ export default function Page() {
|
|||||||
<SettingsSectionForm>
|
<SettingsSectionForm>
|
||||||
<Form {...internalForm}>
|
<Form {...internalForm}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={
|
||||||
e.preventDefault();
|
submitInternalAction
|
||||||
startTransition(() => {
|
}
|
||||||
submitInternalAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
id="create-user-form"
|
id="create-user-form"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,12 +3,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
|||||||
import { Button } from "@app/components/ui/button";
|
import { Button } from "@app/components/ui/button";
|
||||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||||
import { toast } from "@app/hooks/useToast";
|
import { toast } from "@app/hooks/useToast";
|
||||||
import {
|
import { useState, useTransition, useActionState } from "react";
|
||||||
useState,
|
|
||||||
useTransition,
|
|
||||||
useActionState,
|
|
||||||
startTransition
|
|
||||||
} from "react";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -248,12 +243,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
|||||||
<SettingsSectionForm>
|
<SettingsSectionForm>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
className="grid gap-4"
|
className="grid gap-4"
|
||||||
id="org-general-settings-form"
|
id="org-general-settings-form"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,13 +3,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
|||||||
import { Button } from "@app/components/ui/button";
|
import { Button } from "@app/components/ui/button";
|
||||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||||
import { toast } from "@app/hooks/useToast";
|
import { toast } from "@app/hooks/useToast";
|
||||||
import {
|
import { useState, useRef, useActionState, type ComponentRef } from "react";
|
||||||
useState,
|
|
||||||
useRef,
|
|
||||||
useActionState,
|
|
||||||
startTransition,
|
|
||||||
type ComponentRef
|
|
||||||
} from "react";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -123,7 +117,6 @@ export default function SecurityPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LogRetentionSectionForm({ org }: SectionFormProps) {
|
function LogRetentionSectionForm({ org }: SectionFormProps) {
|
||||||
const { updateOrg } = useOrgContext();
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(
|
resolver: zodResolver(
|
||||||
SecurityFormSchema.pick({
|
SecurityFormSchema.pick({
|
||||||
@@ -180,11 +173,6 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
|
|||||||
// Update organization
|
// Update organization
|
||||||
await api.post(`/org/${org.orgId}`, reqData);
|
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({
|
toast({
|
||||||
title: t("orgUpdated"),
|
title: t("orgUpdated"),
|
||||||
description: t("orgUpdatedDescription")
|
description: t("orgUpdatedDescription")
|
||||||
@@ -211,12 +199,7 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
|
|||||||
<SettingsSectionForm>
|
<SettingsSectionForm>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
className="grid gap-4"
|
className="grid gap-4"
|
||||||
id="org-log-retention-settings-form"
|
id="org-log-retention-settings-form"
|
||||||
>
|
>
|
||||||
@@ -844,7 +827,6 @@ function LogRetentionSectionForm({ org }: SectionFormProps) {
|
|||||||
|
|
||||||
function SecuritySettingsSectionForm({ org }: SectionFormProps) {
|
function SecuritySettingsSectionForm({ org }: SectionFormProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { updateOrg } = useOrgContext();
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(
|
resolver: zodResolver(
|
||||||
SecurityFormSchema.pick({
|
SecurityFormSchema.pick({
|
||||||
@@ -917,11 +899,6 @@ function SecuritySettingsSectionForm({ org }: SectionFormProps) {
|
|||||||
// Update organization
|
// Update organization
|
||||||
await api.post(`/org/${org.orgId}`, reqData);
|
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({
|
toast({
|
||||||
title: t("orgUpdated"),
|
title: t("orgUpdated"),
|
||||||
description: t("orgUpdatedDescription")
|
description: t("orgUpdatedDescription")
|
||||||
@@ -965,12 +942,7 @@ function SecuritySettingsSectionForm({ org }: SectionFormProps) {
|
|||||||
<SettingsSectionForm>
|
<SettingsSectionForm>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
ref={formRef}
|
ref={formRef}
|
||||||
id="security-settings-section-form"
|
id="security-settings-section-form"
|
||||||
className="space-y-4"
|
className="space-y-4"
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useActionState, useEffect, useMemo, startTransition } from "react";
|
import { useActionState, useEffect, useMemo } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@@ -232,12 +232,7 @@ export default function PrivateResourceInferencePage() {
|
|||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="private-resource-providers-form"
|
id="private-resource-providers-form"
|
||||||
>
|
>
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ExternalLink } from "lucide-react";
|
import { ExternalLink } from "lucide-react";
|
||||||
import { useActionState, useMemo, startTransition } from "react";
|
import { useActionState, useMemo } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useSaveSiteResource } from "@app/hooks/useSaveSiteResource";
|
import { useSaveSiteResource } from "@app/hooks/useSaveSiteResource";
|
||||||
@@ -97,12 +97,7 @@ export default function PrivateResourceGeneralPage() {
|
|||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="private-resource-general-form"
|
id="private-resource-general-form"
|
||||||
>
|
>
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
|
|||||||
@@ -41,13 +41,7 @@ import { AxiosResponse } from "axios";
|
|||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { toASCII, toUnicode } from "punycode";
|
import { toASCII, toUnicode } from "punycode";
|
||||||
import {
|
import { useActionState, useEffect, useMemo, useState } from "react";
|
||||||
useActionState,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
startTransition
|
|
||||||
} from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
@@ -288,12 +282,7 @@ export default function GeneralForm() {
|
|||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="general-settings-form"
|
id="general-settings-form"
|
||||||
>
|
>
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import {
|
|||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { useActionState, useState, startTransition } from "react";
|
import { useActionState, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@@ -209,15 +209,7 @@ function ProxyResourceHttpForm({
|
|||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form action={formAction} id="http-settings-form">
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="http-settings-form"
|
|
||||||
>
|
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
{!env.flags.usePangolinDns && (
|
{!env.flags.usePangolinDns && (
|
||||||
<SettingsFormCell span="full">
|
<SettingsFormCell span="full">
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { AxiosResponse } from "axios";
|
|||||||
import { AlertCircle } from "lucide-react";
|
import { AlertCircle } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
import { useActionState, useEffect, startTransition } from "react";
|
import { useActionState, useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
@@ -203,12 +203,7 @@ export default function ResourceMaintenancePage() {
|
|||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...maintenanceForm}>
|
<Form {...maintenanceForm}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={maintenanceFormAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
maintenanceFormAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="maintenance-settings-form"
|
id="maintenance-settings-form"
|
||||||
>
|
>
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ import { useRouter } from "next/navigation";
|
|||||||
import {
|
import {
|
||||||
use,
|
use,
|
||||||
useActionState,
|
useActionState,
|
||||||
useMemo,
|
useMemo
|
||||||
startTransition
|
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -207,12 +206,7 @@ function ProxyResourceProtocolForm({
|
|||||||
<SettingsSectionForm variant="half">
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...proxySettingsForm}>
|
<Form {...proxySettingsForm}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
action={formAction}
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
id="proxy-protocol-settings-form"
|
id="proxy-protocol-settings-form"
|
||||||
>
|
>
|
||||||
<SettingsFormGrid>
|
<SettingsFormGrid>
|
||||||
|
|||||||
@@ -30,15 +30,9 @@ import { normalizePostAuthPath } from "@server/lib/normalizePostAuthPath";
|
|||||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export const metadata: Metadata = {
|
||||||
const env = pullEnv();
|
title: "Resource Access"
|
||||||
const title =
|
};
|
||||||
env.branding.resourceAuthPage?.titleText ||
|
|
||||||
env.branding.appName ||
|
|
||||||
"Resource Access";
|
|
||||||
|
|
||||||
return { title };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -53,21 +53,17 @@ export type OrgNavSectionsOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Merged from 'user-management-and-resources' branch
|
// Merged from 'user-management-and-resources' branch
|
||||||
export const orgLangingNavItems = (env?: Env): SidebarNavItem[] => [
|
export const orgLangingNavItems: SidebarNavItem[] = [
|
||||||
{
|
{
|
||||||
title: "sidebarAccount",
|
title: "sidebarAccount",
|
||||||
href: "/{orgId}",
|
href: "/{orgId}",
|
||||||
icon: <LayoutGrid className="size-4 flex-none" />
|
icon: <LayoutGrid className="size-4 flex-none" />
|
||||||
},
|
},
|
||||||
...(!env?.flags.disableVirtualApiKeysUi
|
{
|
||||||
? [
|
title: "sidebarMyApiKeys",
|
||||||
{
|
href: "/{orgId}/keys",
|
||||||
title: "sidebarMyApiKeys",
|
icon: <KeyRound className="size-4 flex-none" />
|
||||||
href: "/{orgId}/keys",
|
}
|
||||||
icon: <KeyRound className="size-4 flex-none" />
|
|
||||||
}
|
|
||||||
]
|
|
||||||
: [])
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const orgNavSections = (
|
export const orgNavSections = (
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import { ListUserOrgsResponse } from "@server/routers/org";
|
import { ListUserOrgsResponse } from "@server/routers/org";
|
||||||
import { Env } from "@app/lib/types/env";
|
|
||||||
import {
|
import {
|
||||||
orgLangingNavItems,
|
orgLangingNavItems,
|
||||||
type CommandBarNavSection,
|
type CommandBarNavSection,
|
||||||
@@ -26,7 +25,6 @@ interface LayoutProps {
|
|||||||
defaultSidebarCollapsed?: boolean;
|
defaultSidebarCollapsed?: boolean;
|
||||||
launcherMode?: boolean;
|
launcherMode?: boolean;
|
||||||
showViewAsAdmin?: boolean;
|
showViewAsAdmin?: boolean;
|
||||||
env?: Env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function Layout({
|
export async function Layout({
|
||||||
@@ -40,8 +38,7 @@ export async function Layout({
|
|||||||
showTopBar = true,
|
showTopBar = true,
|
||||||
defaultSidebarCollapsed = false,
|
defaultSidebarCollapsed = false,
|
||||||
launcherMode = false,
|
launcherMode = false,
|
||||||
showViewAsAdmin = false,
|
showViewAsAdmin = false
|
||||||
env
|
|
||||||
}: LayoutProps) {
|
}: LayoutProps) {
|
||||||
const allCookies = await cookies();
|
const allCookies = await cookies();
|
||||||
const sidebarStateCookie = allCookies.get("pangolin-sidebar-state")?.value;
|
const sidebarStateCookie = allCookies.get("pangolin-sidebar-state")?.value;
|
||||||
@@ -52,7 +49,7 @@ export async function Layout({
|
|||||||
(sidebarStateCookie !== "expanded" && defaultSidebarCollapsed);
|
(sidebarStateCookie !== "expanded" && defaultSidebarCollapsed);
|
||||||
|
|
||||||
const launcherNavItems: SidebarNavItem[] = launcherMode
|
const launcherNavItems: SidebarNavItem[] = launcherMode
|
||||||
? orgLangingNavItems(env)
|
? orgLangingNavItems
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ export function OrgLabelForm({
|
|||||||
<form
|
<form
|
||||||
id="org-label-form"
|
id="org-label-form"
|
||||||
className="flex flex-col gap-4 px-0.5"
|
className="flex flex-col gap-4 px-0.5"
|
||||||
onSubmit={async (e) => {
|
action={async () => {
|
||||||
e.preventDefault();
|
|
||||||
if (await form.trigger()) {
|
if (await form.trigger()) {
|
||||||
onSubmit(form.getValues());
|
onSubmit(form.getValues());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,15 +211,7 @@ export default function AlertRuleGraphEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form id={FORM_ID} action={formAction}>
|
||||||
id={FORM_ID}
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
startTransition(() => {
|
|
||||||
formAction();
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SettingsContainer>
|
<SettingsContainer>
|
||||||
<PaidFeaturesAlert tiers={tierMatrix.alertingRules} />
|
<PaidFeaturesAlert tiers={tierMatrix.alertingRules} />
|
||||||
<div className="flex flex-col lg:flex-row gap-6 lg:gap-8 items-start">
|
<div className="flex flex-col lg:flex-row gap-6 lg:gap-8 items-start">
|
||||||
|
|||||||
@@ -70,10 +70,6 @@ export function pullEnv(): Env {
|
|||||||
: false,
|
: false,
|
||||||
disableEnterpriseFeatures:
|
disableEnterpriseFeatures:
|
||||||
process.env.DISABLE_ENTERPRISE_FEATURES === "true"
|
process.env.DISABLE_ENTERPRISE_FEATURES === "true"
|
||||||
? true
|
|
||||||
: false,
|
|
||||||
disableVirtualApiKeysUi:
|
|
||||||
process.env.FLAGS_DISABLE_VIRTUAL_API_KEYS_UI === "true"
|
|
||||||
? true
|
? true
|
||||||
: false
|
: false
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export type Env = {
|
|||||||
usePangolinDns: boolean;
|
usePangolinDns: boolean;
|
||||||
disableProductHelpBanners: boolean;
|
disableProductHelpBanners: boolean;
|
||||||
disableEnterpriseFeatures: boolean;
|
disableEnterpriseFeatures: boolean;
|
||||||
disableVirtualApiKeysUi: boolean;
|
|
||||||
};
|
};
|
||||||
branding: {
|
branding: {
|
||||||
appName?: string;
|
appName?: string;
|
||||||
|
|||||||