Merge pull request #3245 from fosrl/dev

Bugfixes
This commit is contained in:
Owen Schwartz
2026-06-11 16:17:41 -07:00
committed by GitHub
10 changed files with 214 additions and 224 deletions
+1
View File
@@ -35,3 +35,4 @@ tsconfig.json
Dockerfile* Dockerfile*
drizzle.config.ts drizzle.config.ts
allowedDevOrigins.json allowedDevOrigins.json
scratch/
+1 -1
View File
@@ -984,7 +984,7 @@
"sharedPolicy": "Shared Policy", "sharedPolicy": "Shared Policy",
"sharedPolicyNoneDescription": "This resource has its own policy.", "sharedPolicyNoneDescription": "This resource has its own policy.",
"resourceSharedPolicyOwnDescription": "This resource has its own authentication and access rules controls.", "resourceSharedPolicyOwnDescription": "This resource has its own authentication and access rules controls.",
"resourceSharedPolicyInheritedDescription": "This resource inherits authentication and access rules controls from <policyLink>{policyName}</policyLink>.", "resourceSharedPolicyInheritedDescription": "This resource inherits from <policyLink>{policyName}</policyLink>.",
"resourceSharedPolicyAuthenticationNotice": "This resource is using a shared policy. Some authentication settings can be edited on this resource to add to the policy. To change the underlying policy, you must edit to <policyLink>{policyName}</policyLink>.", "resourceSharedPolicyAuthenticationNotice": "This resource is using a shared policy. Some authentication settings can be edited on this resource to add to the policy. To change the underlying policy, you must edit to <policyLink>{policyName}</policyLink>.",
"resourceSharedPolicyRulesNotice": "This resource is using a shared policy. Some access rules can be edited on this resource. To change the underlying policy, you must edit <policyLink>{policyName}</policyLink>.", "resourceSharedPolicyRulesNotice": "This resource is using a shared policy. Some access rules can be edited on this resource. To change the underlying policy, you must edit <policyLink>{policyName}</policyLink>.",
"resourceUsersRoles": "Access Controls", "resourceUsersRoles": "Access Controls",
+4 -4
View File
@@ -228,7 +228,7 @@ export default async function migration() {
).run(); ).run();
db.prepare( db.prepare(
` `
UPDATE 'siteResources' SET 'destination2' = 'destination'; UPDATE 'siteResources' SET "destination2" = "destination";
` `
).run(); ).run();
db.prepare( db.prepare(
@@ -349,9 +349,9 @@ export default async function migration() {
db.prepare( db.prepare(
` `
UPDATE 'targets' UPDATE 'targets'
SET 'mode' = ( SET "mode" = (
SELECT 'mode' FROM 'resources' SELECT "mode" FROM 'resources'
WHERE 'resources'.'resourceId' = 'targets'.'resourceId' WHERE "resources"."resourceId" = "targets"."resourceId"
); );
` `
).run(); ).run();
+10 -2
View File
@@ -43,6 +43,7 @@ import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix"; import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
import { ExternalLink } from "lucide-react"; import { ExternalLink } from "lucide-react";
import { env } from "process";
// Schema for general organization settings // Schema for general organization settings
const GeneralFormSchema = z.object({ const GeneralFormSchema = z.object({
@@ -165,6 +166,7 @@ function DeleteForm({ org }: SectionFormProps) {
function GeneralSectionForm({ org }: SectionFormProps) { function GeneralSectionForm({ org }: SectionFormProps) {
const { updateOrg } = useOrgContext(); const { updateOrg } = useOrgContext();
const { env } = useEnvContext();
const form = useForm({ const form = useForm({
resolver: zodResolver( resolver: zodResolver(
GeneralFormSchema.pick({ GeneralFormSchema.pick({
@@ -265,6 +267,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
<PaidFeaturesAlert <PaidFeaturesAlert
tiers={tierMatrix.newtAutoUpdate} tiers={tierMatrix.newtAutoUpdate}
/> />
{!env.flags.disableEnterpriseFeatures && (
<FormField <FormField
control={form.control} control={form.control}
name="settingsEnableGlobalNewtAutoUpdate" name="settingsEnableGlobalNewtAutoUpdate"
@@ -275,8 +278,12 @@ function GeneralSectionForm({ org }: SectionFormProps) {
id="settings-enable-global-newt-auto-update" id="settings-enable-global-newt-auto-update"
label={t("newtAutoUpdate")} label={t("newtAutoUpdate")}
checked={field.value} checked={field.value}
onCheckedChange={field.onChange} onCheckedChange={
disabled={!hasAutoUpdateFeature} field.onChange
}
disabled={
!hasAutoUpdateFeature
}
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
@@ -295,6 +302,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
</FormItem> </FormItem>
)} )}
/> />
)}
</form> </form>
</Form> </Form>
</SettingsSectionForm> </SettingsSectionForm>
@@ -455,7 +455,7 @@ export default function GeneralForm() {
)} )}
{ !["tcp", "udp"].includes( { !["tcp", "udp"].includes(
resource.mode resource.mode
) && ( ) && !env.flags.disableEnterpriseFeatures && (
<> <>
<SettingsFormCell span="full"> <SettingsFormCell span="full">
<SettingsSubsectionHeader> <SettingsSubsectionHeader>
@@ -169,18 +169,25 @@ export default function ResourceMaintenancePage() {
{ {
id: "automatic", id: "automatic",
title: `${t("automatic")} (${t("recommended")})`, title: `${t("automatic")} (${t("recommended")})`,
description: t("automaticModeDescription"), description: t("automaticModeDescription")
disabled: isMaintenanceDisabled
}, },
{ {
id: "forced", id: "forced",
title: t("forced"), title: t("forced"),
description: t("forcedModeDescription"), description: t("forcedModeDescription")
disabled: isMaintenanceDisabled
} }
]; ];
return ( return (
<>
<PaidFeaturesAlert tiers={tierMatrix.maintencePage} />
<div
className={
isMaintenanceDisabled
? "pointer-events-none opacity-50"
: undefined
}
>
<SettingsContainer> <SettingsContainer>
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
@@ -193,7 +200,6 @@ export default function ResourceMaintenancePage() {
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
<PaidFeaturesAlert tiers={tierMatrix.maintencePage} />
<SettingsSectionForm variant="half"> <SettingsSectionForm variant="half">
<Form {...maintenanceForm}> <Form {...maintenanceForm}>
<form <form
@@ -205,12 +211,7 @@ export default function ResourceMaintenancePage() {
<FormField <FormField
control={maintenanceForm.control} control={maintenanceForm.control}
name="maintenanceModeEnabled" name="maintenanceModeEnabled"
render={({ field }) => { render={({ field }) => (
const isDisabled = !isPaidUser(
tierMatrix.maintencePage
);
return (
<FormItem> <FormItem>
<FormControl> <FormControl>
<SwitchInput <SwitchInput
@@ -224,27 +225,19 @@ export default function ResourceMaintenancePage() {
description={t( description={t(
"enableMaintenanceModeDescription" "enableMaintenanceModeDescription"
)} )}
disabled={
isDisabled
}
onCheckedChange={( onCheckedChange={(
val val
) => { ) => {
if (
!isDisabled
) {
maintenanceForm.setValue( maintenanceForm.setValue(
"maintenanceModeEnabled", "maintenanceModeEnabled",
val val
); );
}
}} }}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
); )}
}}
/> />
</SettingsFormCell> </SettingsFormCell>
@@ -329,11 +322,6 @@ export default function ResourceMaintenancePage() {
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
disabled={
!isPaidUser(
tierMatrix.maintencePage
)
}
placeholder="We'll be back soon!" placeholder="We'll be back soon!"
/> />
</FormControl> </FormControl>
@@ -365,11 +353,6 @@ export default function ResourceMaintenancePage() {
<Textarea <Textarea
{...field} {...field}
rows={4} rows={4}
disabled={
!isPaidUser(
tierMatrix.maintencePage
)
}
placeholder={t( placeholder={t(
"maintenancePageMessagePlaceholder" "maintenancePageMessagePlaceholder"
)} )}
@@ -402,11 +385,6 @@ export default function ResourceMaintenancePage() {
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
disabled={
!isPaidUser(
tierMatrix.maintencePage
)
}
placeholder={t( placeholder={t(
"maintenanceTime" "maintenanceTime"
)} )}
@@ -434,10 +412,7 @@ export default function ResourceMaintenancePage() {
<Button <Button
type="submit" type="submit"
loading={maintenanceSaveLoading} loading={maintenanceSaveLoading}
disabled={ disabled={maintenanceSaveLoading}
maintenanceSaveLoading ||
!isPaidUser(tierMatrix.maintencePage)
}
form="maintenance-settings-form" form="maintenance-settings-form"
> >
{t("saveSettings")} {t("saveSettings")}
@@ -445,5 +420,7 @@ export default function ResourceMaintenancePage() {
</SettingsSectionFooter> </SettingsSectionFooter>
</SettingsSection> </SettingsSection>
</SettingsContainer> </SettingsContainer>
</div>
</>
); );
} }
@@ -253,7 +253,9 @@ export default function GeneralPage() {
<PaidFeaturesAlert <PaidFeaturesAlert
tiers={tierMatrix.newtAutoUpdate} tiers={tierMatrix.newtAutoUpdate}
/> />
{site && site.type === "newt" && ( {site &&
site.type === "newt" &&
!env.flags.disableEnterpriseFeatures && (
<FormField <FormField
control={form.control} control={form.control}
name="autoUpdateEnabled" name="autoUpdateEnabled"
+1 -10
View File
@@ -23,7 +23,7 @@ import {
} from "@app/components/ui/form"; } from "@app/components/ui/form";
import HeaderTitle from "@app/components/SettingsSectionTitle"; import HeaderTitle from "@app/components/SettingsSectionTitle";
import { z } from "zod"; import { z } from "zod";
import { createElement, useEffect, useState } from "react"; import { useEffect, useState } 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 { Input } from "@app/components/ui/input"; import { Input } from "@app/components/ui/input";
@@ -37,15 +37,6 @@ import {
InfoSections, InfoSections,
InfoSectionTitle InfoSectionTitle
} from "@app/components/InfoSection"; } from "@app/components/InfoSection";
import {
FaApple,
FaCubes,
FaDocker,
FaFreebsd,
FaWindows
} from "react-icons/fa";
import { SiNixos, SiKubernetes } from "react-icons/si";
import { Checkbox, CheckboxWithLabel } from "@app/components/ui/checkbox";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { generateKeypair } from "../[niceId]/wireguardConfig"; import { generateKeypair } from "../[niceId]/wireguardConfig";
import { createApiClient, formatAxiosError } from "@app/lib/api"; import { createApiClient, formatAxiosError } from "@app/lib/api";
+4 -3
View File
@@ -156,10 +156,11 @@ export const orgNavSections = (
] ]
: []), : []),
// PaidFeaturesAlert // PaidFeaturesAlert
...((build === "oss" && !env?.flags.disableEnterpriseFeatures) || ...(!env?.flags.disableEnterpriseFeatures &&
build === "saas" || (build === "saas" ||
env?.app.identityProviderMode === "org" || env?.app.identityProviderMode === "org" ||
(env?.app.identityProviderMode === undefined && build !== "oss") (env?.app.identityProviderMode === undefined &&
build !== "oss"))
? [ ? [
{ {
title: "sidebarIdentityProviders", title: "sidebarIdentityProviders",
+14 -4
View File
@@ -20,6 +20,7 @@ import {
} from "react-icons/fa"; } from "react-icons/fa";
import { ExternalLink } from "lucide-react"; import { ExternalLink } from "lucide-react";
import { SiKubernetes, SiNixos } from "react-icons/si"; import { SiKubernetes, SiNixos } from "react-icons/si";
import { useEnvContext } from "@app/hooks/useEnvContext";
export type CommandItem = string | { title: string; command: string }; export type CommandItem = string | { title: string; command: string };
@@ -50,9 +51,12 @@ export function NewtSiteInstallCommands({
version = "latest" version = "latest"
}: NewtSiteInstallCommandsProps) { }: NewtSiteInstallCommandsProps) {
const t = useTranslations(); const t = useTranslations();
const { env } = useEnvContext();
const [acceptClients, setAcceptClients] = useState(true); const [acceptClients, setAcceptClients] = useState(true);
const [allowPangolinSsh, setAllowPangolinSsh] = useState(true); const [allowPangolinSsh, setAllowPangolinSsh] = useState(
!env.flags.disableEnterpriseFeatures
);
const [platform, setPlatform] = useState<Platform>("linux"); const [platform, setPlatform] = useState<Platform>("linux");
const [architecture, setArchitecture] = useState( const [architecture, setArchitecture] = useState(
() => getArchitectures(platform)[0] () => getArchitectures(platform)[0]
@@ -71,7 +75,11 @@ export function NewtSiteInstallCommands({
: ""; : "";
const disableSshFlag = const disableSshFlag =
supportsSshOption && !allowPangolinSsh ? " --disable-ssh" : ""; supportsSshOption &&
!allowPangolinSsh &&
!env.flags.disableEnterpriseFeatures
? " --disable-ssh"
: "";
const runAsRootPrefix = const runAsRootPrefix =
supportsSshOption && allowPangolinSsh ? "sudo " : ""; supportsSshOption && allowPangolinSsh ? "sudo " : "";
@@ -306,14 +314,16 @@ WantedBy=default.target`
> >
{t("siteAcceptClientConnectionsDescription")} {t("siteAcceptClientConnectionsDescription")}
</p> </p>
{supportsSshOption && ( {supportsSshOption &&
!env.flags.disableEnterpriseFeatures && (
<> <>
<div className="flex items-center space-x-2 mb-2 mt-2"> <div className="flex items-center space-x-2 mb-2 mt-2">
<CheckboxWithLabel <CheckboxWithLabel
id="allowPangolinSsh" id="allowPangolinSsh"
checked={allowPangolinSsh} checked={allowPangolinSsh}
onCheckedChange={(checked) => { onCheckedChange={(checked) => {
const value = checked as boolean; const value =
checked as boolean;
setAllowPangolinSsh(value); setAllowPangolinSsh(value);
}} }}
label="Allow Pangolin SSH" label="Allow Pangolin SSH"