Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat new wizard project create #1736

Merged
merged 3 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib/helpers/flag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { isValueOfStringEnum } from '$lib/helpers/types';
import { Flag } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';

export function getFlagUrl(countryCode: string) {
if (!isValueOfStringEnum(Flag, countryCode)) return '';
return sdk.forProject.avatars.getFlag(countryCode, 22, 15, 100)?.toString();
}
89 changes: 89 additions & 0 deletions src/lib/layout/createProject.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<script lang="ts">
import { Layout, Typography, Input, Tag, Icon, Button } from '@appwrite.io/pink-svelte';
import { IconPencil } from '@appwrite.io/pink-icons-svelte';
import { CustomId } from '$lib/components/index.js';
import type { Region } from '$lib/sdk/billing';
import { getFlagUrl } from '$lib/helpers/flag';
import { isCloud } from '$lib/system.js';

export let projectName: string;
export let id: string;
export let regions: Array<Region> = [];
export let region: string;
export let showTitle = true;
export let createProject: () => Promise<void>;

let showCustomId = false;

function getRegions() {
return regions
.filter((region) => region.$id !== 'default')
.sort((regionA, regionB) => {
if (regionA.disabled && !regionB.disabled) {
return 1;
}
return regionA.name > regionB.name ? 1 : -1;
})
.map((region) => {
return {
label: region.name,
value: region.$id,
leadingHtml: `<img src='${getFlagUrl(region.flag)}' alt='Region flag'/>`,
disabled: region.disabled
};
});
}
</script>

<svelte:head>
{#each regions as region}
<link rel="preload" as="image" href={getFlagUrl(region.flag)} />
{/each}
</svelte:head>
<form>
<Layout.Stack direction="column" gap="xxl">
{#if showTitle}
<Typography.Title size="l">Create your project</Typography.Title>
{/if}
<Layout.Stack direction="column" gap="xxl">
<Layout.Stack direction="column" gap="xxl">
<Layout.Stack direction="column" gap="s">
<Input.Text
label="Name"
placeholder="Project name"
required
bind:value={projectName} />
{#if !showCustomId}
<div>
<Tag
size="s"
on:click={() => {
showCustomId = true;
}}><Icon icon={IconPencil} /> Project ID</Tag>
</div>
{/if}
<CustomId
bind:show={showCustomId}
name="Project"
isProject
bind:id
fullWidth={true} />
</Layout.Stack>
{#if isCloud && regions.length > 0}
<Layout.Stack gap="xs"
><Input.Select
bind:value={region}
placeholder="Select a region"
options={getRegions()}
label="Region" />
<Typography.Text>Region cannot be changed after creation</Typography.Text>
</Layout.Stack>
{/if}
</Layout.Stack>
</Layout.Stack>
<Layout.Stack direction="row" justifyContent="flex-end"
><Button.Button type="button" variant="primary" size="s" on:click={createProject}>
Create</Button.Button>
</Layout.Stack>
</Layout.Stack>
</form>
104 changes: 11 additions & 93 deletions src/routes/(console)/onboarding/create-project/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<script lang="ts">
import { Card, Layout, Typography, Input, Tag, Icon, Button } from '@appwrite.io/pink-svelte';
import { IconPencil } from '@appwrite.io/pink-icons-svelte';
import { CustomId } from '$lib/components/index.js';
import { Card } from '@appwrite.io/pink-svelte';
import type { RegionList } from '$lib/sdk/billing';
import { onMount } from 'svelte';
import { isCloud } from '$lib/system';
import { sdk } from '$lib/stores/sdk';
import { isValueOfStringEnum } from '$lib/helpers/types';
import { Flag, ID, Region } from '@appwrite.io/console';
import Loading from './loading.svelte';
import { BillingPlan, Dependencies } from '$lib/constants';
Expand All @@ -15,27 +11,15 @@
import { base } from '$app/paths';
import { addNotification } from '$lib/stores/notifications';
import { tierToPlan } from '$lib/stores/billing';
import CreateProject from '$lib/layout/createProject.svelte';
let showCustomId = false;
let isLoading = false;
let id: string;
let startAnimation = false;
let projectName = '';
let region = Region.Default;
export let data: { regions: RegionList | null };
onMount(() => {
if (isCloud) {
if (data.regions) {
data.regions.regions.forEach((region) => fetch(getFlagUrl(region.flag)));
}
}
});
function getFlagUrl(countryCode: string) {
if (!isValueOfStringEnum(Flag, countryCode)) return '';
return sdk.forProject.avatars.getFlag(countryCode, 22, 15, 100)?.toString();
}
async function createProject() {
isLoading = true;
Expand Down Expand Up @@ -72,7 +56,7 @@
id ?? ID.unique(),
projectName,
teamId,
Region.Default
region
);
trackEvent(Submit.ProjectCreate, {
customId: !!id,
Expand All @@ -99,28 +83,6 @@
}
}
}
function getRegions() {
if (!data.regions) {
return;
}
return data.regions.regions
.filter((region) => region.$id !== 'default')
.sort((regionA, regionB) => {
if (regionA.disabled && !regionB.disabled) {
return 1;
}
return regionA.name > regionB.name ? 1 : -1;
})
.map((region) => {
return {
label: region.name,
value: region.$id,
leadingHtml: `<img src='${getFlagUrl(region.flag)}' alt='Region flag'/>`,
disabled: region.disabled
};
});
}
</script>

<svelte:head>
Expand All @@ -144,57 +106,13 @@
height="22"
class="u-only-dark"
alt="Appwrite Logo" />
<Card.Base variant="primary" padding="l"
><form>
<Layout.Stack direction="column" gap="xxl">
<Typography.Title size="l">Create your project</Typography.Title>

<Layout.Stack direction="column" gap="xxl">
<Layout.Stack direction="column" gap="xxl">
<Layout.Stack direction="column" gap="s">
<Input.Text
label="Name"
placeholder="Project name"
required
bind:value={projectName} />
{#if !showCustomId}
<div>
<Tag
size="s"
on:click={() => {
showCustomId = true;
}}><Icon icon={IconPencil} /> Project ID</Tag>
</div>
{/if}
<CustomId
bind:show={showCustomId}
name="Project"
isProject
bind:id
fullWidth={true} />
</Layout.Stack>
{#if data.regions}
<Layout.Stack gap="xs"
><Input.Select
placeholder="Select a region"
options={getRegions()}
label="Region" />
<Typography.Text
>Region cannot be changed after creation</Typography.Text>
</Layout.Stack>
{/if}
</Layout.Stack>
</Layout.Stack>
<Layout.Stack direction="row" justifyContent="flex-end"
><Button.Button
type="button"
variant="primary"
size="s"
on:click={createProject}>
Create</Button.Button>
</Layout.Stack>
</Layout.Stack>
</form></Card.Base>
<Card.Base variant="primary" padding="l">
<CreateProject
regions={data.regions.regions}
bind:projectName
bind:id
bind:region
{createProject} /></Card.Base>
{/if}
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@
IconUnity
} from '@appwrite.io/pink-icons-svelte';
import { getPlatformInfo } from '$lib/helpers/platform';
import CreateProjectCloud from './createProjectCloud.svelte';

export let data;

let addOrganization = false;
let showCreate = false;
let showCreateProjectCloud = false;

function allServiceDisabled(project: Models.Project): boolean {
let disabled = true;
Expand All @@ -66,7 +68,7 @@

function handleCreateProject() {
if (!$canWriteProjects) return;
if (isCloud) wizard.start(Create);
if (isCloud) showCreateProjectCloud = true;
else showCreate = true;
}

Expand Down Expand Up @@ -234,3 +236,6 @@

<CreateOrganization bind:show={addOrganization} />
<CreateProject bind:show={showCreate} teamId={$page.params.organization} />
{#if showCreateProjectCloud}
<CreateProjectCloud bind:showCreateProjectCloud regions={regions.regions} />
{/if}
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
<script lang="ts">
import { WizardWithSteps } from '$lib/layout';
import { sdk } from '$lib/stores/sdk';
import { onDestroy } from 'svelte';
import { addNotification } from '$lib/stores/notifications';
import Step1 from './wizard/step1.svelte';
import Step2 from './wizard/step2.svelte';
import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte';
import { goto, invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { page } from '$app/stores';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { ID, Region } from '@appwrite.io/console';
import { ID, Region as ConsoleRegion } from '@appwrite.io/console';
import { createProject } from './wizard/store';
import { wizard } from '$lib/stores/wizard';
import { base } from '$app/paths';
import CreateProject from '$lib/layout/createProject.svelte';
import { Modal } from '$lib/components';
import type { Region } from '$lib/sdk/billing';

const teamId = $page.params.organization;
export let regions: Array<Region> = [];
export let showCreateProjectCloud: boolean;

async function onFinish() {
await invalidate(Dependencies.FUNCTIONS);
Expand All @@ -28,7 +29,7 @@
$createProject?.id ?? ID.unique(),
$createProject.name,
teamId,
$createProject.region as Region
$createProject.region as ConsoleRegion
);
trackEvent(Submit.ProjectCreate, {
customId: !!$createProject?.id,
Expand All @@ -39,8 +40,8 @@
type: 'success',
message: `${$createProject.name} has been created`
});
await onFinish();
await goto(`${base}/project-${project.$id}`);
wizard.hide();
} catch (e) {
addNotification({
type: 'error',
Expand All @@ -57,20 +58,13 @@
region: 'fra'
};
});

const stepsComponents: WizardStepsType = new Map();
stepsComponents.set(1, {
label: 'Details',
component: Step1
});
stepsComponents.set(2, {
label: 'Region',
component: Step2
});
</script>

<WizardWithSteps
title="Create project"
steps={stepsComponents}
finalMethod={create}
on:exit={onFinish} />
<Modal bind:show={showCreateProjectCloud} title={'Create Project'}
><CreateProject
createProject={create}
showTitle={false}
bind:id={$createProject.id}
bind:projectName={$createProject.name}
bind:region={$createProject.region}
{regions} /></Modal>

This file was deleted.

Loading
Loading