feat: build + runtime specification controls for sites and functions

This commit is contained in:
Harsh Mahajan
2026-03-20 17:19:02 +05:30
parent a90a0ea5a9
commit fe98ce018f
7 changed files with 122 additions and 36 deletions
+2 -2
View File
@@ -6,7 +6,7 @@
"name": "@appwrite/console",
"dependencies": {
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@41152f5",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@9163640",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3",
"@appwrite.io/pink-legacy": "^1.0.3",
@@ -108,7 +108,7 @@
"@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="],
"@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@41152f5", { "dependencies": { "json-bigint": "1.0.0" } }],
"@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@9163640", { "dependencies": { "json-bigint": "1.0.0" } }],
"@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="],
+1 -1
View File
@@ -20,7 +20,7 @@
},
"dependencies": {
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@41152f5",
"@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@9163640",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3",
"@appwrite.io/pink-legacy": "^1.0.3",
@@ -5,7 +5,15 @@ export const load = async ({ params, depends, parent }) => {
depends(Dependencies.VARIABLES);
depends(Dependencies.FUNCTION);
const { runtimesList, specificationsList } = await parent();
const { runtimesList, specificationsList, function: fn } = await parent();
const enabledSpecs = specificationsList?.specifications?.filter((s) => s.enabled) ?? [];
if (!enabledSpecs.some((s) => s.slug === fn.buildSpecification)) {
fn.buildSpecification = enabledSpecs[0]?.slug;
}
if (!enabledSpecs.some((s) => s.slug === fn.runtimeSpecification)) {
fn.runtimeSpecification = enabledSpecs[0]?.slug;
}
const [globalVariables, variables] = await Promise.all([
sdk.forProject(params.region, params.project).projectApi.listVariables(),
@@ -36,6 +44,7 @@ export const load = async ({ params, depends, parent }) => {
variables,
globalVariables,
runtimesList,
specificationsList
specificationsList,
function: fn
};
};
@@ -9,7 +9,8 @@
import { isValueOfStringEnum } from '$lib/helpers/types';
import { Runtime, type Models, type Scopes } from '@appwrite.io/console';
import Link from '$lib/elements/link.svelte';
import { Alert } from '@appwrite.io/pink-svelte';
import { Alert, Icon, Tooltip } from '@appwrite.io/pink-svelte';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
import { isStarterPlan, getChangePlanUrl } from '$lib/stores/billing';
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
@@ -18,11 +19,19 @@
export let func: Models.Function;
export let specs: Models.SpecificationList;
let specification = func.buildSpecification;
let originalSpecification = func.buildSpecification;
$: originalSpecification = func.buildSpecification;
let buildSpecification = func.buildSpecification;
let runtimeSpecification = func.runtimeSpecification;
let originalBuild = func.buildSpecification;
let originalRuntime = func.runtimeSpecification;
async function updateLogging() {
$: {
buildSpecification = func.buildSpecification;
runtimeSpecification = func.runtimeSpecification;
originalBuild = func.buildSpecification;
originalRuntime = func.runtimeSpecification;
}
async function updateResourceLimits() {
try {
if (!isValueOfStringEnum(Runtime, func.runtime)) {
throw new Error(`Invalid runtime: ${func.runtime}`);
@@ -45,13 +54,12 @@
providerBranch: func.providerBranch || undefined,
providerSilentMode: func.providerSilentMode || undefined,
providerRootDirectory: func.providerRootDirectory || undefined,
buildSpecification: specification || undefined
buildSpecification: buildSpecification || undefined,
runtimeSpecification: runtimeSpecification || undefined
});
await invalidate(Dependencies.FUNCTION);
originalSpecification = specification;
addNotification({
type: 'success',
message: 'Resource limits have been updated'
@@ -73,7 +81,7 @@
}));
</script>
<Form onSubmit={updateLogging}>
<Form onSubmit={updateResourceLimits}>
<CardGrid>
<svelte:fragment slot="title">Resource limits</svelte:fragment>
Define your function's compute specifications, including CPU and memory, to optimize performance
@@ -84,12 +92,33 @@
</Link>.
<svelte:fragment slot="aside">
<InputSelect
label="CPU and memory"
id="resources"
label="Build specification"
id="build-specification"
required
disabled={options.length < 1}
bind:value={specification}
{options} />
bind:value={buildSpecification}
{options}>
<Tooltip slot="info">
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
CPU and memory used when building and packaging your function deployment.
</span>
</Tooltip>
</InputSelect>
<InputSelect
label="Runtime specification"
id="runtime-specification"
required
disabled={options.length < 1}
bind:value={runtimeSpecification}
{options}>
<Tooltip slot="info">
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
CPU and memory available to each function execution at runtime.
</span>
</Tooltip>
</InputSelect>
<!-- always show upgrade on starters -->
{@const isStarter = isStarterPlan($organization.billingPlanId)}
@@ -104,7 +133,10 @@
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={originalSpecification === specification} submit>Update</Button>
<Button
disabled={originalBuild === buildSpecification &&
originalRuntime === runtimeSpecification}
submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
@@ -42,6 +42,9 @@ export const load = async ({ params, depends, parent }) => {
if (!enabledSpecs.some((s) => s.slug === site.buildSpecification)) {
site.buildSpecification = enabledSpecs[0]?.slug;
}
if (!enabledSpecs.some((s) => s.slug === site.runtimeSpecification)) {
site.runtimeSpecification = enabledSpecs[0]?.slug;
}
return {
site,
@@ -115,6 +115,9 @@
if (!specs.specifications.some((s) => s.slug === site.buildSpecification)) {
site.buildSpecification = specs.specifications[0].slug;
}
if (!specs.specifications.some((s) => s.slug === site.runtimeSpecification)) {
site.runtimeSpecification = specs.specifications[0].slug;
}
}
}
});
@@ -132,6 +135,10 @@
? site.buildSpecification
: enabledSpecs[0]?.slug;
site.buildSpecification = specToSend;
let runtimeSpecToSend = enabledSpecs.some((s) => s.slug === site.runtimeSpecification)
? site.runtimeSpecification
: enabledSpecs[0]?.slug;
site.runtimeSpecification = runtimeSpecToSend;
try {
await sdk.forProject(page.params.region, page.params.project).sites.update({
siteId: site.$id,
@@ -151,7 +158,8 @@
providerBranch: site.providerBranch || undefined,
providerSilentMode: site.providerSilentMode || undefined,
providerRootDirectory: site.providerRootDirectory || undefined,
buildSpecification: specToSend || undefined
buildSpecification: specToSend || undefined,
runtimeSpecification: runtimeSpecToSend || undefined
});
await invalidate(Dependencies.SITE);
addNotification({
@@ -8,7 +8,8 @@
import { sdk } from '$lib/stores/sdk';
import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
import Link from '$lib/elements/link.svelte';
import { Alert } from '@appwrite.io/pink-svelte';
import { Alert, Icon, Tooltip } from '@appwrite.io/pink-svelte';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
import { getChangePlanUrl, isStarterPlan } from '$lib/stores/billing';
import { isCloud } from '$lib/system';
import { organization } from '$lib/stores/organization';
@@ -17,10 +18,19 @@
export let site: Models.Site;
export let specs: Models.SpecificationList;
let specification = site.buildSpecification;
let originalSpecification = site.buildSpecification;
let buildSpecification = site.buildSpecification;
let runtimeSpecification = site.runtimeSpecification;
let originalBuild = site.buildSpecification;
let originalRuntime = site.runtimeSpecification;
async function updateLogging() {
$: {
buildSpecification = site.buildSpecification;
runtimeSpecification = site.runtimeSpecification;
originalBuild = site.buildSpecification;
originalRuntime = site.runtimeSpecification;
}
async function updateResourceLimits() {
try {
await sdk.forProject(page.params.region, page.params.project).sites.update({
siteId: site.$id,
@@ -40,10 +50,10 @@
providerBranch: site?.providerBranch || undefined,
providerSilentMode: site?.providerSilentMode || undefined,
providerRootDirectory: site?.providerRootDirectory || undefined,
buildSpecification: specification || undefined
buildSpecification: buildSpecification || undefined,
runtimeSpecification: runtimeSpecification || undefined
});
await invalidate(Dependencies.SITE);
originalSpecification = specification;
addNotification({
type: 'success',
@@ -66,23 +76,44 @@
}));
</script>
<Form onSubmit={updateLogging}>
<Form onSubmit={updateResourceLimits}>
<CardGrid>
<svelte:fragment slot="title">Resource limits</svelte:fragment>
Define your sites's compute specifications, including CPU and memory, to optimize performance
for your workloads. <Link
href="https://appwrite.io/docs/advanced/platform/compute"
external>
Define your site's compute specifications, including CPU and memory, to optimize performance for
your workloads. <Link href="https://appwrite.io/docs/advanced/platform/compute" external>
Learn more
</Link>.
<svelte:fragment slot="aside">
<InputSelect
label="CPU and memory"
id="resources"
label="Build specification"
id="build-specification"
required
disabled={options.length < 1}
bind:value={specification}
{options} />
bind:value={buildSpecification}
{options}>
<Tooltip slot="info">
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
CPU and memory used when installing dependencies and building your site for
deployment.
</span>
</Tooltip>
</InputSelect>
<InputSelect
label="Runtime specification"
id="runtime-specification"
required
disabled={options.length < 1}
bind:value={runtimeSpecification}
{options}>
<Tooltip slot="info">
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
CPU and memory used when your site serves traffic, including server-side
rendering (SSR).
</span>
</Tooltip>
</InputSelect>
<!-- always show upgrade on starters -->
{@const isStarter = isStarterPlan($organization.billingPlanId)}
@@ -97,7 +128,10 @@
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={originalSpecification === specification} submit>Update</Button>
<Button
disabled={originalBuild === buildSpecification &&
originalRuntime === runtimeSpecification}
submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>