Control updates from the ui

This commit is contained in:
Owen
2026-05-21 15:43:31 -07:00
parent dee0ca6864
commit 6d4afd0953
9 changed files with 333 additions and 44 deletions

View File

@@ -38,11 +38,16 @@ import { useUserContext } from "@app/hooks/useUserContext";
import { useTranslations } from "next-intl";
import { build } from "@server/build";
import type { OrgContextType } from "@app/contexts/orgContext";
import { SwitchInput } from "@app/components/SwitchInput";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
// Schema for general organization settings
const GeneralFormSchema = z.object({
name: z.string(),
subnet: z.string().optional()
subnet: z.string().optional(),
settingsEnableGlobalNewtAutoUpdate: z.boolean().optional()
});
export default function GeneralPage() {
@@ -163,17 +168,24 @@ function GeneralSectionForm({ org }: SectionFormProps) {
resolver: zodResolver(
GeneralFormSchema.pick({
name: true,
subnet: true
subnet: true,
settingsEnableGlobalNewtAutoUpdate: true
})
),
defaultValues: {
name: org.name,
subnet: org.subnet || "" // Add default value for subnet
subnet: org.subnet || "",
settingsEnableGlobalNewtAutoUpdate:
org.settingsEnableGlobalNewtAutoUpdate ?? false
},
mode: "onChange"
});
const t = useTranslations();
const router = useRouter();
const { isPaidUser } = usePaidStatus();
const hasAutoUpdateFeature = isPaidUser(
tierMatrix[TierFeature.NewtAutoUpdate]
);
const [, formAction, loadingSave] = useActionState(performSave, null);
const api = createApiClient(useEnvContext());
@@ -186,7 +198,9 @@ function GeneralSectionForm({ org }: SectionFormProps) {
try {
const reqData = {
name: data.name
name: data.name,
settingsEnableGlobalNewtAutoUpdate:
data.settingsEnableGlobalNewtAutoUpdate
} as any;
// Update organization
@@ -194,7 +208,9 @@ function GeneralSectionForm({ org }: SectionFormProps) {
// Update the org context to reflect the change in the info card
updateOrg({
name: data.name
name: data.name,
settingsEnableGlobalNewtAutoUpdate:
data.settingsEnableGlobalNewtAutoUpdate
});
toast({
@@ -243,6 +259,34 @@ function GeneralSectionForm({ org }: SectionFormProps) {
</FormItem>
)}
/>
<FormField
control={form.control}
name="settingsEnableGlobalNewtAutoUpdate"
render={({ field }) => (
<FormItem>
<FormControl>
<SwitchInput
id="settings-enable-global-newt-auto-update"
label={t("newtAutoUpdate")}
checked={field.value}
onCheckedChange={field.onChange}
disabled={
!hasAutoUpdateFeature
}
/>
</FormControl>
<FormDescription>
{hasAutoUpdateFeature
? t("newtAutoUpdateDescription")
: t(
"newtAutoUpdateDisabledDescription"
)}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</form>
</Form>
</SettingsSectionForm>

View File

@@ -36,35 +36,53 @@ import { useState } from "react";
import { SwitchInput } from "@app/components/SwitchInput";
import { ExternalLink } from "lucide-react";
import { useTranslations } from "next-intl";
import { useOrgContext } from "@app/hooks/useOrgContext";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix, TierFeature } from "@server/lib/billing/tierMatrix";
import { Button as ButtonUI } from "@/components/ui/button";
const GeneralFormSchema = z.object({
name: z.string().nonempty("Name is required"),
niceId: z.string().min(1).max(255).optional(),
dockerSocketEnabled: z.boolean().optional()
dockerSocketEnabled: z.boolean().optional(),
autoUpdateEnabled: z.boolean().optional(),
autoUpdateOverrideOrg: z.boolean().optional()
});
type GeneralFormValues = z.infer<typeof GeneralFormSchema>;
export default function GeneralPage() {
const { site, updateSite } = useSiteContext();
const { org } = useOrgContext();
const { env } = useEnvContext();
const api = createApiClient(useEnvContext());
const router = useRouter();
const t = useTranslations();
const { toast } = useToast();
const { isPaidUser } = usePaidStatus();
const hasAutoUpdateFeature = isPaidUser(
tierMatrix[TierFeature.NewtAutoUpdate]
);
const [loading, setLoading] = useState(false);
const [activeCidrTagIndex, setActiveCidrTagIndex] = useState<number | null>(
null
);
const orgAutoUpdate =
org.org.settingsEnableGlobalNewtAutoUpdate ?? false;
const form = useForm({
resolver: zodResolver(GeneralFormSchema),
defaultValues: {
name: site?.name,
niceId: site?.niceId || "",
dockerSocketEnabled: site?.dockerSocketEnabled ?? false
dockerSocketEnabled: site?.dockerSocketEnabled ?? false,
autoUpdateEnabled: site?.autoUpdateOverrideOrg
? (site?.autoUpdateEnabled ?? false)
: orgAutoUpdate,
autoUpdateOverrideOrg: site?.autoUpdateOverrideOrg ?? false
},
mode: "onChange"
});
@@ -76,13 +94,17 @@ export default function GeneralPage() {
await api.post(`/site/${site?.siteId}`, {
name: data.name,
niceId: data.niceId,
dockerSocketEnabled: data.dockerSocketEnabled
dockerSocketEnabled: data.dockerSocketEnabled,
autoUpdateEnabled: data.autoUpdateEnabled,
autoUpdateOverrideOrg: data.autoUpdateOverrideOrg
});
updateSite({
name: data.name,
niceId: data.niceId,
dockerSocketEnabled: data.dockerSocketEnabled
dockerSocketEnabled: data.dockerSocketEnabled,
autoUpdateEnabled: data.autoUpdateEnabled,
autoUpdateOverrideOrg: data.autoUpdateOverrideOrg
});
if (data.niceId && data.niceId !== site?.niceId) {
@@ -217,6 +239,91 @@ export default function GeneralPage() {
)}
/>
)}
{site && site.type === "newt" && (
<FormField
control={form.control}
name="autoUpdateEnabled"
render={({ field }) => {
const isOverriding =
form.watch(
"autoUpdateOverrideOrg"
);
return (
<FormItem>
<FormControl>
<SwitchInput
id="auto-update-enabled"
label={t(
"siteAutoUpdateLabel"
)}
checked={
field.value
}
onCheckedChange={(checked) => {
field.onChange(
checked
);
form.setValue(
"autoUpdateOverrideOrg",
true
);
}}
disabled={
!hasAutoUpdateFeature
}
/>
</FormControl>
<FormDescription>
{isOverriding ? (
<span className="flex items-center gap-2">
<span>
{t(
"siteAutoUpdateOverriding"
)}
</span>
<ButtonUI
type="button"
variant="link"
size="sm"
className="h-auto p-0 text-xs"
onClick={() => {
form.setValue(
"autoUpdateOverrideOrg",
false
);
form.setValue(
"autoUpdateEnabled",
orgAutoUpdate
);
}}
>
{t(
"siteAutoUpdateResetToOrg"
)}
</ButtonUI>
</span>
) : (
t(
"siteAutoUpdateOrgDefault",
{
state: orgAutoUpdate
? t(
"siteAutoUpdateEnabled"
)
: t(
"siteAutoUpdateDisabled"
)
}
)
)}
</FormDescription>
<FormMessage />
</FormItem>
);
}}
/>
)}
</form>
</Form>
</SettingsSectionForm>