feat: creation flow fixes

This commit is contained in:
Arman
2025-03-09 11:30:31 +01:00
parent 8241d0d6d5
commit 0940fe97c4
14 changed files with 210 additions and 52 deletions
@@ -1,7 +1,7 @@
<script lang="ts">
import { Button, InputSelect, InputText } from '$lib/elements/forms';
import { Fieldset, Layout, Selector, Skeleton } from '@appwrite.io/pink-svelte';
import SelectRootModal from '../../../routes/(console)/project-[project]/sites/(components)/selectRootModal.svelte';
import SelectRootModal from './selectRootModal.svelte';
import { sdk } from '$lib/stores/sdk';
import { sortBranches } from '$lib/stores/vcs';
@@ -1,8 +1,13 @@
<script lang="ts">
import { CustomId } from '$lib/components';
import { BillingPlan } from '$lib/constants';
import { InputSelect, InputText } from '$lib/elements/forms';
import Link from '$lib/elements/link.svelte';
import { upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { isCloud } from '$lib/system';
import { IconPencil } from '@appwrite.io/pink-icons-svelte';
import { Fieldset, Icon, Layout, Tag } from '@appwrite.io/pink-svelte';
import { Fieldset, Icon, Input, Layout, Tag } from '@appwrite.io/pink-svelte';
import type { ComponentType } from 'svelte';
export let name: string;
@@ -15,6 +20,11 @@
label: string;
leadingIcon?: ComponentType;
}[] = [];
export let specification: string;
export let specificationOptions: {
value: string;
label: string;
}[] = [];
let showCustomId = false;
</script>
@@ -49,6 +59,25 @@
required
{options} />
{/key}
{#if isCloud}
<Layout.Stack gap="xs">
<InputSelect
label="CPU and memory"
id="specification"
placeholder="Select specification"
required
disabled={specificationOptions.length < 1}
options={specificationOptions}
bind:value={specification} />
{#if $organization?.billingPlan === BillingPlan.FREE}
<Input.Helper state="default">
<Link href={$upgradeURL} variant="muted">Upgrade</Link> to Pro or Scale to adjust
your CPU and RAM beyond the default.
</Input.Helper>
{/if}
</Layout.Stack>
{/if}
{#if showEntrypoint}
<InputText
label="Entrypoint"
@@ -125,7 +125,7 @@
runtime: template.name
});
}}
href={`${wizardBase}/create-function/template-${starterTemplate.id}`}>
href={`${wizardBase}/create-function/template-${starterTemplate.id}?runtime=${runtimeDetail.$id}`}>
<Layout.Stack direction="row" gap="s" alignItems="center">
<Avatar
size="xs"
@@ -7,10 +7,9 @@
import { Wizard } from '$lib/layout';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { installation, repository } from '$lib/stores/vcs';
import { Layout } from '@appwrite.io/pink-svelte';
import { Icon, Layout, Tooltip, Typography, Upload } from '@appwrite.io/pink-svelte';
import { writable } from 'svelte/store';
import { ID, Runtime, Type } from '@appwrite.io/console';
import { ID, Runtime } from '@appwrite.io/console';
import type { Models } from '@appwrite.io/console';
import { consoleVariables } from '$routes/(console)/store';
import Details from '../(components)/details.svelte';
@@ -18,8 +17,26 @@
import { iconPath } from '$lib/stores/app';
import { getIconFromRuntime } from '../../store';
import { Dependencies } from '$lib/constants';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
import Configuration from './configuration.svelte';
export let data;
const runtimeOptions = data.runtimesList.runtimes.map((runtime) => {
return {
value: runtime.$id,
label: `${runtime.name} - ${runtime.version}`,
leadingHtml: `<img src='${$iconPath(getIconFromRuntime(runtime.key), 'color')}' style='inline-size: var(--icon-size-m)' />`
};
});
const specificationOptions = data.specificationsList.specifications.map((size) => ({
label:
`${size.cpus} CPU, ${size.memory} MB RAM` +
(!size.enabled ? ` (Upgrade to use this)` : ''),
value: size.slug,
disabled: !size.enabled
}));
let showExitModal = false;
let formComponent: Form;
@@ -31,18 +48,18 @@
let entrypoint = '';
let buildCommand = '';
let scopes: string[] = [];
let branch: string;
let rootDir = './';
let variables: Partial<Models.Variable>[] = [];
let silentMode = false;
let files: FileList;
let specification = specificationOptions[0].value;
async function create() {
try {
const rt = Object.values(Runtime).find((r) => r === runtime);
console.log(runtime);
const func = await sdk.forProject.functions.create(
id,
name,
rt,
runtime,
undefined,
undefined,
undefined,
@@ -52,12 +69,12 @@
entrypoint,
undefined,
scopes,
$installation.$id,
$repository.id,
branch,
silentMode,
rootDir,
undefined //TODO: specs
undefined,
undefined,
undefined,
undefined,
undefined,
specification || undefined
);
// Add domain
@@ -77,14 +94,20 @@
);
await Promise.all(promises);
await sdk.forProject.functions.createVcsDeployment(func.$id, Type.Branch, branch, true);
await sdk.forProject.functions.createDeployment(
func.$id,
files[0],
true,
entrypoint,
buildCommand
);
trackEvent(Submit.FunctionCreate, {
source: 'repository',
runtime: runtime
});
await goto(`${base}/project-${$page.params.project}/functions/function=${func.$id}`);
await goto(`${base}/project-${$page.params.project}/functions/function-${func.$id}`);
invalidate(Dependencies.FUNCTION);
} catch (e) {
@@ -95,14 +118,6 @@
trackError(e, Submit.FunctionCreate);
}
}
const runtimeOptions = data.runtimesList.runtimes.map((runtime) => {
return {
value: runtime.name,
label: `${runtime.name} - ${runtime.version}`,
leadingHtml: `<img src='${$iconPath(getIconFromRuntime(runtime.key), 'color')}' style='inline-size: var(--icon-size-m)' />`
};
});
</script>
<svelte:head>
@@ -113,18 +128,58 @@
title="Create function"
bind:showExitModal
href={`${base}/project-${$page.params.project}/functions`}
column
columnSize="s"
confirmExit>
<Form bind:this={formComponent} onSubmit={create} bind:isSubmitting>
<Layout.Stack gap="xl">
<Layout.Stack gap="s">
<Typography.Text color="--fgcolor-neutral-primary">
Upload a zip file (tar.gz) containing your function source code
</Typography.Text>
<Upload.Dropzone bind:files title="Upload function">
<Layout.Stack alignItems="center" gap="s">
<Layout.Stack alignItems="center" gap="s">
<Layout.Stack
alignItems="center"
justifyContent="center"
direction="row"
gap="s">
<Typography.Text variant="l-500">
Drag and drop file here or click to upload
</Typography.Text>
<Tooltip>
<Layout.Stack
alignItems="center"
justifyContent="center"
inline>
<Icon icon={IconInfo} size="s" />
</Layout.Stack>
<svelte:fragment slot="tooltip"
>Only .tar.gz files allowed</svelte:fragment>
</Tooltip>
</Layout.Stack>
<Typography.Caption variant="400"
>Max file size 10MB</Typography.Caption>
</Layout.Stack>
</Layout.Stack>
</Upload.Dropzone>
{#if files?.length}
<Upload.List bind:files />
{/if}
</Layout.Stack>
<Details
bind:name
bind:entrypoint
bind:id
bind:runtime
bind:specification
{specificationOptions}
options={runtimeOptions}
showEntrypoint />
<!-- <Configuration bind:buildCommand bind:scopes /> -->
<Configuration bind:buildCommand bind:scopes />
</Layout.Stack>
</Form>
<svelte:fragment slot="aside">
@@ -1,8 +1,9 @@
export const load = async ({ parent }) => {
let { installations, runtimesList } = await parent();
let { installations, runtimesList, specificationsList } = await parent();
return {
installations,
runtimesList
runtimesList,
specificationsList
};
};
@@ -0,0 +1,36 @@
<script lang="ts">
import { Roles } from '$lib/components/permissions';
import { Link } from '$lib/elements';
import { InputText } from '$lib/elements/forms';
import { Accordion, Fieldset, Layout } from '@appwrite.io/pink-svelte';
export let buildCommand = '';
export let scopes: string[] = [];
</script>
<Fieldset legend="Settings">
<Layout.Stack>
<Accordion title="Build settings" badge="Optional">
<Layout.Stack gap="xl">
Set up how your project is built.
<InputText
id="installCommand"
label="Install command"
bind:value={buildCommand}
placeholder="npm install" />
</Layout.Stack>
</Accordion>
<Accordion title="Execute access" badge="Optional" hideDivider>
<Layout.Stack gap="xl">
<span>
Choose who can execute this function using the client API. <Link
external
href="https://appwrite.io/docs/advanced/platform/permissions"
>Learn more</Link>
</span>
<Roles bind:roles={scopes} />
</Layout.Stack>
</Accordion>
</Layout.Stack>
</Fieldset>
@@ -24,6 +24,22 @@
import RepoCard from './repoCard.svelte';
export let data;
const specificationOptions = data.specificationsList.specifications.map((size) => ({
label:
`${size.cpus} CPU, ${size.memory} MB RAM` +
(!size.enabled ? ` (Upgrade to use this)` : ''),
value: size.slug,
disabled: !size.enabled
}));
const runtimeOptions = data.runtimesList.runtimes.map((runtime) => {
return {
value: runtime.$id,
label: `${runtime.name} - ${runtime.version}`,
leadingHtml: `<img src='${$iconPath(getIconFromRuntime(runtime.key), 'color')}' style='inline-size: var(--icon-size-m)' />`
};
});
let showExitModal = false;
let formComponent: Form;
@@ -39,14 +55,7 @@
let rootDir = './';
let variables: Partial<Models.Variable>[] = [];
let silentMode = false;
const runtimeOptions = data.runtimesList.runtimes.map((runtime) => {
return {
value: runtime.name,
label: `${runtime.name} - ${runtime.version}`,
leadingHtml: `<img src='${$iconPath(getIconFromRuntime(runtime.key), 'color')}' style='inline-size: var(--icon-size-m)' />`
};
});
let specification = specificationOptions[0].value;
onMount(async () => {
installation.set(data.installation);
@@ -74,7 +83,7 @@
branch,
silentMode,
rootDir,
undefined //TODO: specs
specification || undefined
);
// Add domain
@@ -101,7 +110,7 @@
runtime: runtime
});
await goto(`${base}/project-${$page.params.project}/functions/function=${func.$id}`);
await goto(`${base}/project-${$page.params.project}/functions/function-${func.$id}`);
invalidate(Dependencies.FUNCTION);
} catch (e) {
@@ -132,6 +141,8 @@
bind:entrypoint
bind:id
bind:runtime
bind:specification
{specificationOptions}
options={runtimeOptions}
showEntrypoint />
@@ -161,7 +172,7 @@
submissionLoader
on:click={() => formComponent.triggerSubmit()}
disabled={$isSubmitting}>
Create
Deploy
</Button>
</svelte:fragment>
</Wizard>
@@ -1,7 +1,7 @@
import { sdk } from '$lib/stores/sdk';
export const load = async ({ parent, params, url }) => {
const { installations, runtimesList } = await parent();
const { installations, runtimesList, specificationsList } = await parent();
const [repository] = await Promise.all([
sdk.forProject.vcs.getRepository(url.searchParams.get('installation'), params.repository)
@@ -13,6 +13,7 @@ export const load = async ({ parent, params, url }) => {
(installation) => installation.$id === url.searchParams.get('installation')
),
repository,
runtimesList
runtimesList,
specificationsList
};
};
@@ -8,7 +8,7 @@
export let scopes: string[] = [];
</script>
<Fieldset legend="Configuration">
<Fieldset legend="Settings">
<Layout.Stack>
<Accordion title="Build settings" badge="Optional">
<Layout.Stack gap="xl">
@@ -30,6 +30,14 @@
export let data;
const specificationOptions = data.specificationsList.specifications.map((size) => ({
label:
`${size.cpus} CPU, ${size.memory} MB RAM` +
(!size.enabled ? ` (Upgrade to use this)` : ''),
value: size.slug,
disabled: !size.enabled
}));
let showExitModal = false;
let isCreatingRepository = false;
let hasInstallations = !!data?.installations?.total;
@@ -54,8 +62,15 @@
let selectedScopes: string[] = [];
let execute = false;
let variables: Partial<Models.TemplateVariable>[] = [];
let specification = specificationOptions[0].value;
onMount(async () => {
if ($page.url.searchParams.has('runtime')) {
console.log(runtime);
console.log($page.url.searchParams.get('runtime'));
runtime = $page.url.searchParams.get('runtime') as Runtime;
console.log(runtime);
}
if (!$installation?.$id) {
$installation = data.installations.installations[0];
}
@@ -125,7 +140,7 @@
branch,
silentMode,
rootDir,
undefined //TODO: specs
specification || undefined
);
// Add domain
@@ -228,7 +243,14 @@
})}
<Layout.Stack gap="xxl">
<Details bind:name bind:id bind:runtime bind:entrypoint {options} />
<Details
bind:name
bind:id
bind:runtime
bind:entrypoint
bind:specification
{specificationOptions}
{options} />
<Permissions
templateScopes={data.template.scopes}
@@ -329,7 +351,7 @@
size="s"
on:click={() => formComponent.triggerSubmit()}
disabled={$isSubmitting || (connectBehaviour === 'now' && !selectedRepository)}>
Create
Deploy
</Button>
</svelte:fragment>
</Wizard>
@@ -1,12 +1,13 @@
import { sdk } from '$lib/stores/sdk';
export const load = async ({ parent, params }) => {
let { installations, runtimesList } = await parent();
let { installations, runtimesList, specificationsList } = await parent();
const template = await sdk.forProject.functions.getTemplate(params.template);
return {
installations,
template,
runtimesList
runtimesList,
specificationsList
};
};
@@ -79,6 +79,7 @@
id={variable.name}
value={variable.name}
readonly
required
label={i === 0 ? 'Key' : null} />
<svelte:component
this={selectComponent(variable.type)}
@@ -119,6 +120,7 @@
id={variable.name}
value={variable.name}
readonly
required
label={i === 0 ? 'Key' : null} />
<svelte:component
this={selectComponent(variable.type)}
@@ -3,9 +3,9 @@
import { Button } from '$lib/elements/forms';
import { canWriteFunctions } from '$lib/stores/roles';
import { ActionMenu, Icon, Popover } from '@appwrite.io/pink-svelte';
import CreateCli from './createCli.svelte';
import CreateGit from './createGit.svelte';
import CreateManual from './createManual.svelte';
import CreateCli from './(modals)/createCli.svelte';
import CreateGit from './(modals)/createGit.svelte';
import CreateManual from './(modals)/createManual.svelte';
import { showCreateDeployment } from './store';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';