Update setting is working

Adjust the ui

Adjust description
This commit is contained in:
Owen
2026-05-21 16:21:23 -07:00
parent 6d4afd0953
commit 4530aac4f3
5 changed files with 85 additions and 71 deletions

View File

@@ -1601,16 +1601,15 @@
"contents": "Contents", "contents": "Contents",
"parsedContents": "Parsed Contents (Read Only)", "parsedContents": "Parsed Contents (Read Only)",
"enableDockerSocket": "Enable Docker Blueprint", "enableDockerSocket": "Enable Docker Blueprint",
"enableDockerSocketDescription": "Enable Docker Socket label scraping for blueprint labels. Socket path must be provided to Newt. Read about how this works in <docsLink>the documentation</docsLink>.", "enableDockerSocketDescription": "Enable Docker Socket label scraping for blueprint labels. Socket path must be provided to the site connector. Read about how this works in <docsLink>the documentation</docsLink>.",
"newtAutoUpdate": "Enable Newt Auto-Update", "newtAutoUpdate": "Enable Site Auto-Update",
"newtAutoUpdateDescription": "When enabled, Newt clients will automatically update to the latest version when a new release is available.", "newtAutoUpdateDescription": "When enabled, site connectors will automatically update to the latest version when a new release is available.",
"newtAutoUpdateDisabledDescription": "This feature requires a valid license (Enterprise) or active subscription (SaaS)", "siteAutoUpdate": "Site Auto-Update",
"siteAutoUpdate": "Newt Auto-Update",
"siteAutoUpdateLabel": "Enable Auto-Update", "siteAutoUpdateLabel": "Enable Auto-Update",
"siteAutoUpdateDescription": "Control whether this site's Newt client automatically updates. When not overriding, the organization default is used.", "siteAutoUpdateDescription": "Control whether this site's connector automatically downloads the latest version.",
"siteAutoUpdateOrgDefault": "Organization default: {state}", "siteAutoUpdateOrgDefault": "Organization default: {state}",
"siteAutoUpdateOverriding": "Overriding organization setting", "siteAutoUpdateOverriding": "Overriding organization setting",
"siteAutoUpdateResetToOrg": "Reset to organization default", "siteAutoUpdateResetToOrg": "Reset to Organization Default",
"siteAutoUpdateEnabled": "enabled", "siteAutoUpdateEnabled": "enabled",
"siteAutoUpdateDisabled": "disabled", "siteAutoUpdateDisabled": "disabled",
"viewDockerContainers": "View Docker Containers", "viewDockerContainers": "View Docker Containers",

View File

@@ -217,6 +217,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
title: t("orgUpdated"), title: t("orgUpdated"),
description: t("orgUpdatedDescription") description: t("orgUpdatedDescription")
}); });
router.refresh(); router.refresh();
} catch (e) { } catch (e) {
toast({ toast({
@@ -260,6 +261,9 @@ function GeneralSectionForm({ org }: SectionFormProps) {
)} )}
/> />
<PaidFeaturesAlert
tiers={tierMatrix.newtAutoUpdate}
/>
<FormField <FormField
control={form.control} control={form.control}
name="settingsEnableGlobalNewtAutoUpdate" name="settingsEnableGlobalNewtAutoUpdate"
@@ -271,17 +275,11 @@ function GeneralSectionForm({ org }: SectionFormProps) {
label={t("newtAutoUpdate")} label={t("newtAutoUpdate")}
checked={field.value} checked={field.value}
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
disabled={ disabled={!hasAutoUpdateFeature}
!hasAutoUpdateFeature
}
/> />
</FormControl> </FormControl>
<FormDescription> <FormDescription>
{hasAutoUpdateFeature {t("newtAutoUpdateDescription")}
? t("newtAutoUpdateDescription")
: t(
"newtAutoUpdateDisabledDescription"
)}
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@@ -40,6 +40,7 @@ import { useOrgContext } from "@app/hooks/useOrgContext";
import { usePaidStatus } from "@app/hooks/usePaidStatus"; import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix"; import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix";
import { Button as ButtonUI } from "@/components/ui/button"; import { Button as ButtonUI } from "@/components/ui/button";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
const GeneralFormSchema = z.object({ const GeneralFormSchema = z.object({
name: z.string().nonempty("Name is required"), name: z.string().nonempty("Name is required"),
@@ -70,8 +71,7 @@ export default function GeneralPage() {
null null
); );
const orgAutoUpdate = const orgAutoUpdate = org.org.settingsEnableGlobalNewtAutoUpdate ?? false;
org.org.settingsEnableGlobalNewtAutoUpdate ?? false;
const form = useForm({ const form = useForm({
resolver: zodResolver(GeneralFormSchema), resolver: zodResolver(GeneralFormSchema),
@@ -221,7 +221,9 @@ export default function GeneralPage() {
{t.rich( {t.rich(
"enableDockerSocketDescription", "enableDockerSocketDescription",
{ {
docsLink: (chunks) => ( docsLink: (
chunks
) => (
<a <a
href="https://docs.pangolin.net/manage/sites/configure-site#docker-socket-integration" href="https://docs.pangolin.net/manage/sites/configure-site#docker-socket-integration"
target="_blank" target="_blank"
@@ -240,53 +242,50 @@ export default function GeneralPage() {
/> />
)} )}
<PaidFeaturesAlert
tiers={tierMatrix.newtAutoUpdate}
/>
{site && site.type === "newt" && ( {site && site.type === "newt" && (
<FormField <FormField
control={form.control} control={form.control}
name="autoUpdateEnabled" name="autoUpdateEnabled"
render={({ field }) => { render={({ field }) => {
const isOverriding = const isOverriding = form.watch(
form.watch( "autoUpdateOverrideOrg"
"autoUpdateOverrideOrg" );
);
return ( return (
<FormItem> <FormItem>
<FormControl> <FormControl>
<SwitchInput <div className="flex items-center gap-3">
id="auto-update-enabled" <SwitchInput
label={t( id="auto-update-enabled"
"siteAutoUpdateLabel" label={t(
)} "siteAutoUpdateLabel"
checked={ )}
field.value checked={
} field.value
onCheckedChange={(checked) => { }
field.onChange( onCheckedChange={(
checked checked
); ) => {
form.setValue( field.onChange(
"autoUpdateOverrideOrg", checked
true );
); form.setValue(
}} "autoUpdateOverrideOrg",
disabled={ true
!hasAutoUpdateFeature );
} }}
/> disabled={
</FormControl> !hasAutoUpdateFeature
<FormDescription> }
{isOverriding ? ( />
<span className="flex items-center gap-2"> {isOverriding && (
<span>
{t(
"siteAutoUpdateOverriding"
)}
</span>
<ButtonUI <ButtonUI
type="button" type="button"
variant="link" variant="link"
size="sm" size="sm"
className="h-auto p-0 text-xs" className="h-auto p-0 pb-2 text-xs"
onClick={() => { onClick={() => {
form.setValue( form.setValue(
"autoUpdateOverrideOrg", "autoUpdateOverrideOrg",
@@ -302,20 +301,12 @@ export default function GeneralPage() {
"siteAutoUpdateResetToOrg" "siteAutoUpdateResetToOrg"
)} )}
</ButtonUI> </ButtonUI>
</span> )}
) : ( </div>
t( </FormControl>
"siteAutoUpdateOrgDefault", <FormDescription>
{ {t(
state: orgAutoUpdate "siteAutoUpdateDescription"
? t(
"siteAutoUpdateEnabled"
)
: t(
"siteAutoUpdateDisabled"
)
}
)
)} )}
</FormDescription> </FormDescription>
<FormMessage /> <FormMessage />

View File

@@ -1,6 +1,8 @@
import SiteProvider from "@app/providers/SiteProvider"; import SiteProvider from "@app/providers/SiteProvider";
import OrgProvider from "@app/providers/OrgProvider";
import { internal } from "@app/lib/api"; import { internal } from "@app/lib/api";
import { GetSiteResponse } from "@server/routers/site"; import { GetSiteResponse } from "@server/routers/site";
import { GetOrgResponse } from "@server/routers/org";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { authCookieHeader } from "@app/lib/api/cookies"; import { authCookieHeader } from "@app/lib/api/cookies";
@@ -35,6 +37,17 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
redirect(`/${params.orgId}/settings/sites`); redirect(`/${params.orgId}/settings/sites`);
} }
let org = null;
try {
const res = await internal.get<AxiosResponse<GetOrgResponse>>(
`/org/${params.orgId}`,
await authCookieHeader()
);
org = res.data.data;
} catch {
redirect(`/${params.orgId}/settings/sites`);
}
const t = await getTranslations(); const t = await getTranslations();
const navItems = [ const navItems = [
@@ -64,10 +77,14 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
/> />
<SiteProvider site={site}> <SiteProvider site={site}>
<div className="space-y-4"> <OrgProvider org={org}>
<SiteInfoCard /> <div className="space-y-4">
<HorizontalTabs items={navItems}>{children}</HorizontalTabs> <SiteInfoCard />
</div> <HorizontalTabs items={navItems}>
{children}
</HorizontalTabs>
</div>
</OrgProvider>
</SiteProvider> </SiteProvider>
</> </>
); );

View File

@@ -45,7 +45,16 @@ export function SwitchInput({
return ( return (
<div> <div>
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
{label && <Label htmlFor={id}>{label}</Label>} {label && (
<Label
htmlFor={id}
className={
disabled ? "opacity-50 cursor-not-allowed" : ""
}
>
{label}
</Label>
)}
<Switch <Switch
id={id} id={id}
checked={checked} checked={checked}