From b8fca7c1026908762daaa02fd4275cc067835223 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 11 Jul 2026 15:33:33 +1000 Subject: [PATCH 1/3] Deduplicate service configuration toasts --- web/components/service/details/secrets-section.tsx | 1 - web/components/service/details/serverless-section.tsx | 1 - web/components/service/details/source-section.tsx | 2 -- 3 files changed, 4 deletions(-) diff --git a/web/components/service/details/secrets-section.tsx b/web/components/service/details/secrets-section.tsx index bb829df0..517a8c4b 100644 --- a/web/components/service/details/secrets-section.tsx +++ b/web/components/service/details/secrets-section.tsx @@ -184,7 +184,6 @@ export const SecretsSection = memo(function SecretsSection({ await mutate(); setPendingVars([]); setPendingDeletes([]); - toast.success("Environment variables saved"); onUpdate(); } catch { toast.error("Failed to save changes"); diff --git a/web/components/service/details/serverless-section.tsx b/web/components/service/details/serverless-section.tsx index 94814241..11fa8a4a 100644 --- a/web/components/service/details/serverless-section.tsx +++ b/web/components/service/details/serverless-section.tsx @@ -81,7 +81,6 @@ export const ServerlessSection = memo(function ServerlessSection({ wakeTimeoutSeconds: parsed.wakeTimeoutSeconds, }); onUpdate(); - toast.success("Serverless settings saved. Deploy to apply."); } catch (error) { toast.error( error instanceof Error diff --git a/web/components/service/details/source-section.tsx b/web/components/service/details/source-section.tsx index 377084f1..73ea7329 100644 --- a/web/components/service/details/source-section.tsx +++ b/web/components/service/details/source-section.tsx @@ -75,7 +75,6 @@ export const SourceSection = memo(function SourceSection({ branch, rootDir, ); - toast.success("Repository settings updated"); setIsEditing(false); onUpdate?.(); } catch (error) { @@ -99,7 +98,6 @@ export const SourceSection = memo(function SourceSection({ await updateServiceConfig(service.id, { source: { type: "image", image: image.trim() }, }); - toast.success("Docker image updated"); setIsEditing(false); onUpdate?.(); } catch (error) { From 18423a5e1f174ea0fd8fb0834492b59e17cfc5e8 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 11 Jul 2026 15:47:25 +1000 Subject: [PATCH 2/3] Default new services to unlimited resources --- cli/internal/cli/app.go | 3 --- cli/internal/cli/app_test.go | 3 +++ web/actions/projects.ts | 6 ++++-- web/components/service/details/resource-limits-section.tsx | 5 ++--- web/db/schema.ts | 4 ++-- web/lib/cli-service.ts | 3 +-- web/lib/constants.ts | 5 ----- 7 files changed, 12 insertions(+), 17 deletions(-) diff --git a/cli/internal/cli/app.go b/cli/internal/cli/app.go index 14a69ef2..29a04d96 100644 --- a/cli/internal/cli/app.go +++ b/cli/internal/cli/app.go @@ -287,9 +287,6 @@ service: image: nginx:1.27 replicas: count: 1 - resources: - cpuCores: 2 - memoryMb: 1024 ports: - port: 80 public: false diff --git a/cli/internal/cli/app_test.go b/cli/internal/cli/app_test.go index f7992cfc..f5c253c4 100644 --- a/cli/internal/cli/app_test.go +++ b/cli/internal/cli/app_test.go @@ -33,6 +33,9 @@ func TestInitCreatesManifest(t *testing.T) { if !strings.Contains(string(raw), "image: nginx:1.27") { t.Fatalf("manifest = %s", raw) } + if strings.Contains(string(raw), "resources:") { + t.Fatalf("manifest should not set default resource limits: %s", raw) + } } func TestLogsRejectsInvalidTailBeforeConfig(t *testing.T) { diff --git a/web/actions/projects.ts b/web/actions/projects.ts index 3d8385aa..33d51dfa 100644 --- a/web/actions/projects.ts +++ b/web/actions/projects.ts @@ -29,7 +29,6 @@ import { workQueue, } from "@/db/schema"; import { requireDeveloperRole, verifyDeleteConfirmation } from "@/lib/auth"; -import { DEFAULT_RESOURCE_LIMITS } from "@/lib/constants"; import { deployServiceInternal } from "@/lib/deploy-service"; import { isObservedReady, @@ -429,7 +428,10 @@ const SERVICE_CARD_WIDTH = 320; export async function createService(input: CreateServiceInput) { await requireDeveloperRole(); const { projectId, environmentId, name, image, github } = input; - const resourceLimits = input.resourceLimits ?? DEFAULT_RESOURCE_LIMITS; + const resourceLimits = input.resourceLimits ?? { + cpuCores: null, + memoryMb: null, + }; const env = await getEnvironment(environmentId); if (!env) { throw new Error("Environment not found"); diff --git a/web/components/service/details/resource-limits-section.tsx b/web/components/service/details/resource-limits-section.tsx index bd1a52c2..06ff7ac2 100644 --- a/web/components/service/details/resource-limits-section.tsx +++ b/web/components/service/details/resource-limits-section.tsx @@ -11,7 +11,6 @@ import { NativeSelectOption, } from "@/components/ui/native-select"; import type { ServiceWithDetails as Service } from "@/db/types"; -import { DEFAULT_RESOURCE_LIMITS } from "@/lib/constants"; type Preset = { label: string; @@ -25,8 +24,8 @@ const PRESETS: Record = { medium: { label: "Medium (1 CPU, 512MB)", cpuCores: 1, memoryMb: 512 }, large: { label: "Large (2 CPU, 1024MB)", - cpuCores: DEFAULT_RESOURCE_LIMITS.cpuCores, - memoryMb: DEFAULT_RESOURCE_LIMITS.memoryMb, + cpuCores: 2, + memoryMb: 1024, }, xlarge: { label: "X-Large (4 CPU, 2048MB)", cpuCores: 4, memoryMb: 2048 }, custom: { label: "Custom", cpuCores: null, memoryMb: null }, diff --git a/web/db/schema.ts b/web/db/schema.ts index 86da744c..a3bc22ca 100644 --- a/web/db/schema.ts +++ b/web/db/schema.ts @@ -408,8 +408,8 @@ export const services = pgTable("services", { healthCheckRetries: integer("health_check_retries").default(3), healthCheckStartPeriod: integer("health_check_start_period").default(30), startCommand: text("start_command"), - resourceCpuLimit: real("resource_cpu_limit").default(2), - resourceMemoryLimitMb: integer("resource_memory_limit_mb").default(1024), + resourceCpuLimit: real("resource_cpu_limit"), + resourceMemoryLimitMb: integer("resource_memory_limit_mb"), serverlessEnabled: boolean("serverless_enabled").notNull().default(false), serverlessSleepAfterSeconds: integer("serverless_sleep_after_seconds") .notNull() diff --git a/web/lib/cli-service.ts b/web/lib/cli-service.ts index e41ca193..4bcd5368 100644 --- a/web/lib/cli-service.ts +++ b/web/lib/cli-service.ts @@ -23,7 +23,6 @@ import { type TechulusManifest, techulusManifestSchema, } from "@/lib/cli-manifest"; -import { DEFAULT_RESOURCE_LIMITS } from "@/lib/constants"; import { deployServiceInternal } from "@/lib/deploy-service"; import { slugify } from "@/lib/utils"; @@ -36,7 +35,7 @@ export type ManifestChange = { function getManifestResourceLimits(manifest: TechulusManifest) { const resources = manifest.service.resources; if (resources === undefined) { - return DEFAULT_RESOURCE_LIMITS; + return { cpuCores: null, memoryMb: null }; } return { diff --git a/web/lib/constants.ts b/web/lib/constants.ts index 318b66aa..88493e47 100644 --- a/web/lib/constants.ts +++ b/web/lib/constants.ts @@ -1,7 +1,2 @@ export const WIREGUARD_SUBNET_PREFIX = "10.100"; export const CONTAINER_SUBNET_PREFIX = "10.200"; - -export const DEFAULT_RESOURCE_LIMITS = { - cpuCores: 2, - memoryMb: 1024, -} as const; From ec58874cd23a364171d404b29022f205f80a9c4c Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 11 Jul 2026 16:05:14 +1000 Subject: [PATCH 3/3] Preserve limits omitted from CLI manifests --- web/lib/cli-service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/lib/cli-service.ts b/web/lib/cli-service.ts index 4bcd5368..a3191c1b 100644 --- a/web/lib/cli-service.ts +++ b/web/lib/cli-service.ts @@ -35,7 +35,7 @@ export type ManifestChange = { function getManifestResourceLimits(manifest: TechulusManifest) { const resources = manifest.service.resources; if (resources === undefined) { - return { cpuCores: null, memoryMb: null }; + return null; } return { @@ -557,6 +557,9 @@ async function syncResources( changes: ManifestChange[], ) { const desiredResources = getManifestResourceLimits(manifest); + if (desiredResources === null) { + return; + } const desiredCpu = desiredResources.cpuCores; const desiredMemory = desiredResources.memoryMb;