mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' into 'supposed-improvements'.
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
PUBLIC_CONSOLE_MODE=self-hosted
|
||||
PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt
|
||||
PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt,index-lengths
|
||||
PUBLIC_APPWRITE_MULTI_REGION=false
|
||||
PUBLIC_APPWRITE_ENDPOINT=http://localhost/v1
|
||||
PUBLIC_STRIPE_KEY=
|
||||
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
"PUBLIC_CONSOLE_MODE=cloud"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt,index-lengths"
|
||||
"PUBLIC_APPWRITE_MULTI_REGION=true"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
"PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY_STAGE }}"
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
build-args: |
|
||||
"PUBLIC_CONSOLE_MODE=self-hosted"
|
||||
"PUBLIC_APPWRITE_MULTI_REGION=false"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt,index-lengths"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
|
||||
publish-cloud-no-regions:
|
||||
@@ -156,6 +156,6 @@ jobs:
|
||||
build-args: |
|
||||
"PUBLIC_CONSOLE_MODE=cloud"
|
||||
"PUBLIC_APPWRITE_MULTI_REGION=false"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt"
|
||||
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites,csv-import,attribute-encrypt,index-lengths"
|
||||
"PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY_STAGE }}"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
|
||||
@@ -190,83 +190,107 @@
|
||||
$currentPlan?.name.toLocaleLowerCase() !== selectedOrg?.tierName.toLocaleLowerCase()
|
||||
? $currentPlan.name
|
||||
: selectedOrg?.tierName; // fallback
|
||||
|
||||
$: derivedKey = `${selectedOrg?.$id}-${selectedProject?.$id}`;
|
||||
</script>
|
||||
|
||||
<svelte:window on:resize={onResize} />
|
||||
<div use:melt={$menubar}>
|
||||
{#if !$isSmallViewport}
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
use:melt={$triggerOrganizations}
|
||||
aria-label="Open organizations tab">
|
||||
<span class="orgName">{selectedOrg?.name ?? 'Organization'}</span>
|
||||
<span class="not-mobile"
|
||||
>{#if correctPlanName}<Badge
|
||||
variant="secondary"
|
||||
content={correctPlanName} />{/if}</span>
|
||||
<Icon icon={IconChevronDown} size="s" color="--fgcolor-neutral-secondary" />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
on:click={() => {
|
||||
organisationBottomSheetOpen = true;
|
||||
}}
|
||||
aria-label="Open organizations tab">
|
||||
<span class="orgName" class:noProjects={!currentProject}
|
||||
>{selectedOrg?.name ?? 'Organization'}</span>
|
||||
<span class="not-mobile"
|
||||
><Badge variant="secondary" content={correctPlanName ?? ''} /></span>
|
||||
<Icon icon={IconChevronDown} size="s" color="--fgcolor-neutral-secondary" />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div class="menu" use:melt={$menuOrganizations}>
|
||||
<Card.Base padding="xxxs" shadow={true}>
|
||||
{#if selectedOrg}
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor href={`${base}/organization-${selectedOrg?.$id}`}
|
||||
>Organization overview</ActionMenu.Item.Anchor
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{#if organizations.length > 1}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
{#key derivedKey}
|
||||
<div use:melt={$menubar}>
|
||||
{#if !$isSmallViewport}
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
use:melt={$triggerOrganizations}
|
||||
aria-label="Open organizations tab">
|
||||
<span class="orgName">{selectedOrg?.name ?? 'Organization'}</span>
|
||||
<span class="not-mobile"
|
||||
>{#if correctPlanName}<Badge
|
||||
variant="secondary"
|
||||
content={correctPlanName} />{/if}</span>
|
||||
<Icon icon={IconChevronDown} size="s" color="--fgcolor-neutral-secondary" />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
on:click={() => {
|
||||
organisationBottomSheetOpen = true;
|
||||
}}
|
||||
aria-label="Open organizations tab">
|
||||
<span class="orgName" class:noProjects={!currentProject}
|
||||
>{selectedOrg?.name ?? 'Organization'}</span>
|
||||
<span class="not-mobile"
|
||||
><Badge variant="secondary" content={correctPlanName ?? ''} /></span>
|
||||
<Icon icon={IconChevronDown} size="s" color="--fgcolor-neutral-secondary" />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div use:melt={$subTriggerOrganizations}>
|
||||
<div class="menu" use:melt={$menuOrganizations}>
|
||||
<Card.Base padding="xxxs" shadow={true}>
|
||||
{#if selectedOrg}
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button trailingIcon={IconChevronRight}
|
||||
>Switch organization</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor
|
||||
href={`${base}/organization-${selectedOrg?.$id}`}
|
||||
>Organization overview</ActionMenu.Item.Anchor
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
<div class="menu subMenu" use:melt={$subMenuOrganizations}>
|
||||
<Card.Base padding="xxxs" shadow={true}>
|
||||
<div use:melt={$radioGroupOrganizations}>
|
||||
{#each organizations as organization}
|
||||
{#if organizations.length > 1}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
|
||||
<div use:melt={$subTriggerOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button trailingIcon={IconChevronRight}
|
||||
>Switch organization</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</div>
|
||||
<div class="menu subMenu" use:melt={$subMenuOrganizations}>
|
||||
<Card.Base padding="xxxs" shadow={true}>
|
||||
<div use:melt={$radioGroupOrganizations}>
|
||||
{#each organizations as organization}
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor
|
||||
href={`${base}/organization-${organization?.$id}`}
|
||||
>{organization.name}</ActionMenu.Item.Anchor>
|
||||
</ActionMenu.Root>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor
|
||||
href={`${base}/organization-${organization?.$id}`}
|
||||
>{organization.name}</ActionMenu.Item.Anchor>
|
||||
</ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
leadingIcon={IconPlusSm}
|
||||
on:click={createOrg}
|
||||
>Create organization</ActionMenu.Item.Button
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
leadingIcon={IconPlusSm}
|
||||
on:click={createOrg}
|
||||
>Create organization</ActionMenu.Item.Button
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Base>
|
||||
</div>
|
||||
</Card.Base>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
leadingIcon={IconPlusSm}
|
||||
on:click={createOrg}>Create organization</ActionMenu.Item.Button
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#each organizations as organization}
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor
|
||||
href={`${base}/organization-${organization?.$id}`}
|
||||
>{organization.name}</ActionMenu.Item.Anchor
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
@@ -275,48 +299,30 @@
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#each organizations as organization}
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Anchor
|
||||
href={`${base}/organization-${organization?.$id}`}
|
||||
>{organization.name}</ActionMenu.Item.Anchor
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="separator" use:melt={$separatorOrganizations}></div>
|
||||
<div use:melt={$itemOrganizations}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button leadingIcon={IconPlusSm} on:click={createOrg}
|
||||
>Create organization</ActionMenu.Item.Button
|
||||
></ActionMenu.Root>
|
||||
</div>
|
||||
{/if}
|
||||
</Card.Base>
|
||||
</div>
|
||||
</Card.Base>
|
||||
</div>
|
||||
|
||||
{#if selectedOrg && currentProject}
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
{#if !$isSmallViewport}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
use:melt={$triggerProjects}
|
||||
aria-label="Open projects tab">
|
||||
<span class="projectName">{currentProject.name}</span>
|
||||
<Icon icon={IconChevronDown} size="s" />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
on:click={() => (projectsBottomSheetOpen = true)}
|
||||
aria-label="Open projects tab">
|
||||
<span class="projectName">{currentProject.name}</span>
|
||||
<Icon icon={IconChevronDown} size="s" />
|
||||
</button>
|
||||
{/if}
|
||||
{#if selectedOrg && currentProject}
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
{#if !$isSmallViewport}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
use:melt={$triggerProjects}
|
||||
aria-label="Open projects tab">
|
||||
<span class="projectName">{currentProject.name}</span>
|
||||
<Icon icon={IconChevronDown} size="s" />
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
type="button"
|
||||
class="trigger"
|
||||
on:click={() => (projectsBottomSheetOpen = true)}
|
||||
aria-label="Open projects tab">
|
||||
<span class="projectName">{currentProject.name}</span>
|
||||
<Icon icon={IconChevronDown} size="s" />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div class="menu" use:melt={$menuProjects}>
|
||||
<Card.Base padding="xxxs" shadow={true}>
|
||||
|
||||
@@ -27,37 +27,42 @@
|
||||
const importItems: Writable<ImportItemsMap> = writable(new Map());
|
||||
|
||||
async function showCompletionNotification(
|
||||
databaseId: string,
|
||||
collectionId: string,
|
||||
importData: Payload
|
||||
database: string,
|
||||
collection: string,
|
||||
payload: Payload
|
||||
) {
|
||||
await invalidate(Dependencies.DOCUMENTS);
|
||||
const url = `${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/collection-${collectionId}`;
|
||||
const isSuccess = payload.status === 'completed';
|
||||
const isError = !isSuccess && !!payload.errors;
|
||||
|
||||
// extract clean message from nested backend error.
|
||||
const match = importData.errors.join('').match(/message: '(.*)' Message:/i);
|
||||
const errorMessage = match?.[1];
|
||||
if (!isSuccess && !isError) return;
|
||||
|
||||
const type = importData.status === 'completed' ? 'success' : 'error';
|
||||
const message =
|
||||
importData.status === 'completed'
|
||||
? 'CSV import finished successfully.'
|
||||
: `${errorMessage}`;
|
||||
let errorMessage = 'Import failed. Check your CSV for correct fields and required values.';
|
||||
if (isError && Array.isArray(payload.errors)) {
|
||||
try {
|
||||
// the `errors` is a list of json encoded string.
|
||||
errorMessage = JSON.parse(payload.errors[0]).message;
|
||||
} catch {
|
||||
// do nothing, fallback to default message.
|
||||
}
|
||||
}
|
||||
|
||||
const type = isSuccess ? 'success' : 'error';
|
||||
const message = isError ? errorMessage : 'CSV import finished successfully.';
|
||||
const url = `${base}/project-${page.params.region}-${page.params.project}/databases/database-${database}/collection-${collection}`;
|
||||
|
||||
addNotification({
|
||||
type,
|
||||
message,
|
||||
isHtml: true,
|
||||
buttons:
|
||||
collectionId === page.params.collection || type === 'error'
|
||||
? undefined
|
||||
: [
|
||||
{
|
||||
name: 'View documents',
|
||||
method: () => goto(url)
|
||||
}
|
||||
]
|
||||
isSuccess && collection !== page.params.collection
|
||||
? [{ name: 'View documents', method: () => goto(url) }]
|
||||
: undefined
|
||||
});
|
||||
|
||||
if (isSuccess) {
|
||||
await invalidate(Dependencies.DOCUMENTS);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateOrAddItem(importData: Payload | Models.Migration) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
import { page } from '$app/state';
|
||||
import Card from '../card.svelte';
|
||||
import SkeletonRepoList from './skeletonRepoList.svelte';
|
||||
import { untrack } from 'svelte';
|
||||
import { onMount, untrack } from 'svelte';
|
||||
|
||||
let {
|
||||
action = $bindable('select'),
|
||||
@@ -46,6 +46,11 @@
|
||||
let search = $state('');
|
||||
let selectedInstallation = $state(null);
|
||||
let isLoadingRepositories = $state(null);
|
||||
let installationsMap = $state(null);
|
||||
|
||||
onMount(() => {
|
||||
loadInstallations();
|
||||
});
|
||||
|
||||
async function loadInstallations() {
|
||||
if (installationList) {
|
||||
@@ -59,7 +64,7 @@
|
||||
)
|
||||
);
|
||||
}
|
||||
return installationList.installations;
|
||||
installationsMap = installationList.installations;
|
||||
} else {
|
||||
const { installations } = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
@@ -70,7 +75,7 @@
|
||||
}
|
||||
installation.set(installations.find((entry) => entry.$id === selectedInstallation));
|
||||
}
|
||||
return installations;
|
||||
installationsMap = installations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +128,7 @@
|
||||
{#if hasInstallations}
|
||||
<Layout.Stack>
|
||||
<Layout.Stack gap="s">
|
||||
{#await loadInstallations()}
|
||||
{#if !installationsMap}
|
||||
<Layout.Stack direction="row">
|
||||
<InputSelect
|
||||
disabled
|
||||
@@ -137,12 +142,12 @@
|
||||
value={null} />
|
||||
<InputSearch placeholder="Search repositories" disabled />
|
||||
</Layout.Stack>
|
||||
{:then installations}
|
||||
{:else}
|
||||
<Layout.Stack direction={$isSmallViewport ? 'column' : 'row'}>
|
||||
<InputSelect
|
||||
id="installation"
|
||||
options={[
|
||||
...installations.map((entry) => {
|
||||
...installationsMap.map((entry) => {
|
||||
return {
|
||||
label: entry.organization,
|
||||
value: entry.$id
|
||||
@@ -160,7 +165,7 @@
|
||||
}
|
||||
search = '';
|
||||
installation.set(
|
||||
installations.find((entry) => entry.$id === selectedInstallation)
|
||||
installationsMap.find((entry) => entry.$id === selectedInstallation)
|
||||
);
|
||||
|
||||
isLoadingRepositories = true;
|
||||
@@ -174,7 +179,7 @@
|
||||
bind:value={search}
|
||||
disabled={!search && !$repositories?.repositories?.length} />
|
||||
</Layout.Stack>
|
||||
{/await}
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{#if selectedInstallation}
|
||||
<!-- manual installation change -->
|
||||
|
||||
+2
-1
@@ -21,5 +21,6 @@ function isFlagEnabled(name: string) {
|
||||
export const flags = {
|
||||
showSites: isFlagEnabled('sites'),
|
||||
showCsvImport: isFlagEnabled('csv-import'),
|
||||
showAttributeEncrypt: isFlagEnabled('attribute-encrypt')
|
||||
showAttributeEncrypt: isFlagEnabled('attribute-encrypt'),
|
||||
showIndexLengths: isFlagEnabled('index-lengths')
|
||||
};
|
||||
|
||||
@@ -107,7 +107,6 @@ function createPreferences() {
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
getCustomCollectionColumns: (collectionId: string): Preferences['columns'] => {
|
||||
return preferences?.collections?.[collectionId] ?? [];
|
||||
},
|
||||
|
||||
@@ -81,7 +81,8 @@ function createConsoleSdk(client: Client) {
|
||||
billing: new Billing(client),
|
||||
sources: new Sources(client),
|
||||
sites: new Sites(client),
|
||||
domains: new Domains(client)
|
||||
domains: new Domains(client),
|
||||
storage: new Storage(client)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@
|
||||
|
||||
let savedDefault = data.default;
|
||||
|
||||
let showEncrypt = flags.showAttributeEncrypt(page.data);
|
||||
const showEncrypt = flags.showAttributeEncrypt(page.data);
|
||||
|
||||
function handleDefaultState(hideDefault: boolean) {
|
||||
if (hideDefault) {
|
||||
|
||||
+1
-2
@@ -20,7 +20,6 @@
|
||||
const databaseId = page.params.database;
|
||||
const collectionId = page.params.collection;
|
||||
const documentId = page.params.document;
|
||||
const editing = true;
|
||||
|
||||
function initWork() {
|
||||
const prohibitedKeys = [
|
||||
@@ -124,7 +123,7 @@
|
||||
<svelte:fragment slot="title">{label}</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="aside">
|
||||
<AttributeItem {attribute} bind:formValues={$work} {label} {editing} />
|
||||
<AttributeItem {attribute} bind:formValues={$work} {label} editing />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
|
||||
+169
-107
@@ -1,24 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { PaginationInline } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Button, InputSelect } from '$lib/elements/forms';
|
||||
import { preferences } from '$lib/stores/preferences';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Query, type Models } from '@appwrite.io/console';
|
||||
import { onMount } from 'svelte';
|
||||
import { doc } from '../store';
|
||||
import { isRelationshipToMany } from './store';
|
||||
import { IconPlus, IconX } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
|
||||
|
||||
export let id: string;
|
||||
export let label: string;
|
||||
|
||||
export let editing = false;
|
||||
export let value: string | string[];
|
||||
export let attribute: Models.AttributeRelationship;
|
||||
export let optionalText: string | undefined = undefined;
|
||||
export let editing = false;
|
||||
|
||||
const databaseId = page.params.database;
|
||||
|
||||
@@ -28,6 +26,7 @@
|
||||
let relatedList: string[] = [];
|
||||
let singleRel: string;
|
||||
let showInput = false;
|
||||
let newItemValue: string = '';
|
||||
let limit = 10;
|
||||
let offset = 0;
|
||||
|
||||
@@ -39,6 +38,7 @@
|
||||
singleRel = value as string;
|
||||
}
|
||||
}
|
||||
|
||||
documentList = await getDocuments();
|
||||
|
||||
if (editing && $doc?.[attribute.key]) {
|
||||
@@ -59,20 +59,48 @@
|
||||
});
|
||||
|
||||
async function getDocuments(search: string = null) {
|
||||
if (search) {
|
||||
const documents = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.databases.listDocuments(databaseId, attribute.relatedCollection, [
|
||||
Query.startsWith('$id', search),
|
||||
Query.orderDesc('')
|
||||
]);
|
||||
return documents;
|
||||
const queries = search ? [Query.startsWith('$id', search), Query.orderDesc('')] : [];
|
||||
return await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.databases.listDocuments(databaseId, attribute.relatedCollection, queries);
|
||||
}
|
||||
|
||||
function getAvailableOptions(excludeIndex?: number) {
|
||||
return options?.filter((option) => {
|
||||
const otherItems =
|
||||
excludeIndex !== undefined
|
||||
? relatedList.filter((_, idx) => idx !== excludeIndex)
|
||||
: relatedList;
|
||||
return !otherItems.includes(option.value);
|
||||
});
|
||||
}
|
||||
|
||||
function updateRelatedList() {
|
||||
relatedList = relatedList;
|
||||
value = relatedList;
|
||||
}
|
||||
|
||||
function removeItem(index: number) {
|
||||
if (relatedList.length === 1) {
|
||||
relatedList[index] = '';
|
||||
} else {
|
||||
const documents = await sdk
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.databases.listDocuments(databaseId, attribute.relatedCollection);
|
||||
return documents;
|
||||
relatedList.splice(index, 1);
|
||||
}
|
||||
updateRelatedList();
|
||||
}
|
||||
|
||||
function addNewItem() {
|
||||
if (newItemValue) {
|
||||
relatedList = [...relatedList, newItemValue];
|
||||
value = relatedList;
|
||||
newItemValue = '';
|
||||
showInput = false;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelAddItem() {
|
||||
newItemValue = '';
|
||||
showInput = false;
|
||||
}
|
||||
|
||||
//Reactive statements
|
||||
@@ -84,106 +112,140 @@
|
||||
.reverse()
|
||||
.slice(offset, offset + limit)
|
||||
: [];
|
||||
$: total = relatedList?.length ?? 0;
|
||||
|
||||
$: totalCount = relatedList?.length ?? 0;
|
||||
|
||||
$: options =
|
||||
documentList?.documents?.map((n) => {
|
||||
const data = displayNames.filter((name) => name !== '$id').map((name) => n?.[name]);
|
||||
return {
|
||||
value: n.$id,
|
||||
label: n.$id,
|
||||
data
|
||||
};
|
||||
return { value: n.$id, label: n.$id, data };
|
||||
}) ?? [];
|
||||
|
||||
$: hasItems = totalCount > 0;
|
||||
$: showTopAddButton = !editing && totalCount === 0 && !showInput;
|
||||
$: showBottomAddButton =
|
||||
(!editing && hasItems && !showInput) ||
|
||||
(editing && hasItems && relatedList.every((item) => item) && !showInput);
|
||||
$: showEmptyInput = editing && totalCount === 0 && !showInput;
|
||||
</script>
|
||||
|
||||
{#if isRelationshipToMany(attribute)}
|
||||
<div class="u-width-full-line">
|
||||
<Layout.Stack direction="row" alignContent="space-between">
|
||||
<Layout.Stack gap="xxs" direction="row" alignItems="center">
|
||||
<Typography.Text variant="m-500">{label}</Typography.Text>
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-tertiary">
|
||||
{optionalText}
|
||||
</Typography.Text>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Layout.Stack gap="m">
|
||||
<Layout.Stack direction="row" alignContent="space-between">
|
||||
<Layout.Stack gap="xxs" direction="row" alignItems="center">
|
||||
<Typography.Text variant="m-500">{label}</Typography.Text>
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-tertiary">
|
||||
{optionalText}
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
|
||||
{#if showTopAddButton}
|
||||
<Button secondary on:click={() => (showInput = true)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add item
|
||||
</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{#if editing || total === 0}
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
showInput = true;
|
||||
}}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add item
|
||||
</Button>
|
||||
|
||||
<Layout.Stack gap="m">
|
||||
<!-- Empty input for editing mode when no items exist -->
|
||||
{#if showEmptyInput}
|
||||
<Layout.Stack direction="row">
|
||||
<InputSelect
|
||||
{id}
|
||||
required
|
||||
{options}
|
||||
bind:value={relatedList[0]}
|
||||
placeholder={`Select ${attribute.key}`}
|
||||
on:change={() => {
|
||||
if (!relatedList[0]) relatedList = [''];
|
||||
updateRelatedList();
|
||||
}} />
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Existing items in editing mode -->
|
||||
{#if editing && hasItems}
|
||||
{#each paginatedItems as _, paginatedIndex}
|
||||
{@const actualIndex = offset + paginatedIndex}
|
||||
<Layout.Stack direction="row">
|
||||
<InputSelect
|
||||
{id}
|
||||
required
|
||||
options={getAvailableOptions(actualIndex)}
|
||||
bind:value={relatedList[actualIndex]}
|
||||
placeholder={`Select ${attribute.key}`}
|
||||
on:change={updateRelatedList} />
|
||||
{#if relatedList[actualIndex]}
|
||||
<div style:padding-block-start="0.5rem">
|
||||
<Button
|
||||
icon
|
||||
extraCompact
|
||||
on:click={() => removeItem(actualIndex)}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<!-- Existing items in creation mode -->
|
||||
{#if !editing && hasItems}
|
||||
{#each relatedList as item, i}
|
||||
<Layout.Stack direction="row">
|
||||
<InputSelect
|
||||
{id}
|
||||
required
|
||||
options={getAvailableOptions(i)}
|
||||
bind:value={item}
|
||||
on:change={updateRelatedList} />
|
||||
<div style:padding-block-start="0.5rem">
|
||||
<Button
|
||||
icon
|
||||
extraCompact
|
||||
ariaLabel={`Delete item ${i}`}
|
||||
on:click={() => {
|
||||
relatedList.splice(i, 1);
|
||||
updateRelatedList();
|
||||
}}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<!-- Input for adding new items -->
|
||||
{#if showInput}
|
||||
<Layout.Stack direction="row">
|
||||
<InputSelect
|
||||
{id}
|
||||
required
|
||||
placeholder={`Select ${attribute.key}`}
|
||||
bind:value={newItemValue}
|
||||
options={getAvailableOptions()}
|
||||
on:change={addNewItem} />
|
||||
<div style:padding-block-start="0.5rem">
|
||||
<Button icon extraCompact on:click={cancelAddItem}>
|
||||
<Icon icon={IconX} size="s" />
|
||||
</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
{#if showBottomAddButton}
|
||||
<Layout.Stack direction="row" alignContent="flex-start">
|
||||
<Button extraCompact on:click={() => (showInput = true)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add item
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<ul class="u-flex-vertical u-gap-4 u-margin-block-start-4">
|
||||
{#if !editing && relatedList?.length}
|
||||
{#each relatedList as item, i}
|
||||
<InputSelect {id} required bind:value={item} {options} />
|
||||
<Button
|
||||
extraCompact
|
||||
ariaLabel={`Delete item ${i}`}
|
||||
on:click={() => {
|
||||
relatedList.splice(i, 1);
|
||||
relatedList = relatedList;
|
||||
value = relatedList;
|
||||
}}>
|
||||
<span class="icon-x" aria-hidden="true"></span>
|
||||
</Button>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
{#if showInput}
|
||||
<InputSelect
|
||||
{id}
|
||||
label="Rel"
|
||||
required
|
||||
placeholder={`Select ${attribute.key}`}
|
||||
bind:value={relatedList[total]}
|
||||
options={options?.filter((n) => !relatedList.includes(n.value))}
|
||||
on:change={() => {
|
||||
value = relatedList;
|
||||
showInput = false;
|
||||
}} />
|
||||
<Button extraCompact ariaLabel={`Hide input`} on:click={() => (showInput = false)}>
|
||||
<span class="icon-x" aria-hidden="true"></span>
|
||||
</Button>
|
||||
{/if}
|
||||
{#if paginatedItems && editing}
|
||||
{#each paginatedItems as item, i}
|
||||
<InputSelect {id} label="Rel" required bind:value={item} {options} />
|
||||
<Button
|
||||
extraCompact
|
||||
ariaLabel={`Delete item ${i}`}
|
||||
on:click={() => {
|
||||
relatedList.splice(i, 1);
|
||||
relatedList = relatedList;
|
||||
value = relatedList;
|
||||
}}>
|
||||
<span class="icon-x" aria-hidden="true"></span>
|
||||
</Button>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
{#if editing}
|
||||
<div class="u-flex u-margin-block-start-32 u-main-space-between">
|
||||
<p class="text">Total results: {total}</p>
|
||||
<PaginationInline {limit} bind:offset {total} hidePages />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if total > 0 && !editing}
|
||||
<Button
|
||||
extraCompact
|
||||
disabled={showInput}
|
||||
on:click={() => {
|
||||
showInput = true;
|
||||
}}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add item
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<InputSelect
|
||||
{id}
|
||||
|
||||
+4
-1
@@ -14,6 +14,7 @@
|
||||
import { type Attributes, collection, indexes } from '../store';
|
||||
import { Icon, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import { flags } from '$lib/flags';
|
||||
|
||||
export let showCreateIndex = false;
|
||||
export let externalAttribute: Attributes = null;
|
||||
@@ -38,6 +39,8 @@
|
||||
|
||||
let attributeList = [{ value: '', order: '', length: null }];
|
||||
|
||||
const showLengths = flags.showIndexLengths(page.data);
|
||||
|
||||
function generateIndexKey() {
|
||||
let indexKeys = $indexes.map((index) => index.key);
|
||||
|
||||
@@ -149,7 +152,7 @@
|
||||
placeholder="Select Order" />
|
||||
|
||||
<Layout.Stack direction="row" alignItems="flex-end" gap="xs">
|
||||
{#if selectedType === IndexType.Key}
|
||||
{#if selectedType === IndexType.Key && showLengths}
|
||||
<InputNumber
|
||||
id={`length-${i}`}
|
||||
label={i === 0 ? 'Length' : undefined}
|
||||
|
||||
+12
-6
@@ -3,9 +3,13 @@
|
||||
import { InputText } from '$lib/elements/forms';
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { page } from '$app/state';
|
||||
import { flags } from '$lib/flags';
|
||||
|
||||
export let showOverview = false;
|
||||
export let selectedIndex: Models.Index = null;
|
||||
|
||||
const showLengths = flags.showIndexLengths(page.data);
|
||||
</script>
|
||||
|
||||
<Modal title="Overview" bind:show={showOverview}>
|
||||
@@ -39,12 +43,14 @@
|
||||
id={`value-${selectedIndex.orders[i]}`}
|
||||
value={selectedIndex.orders[i]}
|
||||
readonly />
|
||||
<InputText
|
||||
required
|
||||
label={i === 0 ? 'Length' : ''}
|
||||
id={`value-${selectedIndex.lengths[i]}`}
|
||||
value={selectedIndex.lengths[i]?.toString() ?? null}
|
||||
readonly />
|
||||
{#if showLengths}
|
||||
<InputText
|
||||
required
|
||||
label={i === 0 ? 'Length' : ''}
|
||||
id={`value-${selectedIndex.lengths[i]}`}
|
||||
value={selectedIndex.lengths[i]?.toString() ?? null}
|
||||
readonly />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
+79
-74
@@ -33,6 +33,7 @@
|
||||
import { toLocaleDateTime } from '$lib/helpers/date';
|
||||
import DualTimeView from '$lib/components/dualTimeView.svelte';
|
||||
import { flags } from '$lib/flags';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
const databaseId = page.params.database;
|
||||
@@ -169,7 +170,7 @@
|
||||
|
||||
let checked = false;
|
||||
|
||||
let showEncrypt = flags.showAttributeEncrypt(data);
|
||||
const showEncrypt = flags.showAttributeEncrypt(data);
|
||||
</script>
|
||||
|
||||
<Table.Root
|
||||
@@ -205,85 +206,89 @@
|
||||
|
||||
{#each $columns as { id } (id)}
|
||||
{@const attr = $attributes.find((n) => n.key === id)}
|
||||
<Table.Cell column={id} {root}>
|
||||
{#if isRelationship(attr)}
|
||||
{@const args = displayNames?.[attr.relatedCollection] ?? ['$id']}
|
||||
{#if !isRelationshipToMany(attr)}
|
||||
{#if document[id]}
|
||||
{@const related = document[id]}
|
||||
<Link.Button
|
||||
variant="muted"
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
goto(
|
||||
`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/collection-${attr.relatedCollection}/document-${related.$id}`
|
||||
);
|
||||
}}>
|
||||
{#each args as arg, i}
|
||||
{#if arg !== undefined}
|
||||
{#if i}
|
||||
|
|
||||
{#if attr}
|
||||
<Table.Cell column={id} {root}>
|
||||
{#if isRelationship(attr)}
|
||||
{@const args = displayNames?.[attr.relatedCollection] ?? ['$id']}
|
||||
{#if !isRelationshipToMany(attr)}
|
||||
{#if document[id]}
|
||||
{@const related = document[id]}
|
||||
<Link.Button
|
||||
variant="muted"
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
goto(
|
||||
`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}/collection-${attr.relatedCollection}/document-${related.$id}`
|
||||
);
|
||||
}}>
|
||||
{#each args as arg, i}
|
||||
{#if arg !== undefined}
|
||||
{#if i}
|
||||
|
|
||||
{/if}
|
||||
<span class="text" data-private>
|
||||
{related?.[arg]}
|
||||
</span>
|
||||
{/if}
|
||||
<span class="text" data-private>
|
||||
{related?.[arg]}
|
||||
</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</Link.Button>
|
||||
{/each}
|
||||
</Link.Button>
|
||||
{:else}
|
||||
<span class="text">n/a</span>
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="text">n/a</span>
|
||||
{@const itemsNum = document[id]?.length}
|
||||
<Button.Button
|
||||
variant="extra-compact"
|
||||
disabled={!itemsNum}
|
||||
badge={itemsNum ?? 0}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
relationshipData = document[id];
|
||||
showRelationships = true;
|
||||
selectedRelationship = attr;
|
||||
}}>
|
||||
Items
|
||||
</Button.Button>
|
||||
{/if}
|
||||
{:else}
|
||||
{@const itemsNum = document[id]?.length}
|
||||
<Button.Button
|
||||
variant="extra-compact"
|
||||
disabled={!itemsNum}
|
||||
badge={itemsNum ?? 0}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
relationshipData = document[id];
|
||||
showRelationships = true;
|
||||
selectedRelationship = attr;
|
||||
}}>
|
||||
Items
|
||||
</Button.Button>
|
||||
{/if}
|
||||
{:else}
|
||||
{@const formatted = formatColumn(document[id])}
|
||||
{@const isDatetimeAttribute = attr.type === 'datetime'}
|
||||
{#if isDatetimeAttribute}
|
||||
<DualTimeView time={formatted.whole}>
|
||||
<span slot="title">Timestamp</span>
|
||||
{toLocaleDateTime(formatted.whole, true, 'UTC')}
|
||||
</DualTimeView>
|
||||
{:else if isString(attr) && attr.encrypt && showEncrypt}
|
||||
<button on:click={(e) => e.preventDefault()}>
|
||||
<InteractiveText
|
||||
copy={false}
|
||||
variant="secret"
|
||||
isVisible={false}
|
||||
text={formatted.value} />
|
||||
</button>
|
||||
{:else if formatted.truncated}
|
||||
<Tooltip placement="bottom" disabled={!formatted.truncated}>
|
||||
{@const datetime = document[id]}
|
||||
{@const formatted = formatColumn(document[id])}
|
||||
{@const isDatetimeAttribute = attr.type === 'datetime'}
|
||||
{@const isEncryptedAttribute = isString(attr) && attr.encrypt}
|
||||
{#if isDatetimeAttribute}
|
||||
<DualTimeView time={datetime}>
|
||||
<span slot="title">Timestamp</span>
|
||||
{toLocaleDateTime(datetime, true)}
|
||||
</DualTimeView>
|
||||
{:else if isEncryptedAttribute && showEncrypt}
|
||||
<button on:click={(e) => e.preventDefault()}>
|
||||
<InteractiveText
|
||||
copy={false}
|
||||
variant="secret"
|
||||
isVisible={false}
|
||||
text={formatted.value} />
|
||||
</button>
|
||||
{:else if formatted.truncated}
|
||||
<Tooltip placement="bottom" disabled={!formatted.truncated}>
|
||||
<Typography.Text truncate>{formatted.value}</Typography.Text>
|
||||
<span
|
||||
let:showing
|
||||
slot="tooltip"
|
||||
style:white-space="pre-wrap"
|
||||
style:word-break="break-all">
|
||||
{#if showing}
|
||||
{formatted.whole}
|
||||
{/if}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<Typography.Text truncate>{formatted.value}</Typography.Text>
|
||||
<span
|
||||
let:showing
|
||||
slot="tooltip"
|
||||
style:white-space="pre-wrap"
|
||||
style:word-break="break-all">
|
||||
{#if showing}
|
||||
{formatted.whole}
|
||||
{/if}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{:else}
|
||||
<Typography.Text truncate>{formatted.value}</Typography.Text>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
</Table.Cell>
|
||||
{/if}
|
||||
{/each}
|
||||
<Table.Cell column="$created" {root}>
|
||||
<DualTimeView time={document.$createdAt} />
|
||||
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Card, SvgIcon } from '$lib/components';
|
||||
import { Icon, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { Icon, Layout, Skeleton, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { IconGithub, IconGitBranch } from '@appwrite.io/pink-icons-svelte';
|
||||
import type { Models, Runtime } from '@appwrite.io/console';
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
export let rootDir: string = undefined;
|
||||
export let showGitData = true;
|
||||
export let runtimes: Models.RuntimeList;
|
||||
export let loading = false;
|
||||
|
||||
$: selectedRuntime = runtimes?.runtimes.find((r) => r.$id === runtime);
|
||||
</script>
|
||||
@@ -18,7 +19,7 @@
|
||||
<Layout.Stack gap="xl">
|
||||
<slot />
|
||||
<Layout.Stack gap="l">
|
||||
{#if selectedRuntime?.name}
|
||||
{#if selectedRuntime?.name && !loading}
|
||||
<Layout.Stack gap="xxxs">
|
||||
<Typography.Caption variant="400">Runtime</Typography.Caption>
|
||||
<Layout.Stack gap="xxs" alignItems="center" direction="row">
|
||||
@@ -30,6 +31,11 @@
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
{:else if loading}
|
||||
<Layout.Stack gap="xs">
|
||||
<Skeleton variant="line" width={100} height={16} />
|
||||
<Skeleton variant="line" width="100%" height={20} />
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
{#if showGitData}
|
||||
{#if repositoryName}
|
||||
|
||||
+29
-14
@@ -7,7 +7,7 @@
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { IconPencil } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Fieldset, Icon, Input, Layout, Tag } from '@appwrite.io/pink-svelte';
|
||||
import { Fieldset, Icon, Input, Layout, Skeleton, Tag } from '@appwrite.io/pink-svelte';
|
||||
import type { ComponentType } from 'svelte';
|
||||
|
||||
export let name: string;
|
||||
@@ -25,6 +25,7 @@
|
||||
value: string;
|
||||
label: string;
|
||||
}[] = [];
|
||||
export let loading = false;
|
||||
|
||||
let showCustomId = false;
|
||||
</script>
|
||||
@@ -51,13 +52,20 @@
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{#key runtime}
|
||||
<InputSelect
|
||||
id="runtime"
|
||||
label="Runtime"
|
||||
placeholder="Select runtime"
|
||||
bind:value={runtime}
|
||||
required
|
||||
{options} />
|
||||
{#if loading}
|
||||
<Layout.Stack gap="xs">
|
||||
<Skeleton variant="line" width={100} height={20} />
|
||||
<Skeleton variant="line" width="100%" height={32} />
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<InputSelect
|
||||
id="runtime"
|
||||
label="Runtime"
|
||||
placeholder="Select runtime"
|
||||
bind:value={runtime}
|
||||
required
|
||||
{options} />
|
||||
{/if}
|
||||
{/key}
|
||||
|
||||
{#if isCloud}
|
||||
@@ -79,12 +87,19 @@
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
{#if showEntrypoint}
|
||||
<InputText
|
||||
label="Entrypoint"
|
||||
id="entrypoint"
|
||||
bind:value={entrypoint}
|
||||
required
|
||||
placeholder="Enter entrypoint" />
|
||||
{#if loading}
|
||||
<Layout.Stack gap="xs">
|
||||
<Skeleton variant="line" width={100} height={20} />
|
||||
<Skeleton variant="line" width="100%" height={32} />
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<InputText
|
||||
label="Entrypoint"
|
||||
id="entrypoint"
|
||||
bind:value={entrypoint}
|
||||
required
|
||||
placeholder="Enter entrypoint" />
|
||||
{/if}
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
|
||||
+33
-3
@@ -10,7 +10,7 @@
|
||||
import { installation, repository } from '$lib/stores/vcs';
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { ID, Runtime, VCSDeploymentType } from '@appwrite.io/console';
|
||||
import { ID, Runtime, VCSDeploymentType, VCSDetectionType } from '@appwrite.io/console';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { onMount } from 'svelte';
|
||||
import Details from '../(components)/details.svelte';
|
||||
@@ -57,12 +57,40 @@
|
||||
let silentMode = false;
|
||||
let specification = specificationOptions[0].value;
|
||||
|
||||
let detectingRuntime = true;
|
||||
|
||||
onMount(async () => {
|
||||
installation.set(data.installation);
|
||||
repository.set(data.repository);
|
||||
name = data.repository.name;
|
||||
|
||||
await detectRuntime();
|
||||
});
|
||||
|
||||
async function detectRuntime() {
|
||||
try {
|
||||
detectingRuntime = true;
|
||||
|
||||
const detections = (await sdk
|
||||
.forProject(page.params.regionn, page.params.project)
|
||||
.vcs.createRepositoryDetection(
|
||||
data.installation.$id,
|
||||
page.params.repository,
|
||||
VCSDetectionType.Runtime
|
||||
)) as unknown as Models.DetectionRuntime; /* SDK return type is wrong atm */
|
||||
|
||||
entrypoint = detections.entrypoint;
|
||||
buildCommand = detections.commands;
|
||||
runtime = detections.runtime as Runtime;
|
||||
|
||||
trackEvent(Submit.FrameworkDetect, { runtime, source: 'repository' });
|
||||
} catch (error) {
|
||||
trackError(error, Submit.FrameworkDetect);
|
||||
} finally {
|
||||
detectingRuntime = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function create() {
|
||||
try {
|
||||
const func = await sdk
|
||||
@@ -154,7 +182,8 @@
|
||||
bind:specification
|
||||
{specificationOptions}
|
||||
options={runtimeOptions}
|
||||
showEntrypoint />
|
||||
showEntrypoint
|
||||
loading={detectingRuntime} />
|
||||
|
||||
<ProductionBranchFieldset
|
||||
bind:branch
|
||||
@@ -173,7 +202,8 @@
|
||||
runtimes={data.runtimesList}
|
||||
repositoryName={data.repository.name}
|
||||
{branch}
|
||||
{rootDir} />
|
||||
{rootDir}
|
||||
loading={detectingRuntime} />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
|
||||
+8
-8
@@ -3,17 +3,17 @@ import { sdk } from '$lib/stores/sdk';
|
||||
export const load = async ({ parent, params, url }) => {
|
||||
const { installations, runtimesList, specificationsList } = await parent();
|
||||
|
||||
const [repository] = await Promise.all([
|
||||
sdk
|
||||
.forProject(params.region, params.project)
|
||||
.vcs.getRepository(url.searchParams.get('installation'), params.repository)
|
||||
]);
|
||||
const repository = await sdk
|
||||
.forProject(params.region, params.project)
|
||||
.vcs.getRepository(url.searchParams.get('installation'), params.repository);
|
||||
|
||||
const installation = installations.installations.find(
|
||||
(installation) => installation.$id === url.searchParams.get('installation')
|
||||
);
|
||||
|
||||
return {
|
||||
installation,
|
||||
installations,
|
||||
installation: installations.installations.find(
|
||||
(installation) => installation.$id === url.searchParams.get('installation')
|
||||
),
|
||||
repository,
|
||||
runtimesList,
|
||||
specificationsList
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@
|
||||
<div class="u-flex u-gap-16">
|
||||
<div class="u-cross-child-center u-line-height-1-5">
|
||||
<h6 class="u-bold">{$platform.name}</h6>
|
||||
<p>{$platform.hostname}</p>
|
||||
<p>{$platform.hostname || $platform.key}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
|
||||
+57
-56
@@ -91,11 +91,11 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.
|
||||
});
|
||||
</script>
|
||||
|
||||
<Wizard title="Add Android platform" bind:showExitModal confirmExit>
|
||||
<Form onSubmit={createAndroidPlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
{#if !isPlatformCreated}
|
||||
<Wizard title="Add Android platform" bind:showExitModal confirmExit={!isPlatformCreated}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
{#if !isPlatformCreated}
|
||||
<Form onSubmit={createAndroidPlatform}>
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
@@ -136,59 +136,60 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconAndroid} />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconAndroid} />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. Clone the starter kit from GitHub using the terminal or Android
|
||||
Studio.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode
|
||||
size="s"
|
||||
code="data/repository/AppwriteRepository.kt" /> and update the configuration
|
||||
settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="kotlin" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or emulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. If you're starting a new project, you can clone our starter kit from
|
||||
GitHub using the terminal, VSCode or Android Studio.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode
|
||||
size="s"
|
||||
code="data/repository/AppwriteRepository.kt" /> and update the configuration
|
||||
settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="kotlin" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or emulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
<svelte:fragment slot="aside">
|
||||
<Card padding="l" class="responsive-padding">
|
||||
<Layout.Stack gap="xxl">
|
||||
|
||||
+109
-104
@@ -102,116 +102,121 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj
|
||||
});
|
||||
</script>
|
||||
|
||||
<Wizard title="Add Apple platform" bind:showExitModal confirmExit>
|
||||
<Form onSubmit={createApplePlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Grid gap="l" rowGap="l" columns={4} columnsXS={2}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
<Wizard title="Add Apple platform" bind:showExitModal confirmExit={!isPlatformCreated}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Form onSubmit={createApplePlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Grid gap="l" rowGap="l" columns={4} columnsXS={2}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder="My Apple App"
|
||||
required
|
||||
bind:value={$createPlatform.name} />
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder="My Apple App"
|
||||
required
|
||||
bind:value={$createPlatform.name} />
|
||||
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
<InputText
|
||||
id="hostname"
|
||||
label="Bundle ID"
|
||||
placeholder="com.company.appname"
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
You can find your Bundle Identifier in the General tab for
|
||||
your app's primary target in Xcode.
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
</Layout.Stack>
|
||||
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
!$createPlatform.key ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconApple} />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
<InputText
|
||||
id="hostname"
|
||||
label="Bundle ID"
|
||||
placeholder="com.company.appname"
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
You can find your Bundle Identifier in the General tab
|
||||
for your app's primary target in Xcode.
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. Clone the starter kit from GitHub using the terminal or XCode.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode size="s" code="Sources/Config.plist" /> and
|
||||
update the configuration settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="plaintext" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
!$createPlatform.key ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconApple} />
|
||||
<Typography.Text
|
||||
variant="m-400"
|
||||
color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. If you're starting a new project, you can clone our starter kit from
|
||||
GitHub using the terminal or XCode.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode size="s" code="Sources/Config.plist" /> and update
|
||||
the configuration settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="plaintext" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="aside">
|
||||
<Card padding="l" class="responsive-padding">
|
||||
<Layout.Stack gap="xxl">
|
||||
|
||||
+124
-120
@@ -161,133 +161,137 @@ static const String APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.reg
|
||||
});
|
||||
</script>
|
||||
|
||||
<Wizard title="Add Flutter platform" bind:showExitModal confirmExit>
|
||||
<Form onSubmit={createFlutterPlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Grid gap="l" rowGap="l" columns={3} columnsXS={2} columnsXXS={1}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
<Wizard title="Add Flutter platform" bind:showExitModal confirmExit={!isPlatformCreated}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Form onSubmit={createFlutterPlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Grid gap="l" rowGap="l" columns={3} columnsXS={2} columnsXXS={1}>
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder={placeholder[platform].name}
|
||||
required
|
||||
bind:value={$createPlatform.name} />
|
||||
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
{#if platform === PlatformType.Flutterweb}
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="hostname"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder={placeholder[platform].name}
|
||||
required
|
||||
bind:value={$createPlatform.hostname}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
{:else}
|
||||
<InputText
|
||||
id="key"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
bind:value={$createPlatform.name} />
|
||||
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
(!$createPlatform.key && !$createPlatform.hostname) ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconFlutter} />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
{#if platform === PlatformType.Flutterweb}
|
||||
<InputText
|
||||
id="hostname"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
required
|
||||
bind:value={$createPlatform.hostname}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
{:else}
|
||||
<InputText
|
||||
id="key"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
(!$createPlatform.key && !$createPlatform.hostname) ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. Clone the starter kit from GitHub using the terminal, Android Studio
|
||||
or VSCode.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode
|
||||
size="s"
|
||||
code="lib/constants/appwrite.dart" /> and update the configuration settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="dart" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconFlutter} />
|
||||
<Typography.Text
|
||||
variant="m-400"
|
||||
color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.hostname ||
|
||||
$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. If you're starting a new project, you can clone our starter kit from
|
||||
GitHub using the terminal, VSCode or Android Studio.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode size="s" code="lib/constants/appwrite.dart" />
|
||||
and update the configuration settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="dart" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="aside">
|
||||
<Card padding="l" class="responsive-padding">
|
||||
<Layout.Stack gap="xxl">
|
||||
|
||||
+113
-109
@@ -25,7 +25,6 @@
|
||||
import ConnectionLine from './components/ConnectionLine.svelte';
|
||||
import OnboardingPlatformCard from './components/OnboardingPlatformCard.svelte';
|
||||
import { PlatformType } from '@appwrite.io/console';
|
||||
import { isCloud } from '$lib/system';
|
||||
|
||||
let showExitModal = false;
|
||||
let isPlatformCreated = false;
|
||||
@@ -36,10 +35,8 @@
|
||||
const gitCloneCode =
|
||||
'\ngit clone https://github.com/appwrite/starter-for-react-native\ncd starter-for-react-native\n';
|
||||
|
||||
const updateConfigCode = isCloud
|
||||
? `const APPWRITE_PROJECT_ID = "${projectId}";`
|
||||
: `const APPWRITE_PROJECT_ID = "${projectId}";
|
||||
const APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}";
|
||||
const updateConfigCode = `const EXPO_PUBLIC_APPWRITE_PROJECT_ID = "${projectId}";
|
||||
const EXPO_PUBLIC_APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}";
|
||||
`;
|
||||
|
||||
export let platform: PlatformType = PlatformType.Reactnativeandroid;
|
||||
@@ -129,116 +126,123 @@ const APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page.para
|
||||
});
|
||||
</script>
|
||||
|
||||
<Wizard title="Add React Native platform" bind:showExitModal confirmExit>
|
||||
<Form onSubmit={createReactNativePlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Stack gap="l" direction="row">
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Stack>
|
||||
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder={placeholder[platform].name}
|
||||
required
|
||||
bind:value={$createPlatform.name} />
|
||||
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
<InputText
|
||||
id="hostname"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
</Layout.Stack>
|
||||
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
!$createPlatform.key ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconReact} />
|
||||
<Typography.Text variant="m-400" color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
<Wizard title="Add React Native platform" bind:showExitModal confirmExit={!isPlatformCreated}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<Form onSubmit={createReactNativePlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
<Layout.Stack gap="l" direction="row">
|
||||
{#each Object.entries(platforms) as [key, value]}
|
||||
<Pink2Card.Selector
|
||||
{value}
|
||||
id={key}
|
||||
title={key}
|
||||
imageRadius="s"
|
||||
name="framework"
|
||||
bind:group={platform}
|
||||
disabled={isCreatingPlatform || isPlatformCreated} />
|
||||
{/each}
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. Clone the starter kit from GitHub using the terminal or VSCode.
|
||||
</Typography.Text>
|
||||
<!-- Step Two -->
|
||||
{#if !isPlatformCreated}
|
||||
<Fieldset legend="Details">
|
||||
<Layout.Stack gap="l" alignItems="flex-end">
|
||||
<Layout.Stack gap="s">
|
||||
<InputText
|
||||
id="name"
|
||||
label="Name"
|
||||
placeholder={placeholder[platform].name}
|
||||
required
|
||||
bind:value={$createPlatform.name} />
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
<!-- Tooltips on InputText don't work as of now -->
|
||||
<InputText
|
||||
id="hostname"
|
||||
label={hostname[platform]}
|
||||
placeholder={placeholder[platform].hostname}
|
||||
required
|
||||
bind:value={$createPlatform.key}>
|
||||
<Tooltip slot="info" maxWidth="15rem">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Typography.Caption variant="400" slot="tooltip">
|
||||
{placeholder[platform].tooltip}
|
||||
</Typography.Caption>
|
||||
</Tooltip>
|
||||
</InputText>
|
||||
</Layout.Stack>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Open the file <InlineCode
|
||||
<Button
|
||||
fullWidthMobile
|
||||
size="s"
|
||||
code="lib/constants/appwrite.js" /> and update the configuration settings.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="javascript" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
submit
|
||||
forceShowLoader
|
||||
submissionLoader={isCreatingPlatform}
|
||||
disabled={!platform ||
|
||||
!$createPlatform.name ||
|
||||
!$createPlatform.key ||
|
||||
isCreatingPlatform}>
|
||||
Create platform
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{:else}
|
||||
<Layout.Stack gap="xxl">
|
||||
<Card padding="s" radius="s">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
gap="xs">
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Icon size="m" icon={IconReact} />
|
||||
<Typography.Text
|
||||
variant="m-400"
|
||||
color="--fgcolor-neutral-primary">
|
||||
{$createPlatform.name} ({$createPlatform.key})
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. If you're starting a new project, you can clone our starter kit from
|
||||
GitHub using the terminal or VSCode.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={gitCloneCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Add your Appwrite credentials to <InlineCode
|
||||
size="s"
|
||||
code=".env.example" /> then rename it to <InlineCode
|
||||
size="s"
|
||||
code=".env" /> if needed.</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="javascript" lineNumbers code={updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Run the app on a connected device or simulator, then click the <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="aside">
|
||||
<Card padding="l" class="responsive-padding">
|
||||
<Layout.Stack gap="xxl">
|
||||
|
||||
+136
-141
@@ -199,155 +199,150 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p
|
||||
});
|
||||
</script>
|
||||
|
||||
<Wizard title="Add web platform" bind:showExitModal>
|
||||
<Form onSubmit={createWebPlatform}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
{#if !isPlatformCreated || isChangingFramework}
|
||||
<Fieldset legend="Type">
|
||||
<Layout.Stack>
|
||||
<div class="frameworks">
|
||||
{#each frameworks as framework}
|
||||
<Card.Selector
|
||||
bind:group={selectedFrameworkKey}
|
||||
name="framework"
|
||||
id={framework.key}
|
||||
value={framework.key}
|
||||
title={framework.label}
|
||||
icon={framework.icon}
|
||||
imageRadius="s" />
|
||||
{/each}
|
||||
</div>
|
||||
<Wizard title="Add web platform" bind:showExitModal confirmExit={!isPlatformCreated}>
|
||||
<Layout.Stack gap="xxl">
|
||||
<!-- Step One -->
|
||||
{#if !isPlatformCreated || isChangingFramework}
|
||||
<Form onSubmit={createWebPlatform}>
|
||||
<Layout.Stack>
|
||||
<Fieldset legend="Type">
|
||||
<Layout.Stack>
|
||||
<div class="frameworks">
|
||||
{#each frameworks as framework}
|
||||
<Card.Selector
|
||||
bind:group={selectedFrameworkKey}
|
||||
name="framework"
|
||||
id={framework.key}
|
||||
value={framework.key}
|
||||
title={framework.label}
|
||||
icon={framework.icon}
|
||||
imageRadius="s" />
|
||||
{/each}
|
||||
</div>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
{#if isChangingFramework}
|
||||
<Button
|
||||
disabled={!selectedFramework}
|
||||
on:click={() => (isChangingFramework = false)}>
|
||||
Save</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{#if !isChangingFramework}
|
||||
<Fieldset legend="Details">
|
||||
<InputText
|
||||
id="hostname"
|
||||
label="Hostname"
|
||||
placeholder="localhost"
|
||||
error={hostnameError && 'Please enter a valid hostname'}
|
||||
bind:value={hostname}>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
The hostname that your website will use to interact with the
|
||||
Appwrite APIs in production or development environments. No
|
||||
protocol or port number required.
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputText></Fieldset>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
{#if isChangingFramework}
|
||||
<Button
|
||||
disabled={!selectedFramework}
|
||||
on:click={() => (isChangingFramework = false)}>
|
||||
Save</Button>
|
||||
{/if}
|
||||
<Button submit disabled={!selectedFramework}>Create platform</Button>
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
{:else}
|
||||
<Card.Base padding="s"
|
||||
><Layout.Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Layout.Stack gap="xxs" direction="row">
|
||||
<Icon icon={selectedFramework.smallIcon} />
|
||||
<Typography.Text variant="m-500">{selectedFramework.label}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
{#if !isChangingFramework}
|
||||
<Fieldset legend="Details">
|
||||
<InputText
|
||||
id="hostname"
|
||||
label="Hostname"
|
||||
placeholder="localhost"
|
||||
error={hostnameError && 'Please enter a valid hostname'}
|
||||
bind:value={hostname}>
|
||||
<Tooltip slot="info">
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<span slot="tooltip">
|
||||
The hostname that your website will use to interact with the
|
||||
Appwrite APIs in production or development environments. No
|
||||
protocol or port number required.
|
||||
</span>
|
||||
</Tooltip>
|
||||
</InputText></Fieldset>
|
||||
<Layout.Stack direction="row" justifyContent="flex-end"
|
||||
><Button submit disabled={!selectedFramework}>Create platform</Button
|
||||
></Layout.Stack>
|
||||
{/if}
|
||||
{:else}
|
||||
<Card.Base padding="s"
|
||||
><Layout.Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center">
|
||||
<Layout.Stack gap="xxs" direction="row">
|
||||
<Icon icon={selectedFramework.smallIcon} />
|
||||
<Typography.Text variant="m-500"
|
||||
>{selectedFramework.label}</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
on:click={() => {
|
||||
isChangingFramework = true;
|
||||
}}>Change</Button>
|
||||
</Layout.Stack></Card.Base>
|
||||
{/if}
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
on:click={() => {
|
||||
isChangingFramework = true;
|
||||
}}>Change</Button>
|
||||
</Layout.Stack></Card.Base>
|
||||
{/if}
|
||||
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated && !isChangingFramework}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. Clone the starter kit from GitHub using the terminal or VSCode.
|
||||
</Typography.Text>
|
||||
<!-- Step Three -->
|
||||
{#if isPlatformCreated && !isChangingFramework}
|
||||
<Fieldset legend="Clone starter">
|
||||
<Layout.Stack gap="l">
|
||||
<Typography.Text variant="m-500">
|
||||
1. If you're starting a new project, you can clone our starter kit from
|
||||
GitHub using the terminal or VSCode.
|
||||
</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code
|
||||
lang="bash"
|
||||
lineNumbers
|
||||
code={`\ngit clone https://github.com/appwrite/starter-for-${selectedFramework.key}\ncd starter-for-${selectedFramework.key}`} />
|
||||
</div>
|
||||
|
||||
{#if selectedFramework.key === 'angular'}
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Change <InlineCode
|
||||
size="s"
|
||||
code="src/environments/environment.ts" />
|
||||
to reflect the values below:</Typography.Text>
|
||||
{:else}
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Rename <InlineCode size="s" code=".env.example" /> into <InlineCode
|
||||
size="s"
|
||||
code=".env" /> and update the values.</Typography.Text>
|
||||
{/if}
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code
|
||||
lang="bash"
|
||||
lineNumbers
|
||||
code={selectedFramework.updateConfigCode} />
|
||||
</div>
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code
|
||||
lang="bash"
|
||||
lineNumbers
|
||||
code={`\ngit clone https://github.com/appwrite/starter-for-${selectedFramework.key}\ncd starter-for-${selectedFramework.key}`} />
|
||||
</div>
|
||||
|
||||
{#if selectedFramework.key === 'angular'}
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Install project dependencies</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={'npm install'} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>4. Run the app, then click the <InlineCode
|
||||
>2. Change <InlineCode
|
||||
size="s"
|
||||
code="Send a ping" /> button to verify the setup.</Typography.Text>
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={selectedFramework.runCommand} />
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
<Card.Base padding="s"
|
||||
><Layout.Stack direction="row" justifyContent="space-between"
|
||||
><Layout.Stack direction="row" alignItems="center">
|
||||
<Icon
|
||||
icon={IconInfo}
|
||||
color="--fgcolor-neutral-tertiary" /><Typography.Text
|
||||
variant="m-500"
|
||||
color="--fgcolor-neutral-primary">
|
||||
Demo app runs on http://localhost:{selectedFramework.portNumber}</Typography.Text
|
||||
></Layout.Stack>
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href={`http://localhost:${selectedFramework.portNumber}`}
|
||||
><Layout.Stack direction="row" gap="xs"
|
||||
>Open <Icon
|
||||
icon={IconExternalLink}
|
||||
color="--fgcolor-neutral-tertiary" /></Layout.Stack
|
||||
></Button
|
||||
></Layout.Stack
|
||||
></Card.Base>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Form>
|
||||
code="src/environments/environment.ts" />
|
||||
to reflect the values below:</Typography.Text>
|
||||
{:else}
|
||||
<Typography.Text variant="m-500"
|
||||
>2. Add your Appwrite credentials to <InlineCode
|
||||
size="s"
|
||||
code=".env.example" /> then rename it to <InlineCode
|
||||
size="s"
|
||||
code=".env" /> if needed.</Typography.Text>
|
||||
{/if}
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={selectedFramework.updateConfigCode} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>3. Install project dependencies</Typography.Text>
|
||||
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={'npm install'} />
|
||||
</div>
|
||||
|
||||
<Typography.Text variant="m-500"
|
||||
>4. Run the app, then click the <InlineCode size="s" code="Send a ping" /> button
|
||||
to verify the setup.</Typography.Text>
|
||||
<!-- Temporary fix: Remove this div once Code splitting issue with stack spacing is resolved -->
|
||||
<div class="pink2-code-margin-fix">
|
||||
<Code lang="bash" lineNumbers code={selectedFramework.runCommand} />
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</Fieldset>
|
||||
<Card.Base padding="s"
|
||||
><Layout.Stack direction="row" justifyContent="space-between"
|
||||
><Layout.Stack direction="row" alignItems="center">
|
||||
<Icon icon={IconInfo} color="--fgcolor-neutral-tertiary" /><Typography.Text
|
||||
variant="m-500"
|
||||
color="--fgcolor-neutral-primary">
|
||||
Demo app runs on http://localhost:{selectedFramework.portNumber}</Typography.Text
|
||||
></Layout.Stack>
|
||||
<Button
|
||||
external
|
||||
secondary
|
||||
href={`http://localhost:${selectedFramework.portNumber}`}
|
||||
><Layout.Stack direction="row" gap="xs"
|
||||
>Open <Icon
|
||||
icon={IconExternalLink}
|
||||
color="--fgcolor-neutral-tertiary" /></Layout.Stack
|
||||
></Button
|
||||
></Layout.Stack
|
||||
></Card.Base>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="aside">
|
||||
<Card.Base>
|
||||
<Layout.Stack gap="xxl">
|
||||
|
||||
@@ -20,8 +20,17 @@
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
|
||||
export let migration: Models.Migration = null;
|
||||
export let show = false;
|
||||
export let migration: Models.Migration = null;
|
||||
|
||||
// convert to proper json objects from string!
|
||||
migration.errors = migration.errors.map((err) => {
|
||||
try {
|
||||
return JSON.parse(err);
|
||||
} catch {
|
||||
return err;
|
||||
}
|
||||
});
|
||||
|
||||
type StatusCounters = {
|
||||
[resource in 'Database' | 'Collection' | 'Function' | 'Users']?: StatusCounter;
|
||||
@@ -55,7 +64,7 @@
|
||||
};
|
||||
|
||||
let tab = 'details' as 'details' | 'logs';
|
||||
let logs = JSON.stringify(migration, null, 2);
|
||||
const logs = JSON.stringify(migration, null, 2);
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
|
||||
+8
-2
@@ -34,8 +34,14 @@
|
||||
$: dbWrites = data.usage.databasesWrites;
|
||||
|
||||
$: legendData = [
|
||||
{ name: 'Reads', value: data.usage.databasesReadsTotal },
|
||||
{ name: 'Writes', value: data.usage.databasesWritesTotal }
|
||||
{
|
||||
name: 'Reads',
|
||||
value: data.usage.databasesReads.reduce((sum, item) => sum + item.value, 0)
|
||||
},
|
||||
{
|
||||
name: 'Writes',
|
||||
value: data.usage.databasesWrites.reduce((sum, item) => sum + item.value, 0)
|
||||
}
|
||||
];
|
||||
|
||||
const tier = data?.currentInvoice?.plan ?? $organization?.billingPlan;
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
import { app } from '$lib/stores/app';
|
||||
import { base } from '$app/paths';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { getApiEndpoint } from '$lib/stores/sdk';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { capitalize } from '$lib/helpers/string';
|
||||
import { page } from '$app/state';
|
||||
|
||||
export let deployment: Models.Deployment;
|
||||
export let proxyRuleList: Models.ProxyRuleList;
|
||||
@@ -46,9 +45,7 @@
|
||||
}
|
||||
|
||||
function getFilePreview(fileId: string) {
|
||||
// TODO: @Meldiron use sdk.forConsole.storage.getFilePreview
|
||||
const endpoint = getApiEndpoint(page.params.region);
|
||||
return endpoint + `/storage/buckets/screenshots/files/${fileId}/view?project=console`;
|
||||
return sdk.forConsole.storage.getFileView('screenshots', fileId);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@
|
||||
|
||||
let deployment = $state(data.deployment);
|
||||
|
||||
onMount(async () => {
|
||||
sdk.forConsole.client.subscribe(
|
||||
onMount(() => {
|
||||
return sdk.forConsole.client.subscribe(
|
||||
'console',
|
||||
async (response: RealtimeResponseEvent<Models.Deployment>) => {
|
||||
if (
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
.forProject(page.params.region, page.params.project)
|
||||
.vcs.createRepositoryDetection(
|
||||
$installation.$id,
|
||||
data.repository.id,
|
||||
page.params.repository,
|
||||
VCSDetectionType.Framework,
|
||||
rootDir
|
||||
);
|
||||
|
||||
+9
-8
@@ -5,11 +5,14 @@ import { buildVerboseDomain } from '../../store';
|
||||
export const load = async ({ parent, params, url }) => {
|
||||
const { installations, frameworks, project, organization, regionalConsoleVariables } =
|
||||
await parent();
|
||||
const [repository] = await Promise.all([
|
||||
sdk
|
||||
.forProject(params.region, params.project)
|
||||
.vcs.getRepository(url.searchParams.get('installation'), params.repository)
|
||||
]);
|
||||
|
||||
const repository = await sdk
|
||||
.forProject(params.region, params.project)
|
||||
.vcs.getRepository(url.searchParams.get('installation'), params.repository);
|
||||
|
||||
const installation = installations.installations.find(
|
||||
(installation) => installation.$id === url.searchParams.get('installation')
|
||||
);
|
||||
|
||||
const domain = await buildVerboseDomain(
|
||||
regionalConsoleVariables._APP_DOMAIN_SITES,
|
||||
@@ -21,9 +24,7 @@ export const load = async ({ parent, params, url }) => {
|
||||
|
||||
return {
|
||||
installations,
|
||||
installation: installations.installations.find(
|
||||
(installation) => installation.$id === url.searchParams.get('installation')
|
||||
),
|
||||
installation,
|
||||
repository,
|
||||
frameworks,
|
||||
domain
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { generateSiteDeploymentDesc } from './store';
|
||||
import { SvgIcon } from '$lib/components';
|
||||
import { app } from '$lib/stores/app';
|
||||
import { getApiEndpoint } from '$lib/stores/sdk';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import AddCollaboratorModal from './(components)/addCollaboratorModal.svelte';
|
||||
import SitesActionMenu from './sitesActionMenu.svelte';
|
||||
import { capitalize } from '$lib/helpers/string';
|
||||
@@ -33,9 +33,7 @@
|
||||
}
|
||||
|
||||
function getFilePreview(fileId: string) {
|
||||
// TODO: @Meldiron use sdk.forConsole.storage.getFilePreview
|
||||
const endpoint = getApiEndpoint(page.params.region);
|
||||
return endpoint + `/storage/buckets/screenshots/files/${fileId}/view?project=console`;
|
||||
return sdk.forConsole.storage.getFileView('screenshots', fileId);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user