mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'feat-pink-v2' of https://github.com/appwrite/console into feat-pink-v2
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
export { default as Filters } from './filters.svelte';
|
||||
export { default as TagList } from './tagList.svelte';
|
||||
export { default as FilterMenu } from './menu.svelte';
|
||||
export { default as FilterSubMenu } from './subMenu.svelte';
|
||||
export { default as CustomFilters } from './customFilters.svelte';
|
||||
export { default as QuickFilters } from './quickFilters.svelte';
|
||||
export { default as ParsedTagList } from './parsedTagList.svelte';
|
||||
export { hasPageQueries, queryParamToMap, queries } from '$lib/components/filters/store';
|
||||
|
||||
+6
-5
@@ -1,22 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { Icon, Layout, Tag, Tooltip } from '@appwrite.io/pink-svelte';
|
||||
import { queries, tagFormat } from './store';
|
||||
import { queries, tagFormat, tags } from './store';
|
||||
import { IconX } from '@appwrite.io/pink-icons-svelte';
|
||||
import { parsedTags } from './setFilters';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
|
||||
$: console.log($parsedTags);
|
||||
</script>
|
||||
|
||||
{#if $parsedTags?.length}
|
||||
<Layout.Stack direction="row" gap="s" wrap="wrap" alignItems="center" inline>
|
||||
{#each $parsedTags as tag}
|
||||
<span>
|
||||
<Tooltip disabled={Array.isArray(tag.value) ? tag.value?.length < 3 : true}>
|
||||
<Tooltip
|
||||
disabled={Array.isArray(tag.value) ? tag.value?.length < 3 : true}
|
||||
maxWidth="600px">
|
||||
<Tag
|
||||
size="s"
|
||||
on:click={() => {
|
||||
queries.removeFilter(tag);
|
||||
const t = $tags.filter((t) => t.tag.includes(tag.tag.split(' ')[0]));
|
||||
t.forEach((t) => (t ? queries.removeFilter(t) : null));
|
||||
queries.apply();
|
||||
parsedTags.update((tags) => tags.filter((t) => t.tag !== tag.tag));
|
||||
}}>
|
||||
@@ -1,13 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import MenuItem from '$lib/components/filters/subMenu.svelte';
|
||||
import { queryParamToMap } from '$lib/components/filters/store';
|
||||
import type { Column } from '$lib/helpers/types';
|
||||
import { type Writable } from 'svelte/store';
|
||||
import Menu from '$lib/components/filters/menu.svelte';
|
||||
import { CustomFilters } from '$lib/components/filters';
|
||||
import { setFiltersOnNavigate } from '$lib/components/filters/setFilters';
|
||||
import { addFilterAndApply, buildFilterCol } from '$lib/components/filters/quickFilters';
|
||||
import { addFilterAndApply, buildFilterCol } from './quickFilters';
|
||||
import { parsedTags, setFiltersOnNavigate } from './setFilters';
|
||||
import Menu from '../menu/menu.svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Icon } from '@appwrite.io/pink-svelte';
|
||||
import { IconFilterLine } from '@appwrite.io/pink-icons-svelte';
|
||||
import QuickfiltersSubMenu from './quickfiltersSubMenu.svelte';
|
||||
|
||||
export let columns: Writable<Column[]>;
|
||||
export let analyticsSource: string;
|
||||
@@ -22,44 +25,57 @@
|
||||
const localTags = Array.from(localQueries.keys());
|
||||
|
||||
setFiltersOnNavigate(localTags, filterCols, $columns);
|
||||
filterCols = filterCols;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
{#each filterCols as filter}
|
||||
{#if filter.options}
|
||||
<MenuItem
|
||||
{filter}
|
||||
variant={filter?.array ? 'checkbox' : 'radio'}
|
||||
on:add={(e) => {
|
||||
addFilterAndApply(
|
||||
filter.id,
|
||||
filter.title,
|
||||
filter.operator,
|
||||
e.detail.value,
|
||||
filter?.array
|
||||
? (filter.options
|
||||
.filter((opt) => opt.checked)
|
||||
.map((opt) => opt.value) ?? [])
|
||||
: [],
|
||||
$columns,
|
||||
analyticsSource
|
||||
);
|
||||
}}
|
||||
on:clear={() => {
|
||||
filter.tag = null;
|
||||
addFilterAndApply(
|
||||
filter.id,
|
||||
filter.title,
|
||||
filter.operator,
|
||||
null,
|
||||
[],
|
||||
$columns,
|
||||
analyticsSource
|
||||
);
|
||||
}} />
|
||||
{/if}
|
||||
{/each}
|
||||
{#if $parsedTags?.length}
|
||||
<Button secondary badge={`${$parsedTags?.length}`}>
|
||||
<Icon icon={IconFilterLine} slot="start" size="s" />
|
||||
Filters
|
||||
</Button>
|
||||
{:else}
|
||||
<Button secondary>
|
||||
<Icon icon={IconFilterLine} slot="start" size="s" />
|
||||
Filters
|
||||
</Button>
|
||||
{/if}
|
||||
<svelte:fragment slot="menu">
|
||||
{#each filterCols as filter}
|
||||
{#if filter.options}
|
||||
<QuickfiltersSubMenu
|
||||
{filter}
|
||||
variant={filter?.array ? 'checkbox' : 'radio'}
|
||||
on:add={(e) => {
|
||||
addFilterAndApply(
|
||||
filter.id,
|
||||
filter.title,
|
||||
filter.operator,
|
||||
e.detail.value,
|
||||
filter?.array
|
||||
? (filter.options
|
||||
.filter((opt) => opt.checked)
|
||||
.map((opt) => opt.value) ?? [])
|
||||
: [],
|
||||
$columns,
|
||||
analyticsSource
|
||||
);
|
||||
}}
|
||||
on:clear={() => {
|
||||
addFilterAndApply(
|
||||
filter.id,
|
||||
filter.title,
|
||||
filter.operator,
|
||||
null,
|
||||
[],
|
||||
$columns,
|
||||
analyticsSource
|
||||
);
|
||||
}} />
|
||||
{/if}
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="end">
|
||||
<CustomFilters {columns} />
|
||||
|
||||
@@ -61,12 +61,6 @@ export function addFilterAndApply(
|
||||
});
|
||||
}
|
||||
|
||||
export function resetOptions(filter: FilterData) {
|
||||
filter.options.forEach((option) => {
|
||||
option.checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
export function addStatusCodeFilter(value: string, colId: string, columns: Column[]) {
|
||||
addFilter(columns, colId, ValidOperators.LessThanOrEqual, parseInt(value));
|
||||
addFilter(columns, colId, ValidOperators.GreaterThanOrEqual, parseInt(value) - 99);
|
||||
|
||||
+5
-23
@@ -4,17 +4,7 @@
|
||||
import { ActionMenu, Card, Layout, Selector } from '@appwrite.io/pink-svelte';
|
||||
import { createMenubar, melt } from '@melt-ui/svelte';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import type { ValidOperators } from './store';
|
||||
|
||||
type FilterData = {
|
||||
title: string;
|
||||
id: string;
|
||||
array: boolean;
|
||||
show: boolean;
|
||||
tag: string;
|
||||
operator: ValidOperators;
|
||||
options: { value: string; label: string; checked: boolean }[];
|
||||
};
|
||||
import type { FilterData } from './quickFilters';
|
||||
|
||||
export let filter: FilterData;
|
||||
export let variant: 'checkbox' | 'radio' = 'checkbox';
|
||||
@@ -44,7 +34,7 @@
|
||||
</script>
|
||||
|
||||
<div use:melt={$subTrigger}>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Root noPadding>
|
||||
<ActionMenu.Item.Button trailingIcon={IconChevronRight}
|
||||
>{filter.title}</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
@@ -61,11 +51,7 @@
|
||||
on:click={() => {
|
||||
option.checked = !option.checked;
|
||||
dispatch('add', {
|
||||
value: filter?.array
|
||||
? null
|
||||
: option.checked
|
||||
? option.value
|
||||
: null
|
||||
value: option.value
|
||||
});
|
||||
}}>
|
||||
{capitalize(option.label)}
|
||||
@@ -79,15 +65,11 @@
|
||||
on:click={() => {
|
||||
option.checked = !option.checked;
|
||||
dispatch('add', {
|
||||
value: filter?.array
|
||||
? null
|
||||
: option.checked
|
||||
? option.value
|
||||
: null
|
||||
value: option.checked
|
||||
});
|
||||
}}>
|
||||
<Layout.Stack direction="row" gap="s">
|
||||
<Selector.Checkbox bind:checked={option.checked} size="s" />
|
||||
<Selector.Checkbox checked={option.checked} size="s" />
|
||||
{capitalize(option.label)}
|
||||
</Layout.Stack>
|
||||
</ActionMenu.Item.Button>
|
||||
@@ -1,24 +1,25 @@
|
||||
import type { Column } from '$lib/helpers/types';
|
||||
import { get, writable } from 'svelte/store';
|
||||
import { resetOptions, type FilterData } from './quickFilters';
|
||||
import { type FilterData } from './quickFilters';
|
||||
import { tags, type TagValue } from './store';
|
||||
|
||||
export const parsedTags = writable<TagValue[]>([]);
|
||||
|
||||
export function setFiltersOnNavigate(
|
||||
tags: TagValue[],
|
||||
localTags: TagValue[],
|
||||
filterCols: FilterData[],
|
||||
$columns: Column[]
|
||||
) {
|
||||
if (!tags?.length) {
|
||||
if (!localTags?.length) {
|
||||
filterCols.forEach((filter) => {
|
||||
resetOptions(filter);
|
||||
cleanOldTags(filter.title);
|
||||
});
|
||||
} else {
|
||||
filterCols.forEach((filter) => {
|
||||
if (filter.id === 'buildDuration') {
|
||||
setTimeFilter(filter, $columns);
|
||||
} else if (filter.id.includes('size')) {
|
||||
} else if (filter.id.toLocaleLowerCase().includes('size')) {
|
||||
setSizeFilter(filter, $columns);
|
||||
} else if (filter.id === 'statusCode') {
|
||||
setStatusCodeFilter(filter, $columns);
|
||||
@@ -37,26 +38,25 @@ export function setFiltersOnNavigate(
|
||||
export function setFilterData(filter: FilterData) {
|
||||
const tagData = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
|
||||
if (tagData) {
|
||||
cleanOldTags(filter.title);
|
||||
|
||||
filter.tag = tagData.tag;
|
||||
if (Array.isArray(tagData.value) && tagData.value?.length) {
|
||||
const values = tagData.value as string[];
|
||||
filter.options.forEach((option) => {
|
||||
option.checked = values.includes(option.value);
|
||||
});
|
||||
}
|
||||
cleanOldTags(filter.title);
|
||||
const newTag = {
|
||||
tag: tagData.tag.replace(',', ' or '),
|
||||
value: tagData.value
|
||||
};
|
||||
|
||||
parsedTags.update((tags) => {
|
||||
tags.push(newTag);
|
||||
return tags;
|
||||
});
|
||||
} else {
|
||||
filter.tag = null;
|
||||
resetOptions(filter);
|
||||
cleanOldTags(filter.title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ export function setTimeFilter(filter: FilterData, columns: Column[]) {
|
||||
const col = columns.find((c) => c.id === filter.id);
|
||||
const timeTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
|
||||
if (timeTag) {
|
||||
cleanOldTags(filter.title);
|
||||
const now = new Date();
|
||||
|
||||
const diff = now.getTime() - new Date(timeTag.value as string).getTime();
|
||||
@@ -80,15 +79,16 @@ export function setTimeFilter(filter: FilterData, columns: Column[]) {
|
||||
tag: `**${filter.title}** is **${dateRange.label}**`,
|
||||
value: timeTag.value
|
||||
};
|
||||
filter.tag = `**${filter.title}** is **${dateRange.label}**`;
|
||||
filter = filter;
|
||||
|
||||
cleanOldTags(filter.title);
|
||||
|
||||
parsedTags.update((tags) => {
|
||||
tags.push(newTag);
|
||||
return tags;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
filter.tag = null;
|
||||
cleanOldTags(filter.title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +106,19 @@ export function setSizeFilter(filter: FilterData, columns: Column[]) {
|
||||
return prev;
|
||||
});
|
||||
if (sizeRange) {
|
||||
filter.tag = `**${filter.title}** is **${sizeRange.label}**`;
|
||||
filter = filter;
|
||||
cleanOldTags(filter.title);
|
||||
|
||||
const newTag = {
|
||||
tag: `**${filter.title}** is **${sizeRange.label}**`,
|
||||
value: sizeTag.value
|
||||
};
|
||||
parsedTags.update((tags) => {
|
||||
tags.push(newTag);
|
||||
return tags;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
filter.tag = null;
|
||||
cleanOldTags(filter.title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +131,18 @@ export function setStatusCodeFilter(filter: FilterData, columns: Column[]) {
|
||||
|
||||
const codeRange = ranges.find((c) => c?.value && c.value === statusCodeTag.value);
|
||||
if (codeRange) {
|
||||
filter.tag = `**${filter.title}** is **${codeRange.label}**`;
|
||||
filter = filter;
|
||||
cleanOldTags(filter.title);
|
||||
const newTag = {
|
||||
tag: `**${filter.title}** is **${codeRange.label}**`,
|
||||
value: statusCodeTag.value
|
||||
};
|
||||
parsedTags.update((tags) => {
|
||||
tags.push(newTag);
|
||||
return tags;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
filter.tag = null;
|
||||
cleanOldTags(filter.title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +150,6 @@ export function setDateFilter(filter: FilterData, columns: Column[]) {
|
||||
const dateTag = get(tags).find((tag) => tag.tag.includes(`**${filter.title}**`));
|
||||
const col = columns.find((c) => c.id === filter.id);
|
||||
if (dateTag) {
|
||||
cleanOldTags(filter.title);
|
||||
const now = new Date();
|
||||
|
||||
const diff = now.getTime() - new Date(dateTag.value as string).getTime();
|
||||
@@ -147,6 +161,7 @@ export function setDateFilter(filter: FilterData, columns: Column[]) {
|
||||
return prev;
|
||||
});
|
||||
if (dateRange) {
|
||||
cleanOldTags(filter.title);
|
||||
const newTag = {
|
||||
tag: `**${filter.title}** is **${dateRange.label}**`,
|
||||
value: dateTag.value
|
||||
@@ -157,7 +172,7 @@ export function setDateFilter(filter: FilterData, columns: Column[]) {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
filter.tag = null;
|
||||
cleanOldTags(filter.title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,3 +182,9 @@ function cleanOldTags(title: string) {
|
||||
return tags;
|
||||
});
|
||||
}
|
||||
|
||||
export function resetOptions(filter: FilterData) {
|
||||
filter.options.forEach((option) => {
|
||||
option.checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
environment variables are configured.
|
||||
</p>
|
||||
<div>
|
||||
<Button compact external href="#/">Learn more</Button>
|
||||
<Button
|
||||
compact
|
||||
external
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/functions#git"
|
||||
>Learn more</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</Alert.Inline>
|
||||
|
||||
@@ -30,11 +30,13 @@
|
||||
export let installationList = $installations;
|
||||
export let product: 'functions' | 'sites' = 'functions';
|
||||
|
||||
let search = '';
|
||||
let selectedInstallation = null;
|
||||
|
||||
$: {
|
||||
hasInstallations = installationList?.total > 0;
|
||||
}
|
||||
|
||||
let selectedInstallation = null;
|
||||
async function loadInstallations() {
|
||||
if (installationList) {
|
||||
if (installationList.installations.length) {
|
||||
@@ -56,7 +58,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
let search = '';
|
||||
async function loadRepositories(installationId: string, search: string) {
|
||||
if (
|
||||
!$repositories ||
|
||||
@@ -91,7 +92,7 @@
|
||||
$repository = $repositories.repositories[0];
|
||||
}
|
||||
|
||||
return $repositories.repositories.slice(0, 4);
|
||||
return $repositories.repositories;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as Menu } from './menu.svelte';
|
||||
export { default as SubMenu } from './subMenu.svelte';
|
||||
@@ -1,8 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Card, Icon } from '@appwrite.io/pink-svelte';
|
||||
import { tags } from './store';
|
||||
import { IconFilterLine } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Card } from '@appwrite.io/pink-svelte';
|
||||
import { createMenubar, melt } from '@melt-ui/svelte';
|
||||
|
||||
const {
|
||||
@@ -11,30 +8,31 @@
|
||||
} = createMenubar();
|
||||
|
||||
const {
|
||||
elements: { trigger: trigger, menu: menu, separator: separator }
|
||||
elements: { trigger: trigger, menu: menu, separator: separator },
|
||||
states: { open }
|
||||
} = createMenu();
|
||||
|
||||
function toggle() {
|
||||
open.update((state) => !state);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div use:melt={$menubar}>
|
||||
<div use:melt={$trigger}>
|
||||
{#if $tags.length}
|
||||
<Button secondary badge={`${$tags.length}`}>
|
||||
<Icon icon={IconFilterLine} slot="start" size="s" />
|
||||
Filters
|
||||
</Button>
|
||||
{:else}
|
||||
<Button secondary>
|
||||
<Icon icon={IconFilterLine} slot="start" size="s" />
|
||||
Filters
|
||||
</Button>
|
||||
{/if}
|
||||
<slot {toggle} />
|
||||
</div>
|
||||
|
||||
<div class="menu" use:melt={$menu}>
|
||||
<Card.Base padding="xxxs">
|
||||
<slot />
|
||||
<div class="separator" use:melt={$separator} />
|
||||
<slot name="end" />
|
||||
{#if $$slots.start}
|
||||
<slot name="start" />
|
||||
<div class="separator" use:melt={$separator} />
|
||||
{/if}
|
||||
<slot name="menu" {toggle} />
|
||||
{#if $$slots.end}
|
||||
<div class="separator" use:melt={$separator} />
|
||||
<slot name="end" />
|
||||
{/if}
|
||||
</Card.Base>
|
||||
</div>
|
||||
</div>
|
||||
@@ -42,6 +40,7 @@
|
||||
<style>
|
||||
.menu {
|
||||
min-width: 244px;
|
||||
width: max-content;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { Card } from '@appwrite.io/pink-svelte';
|
||||
import { createMenubar, melt } from '@melt-ui/svelte';
|
||||
|
||||
const {
|
||||
builders: { createMenu }
|
||||
} = createMenubar();
|
||||
|
||||
const {
|
||||
elements: { separator: separator },
|
||||
builders: { createSubmenu: createSubmenu }
|
||||
} = createMenu();
|
||||
|
||||
const {
|
||||
elements: { subMenu: subMenu, subTrigger: subTrigger }
|
||||
} = createSubmenu();
|
||||
</script>
|
||||
|
||||
<div use:melt={$subTrigger}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<div class="subMenu" use:melt={$subMenu}>
|
||||
<Card.Base padding="xxxs">
|
||||
{#if $$slots.start}
|
||||
<slot name="start" />
|
||||
<div class="separator" use:melt={$separator} />
|
||||
{/if}
|
||||
<slot name="menu" />
|
||||
{#if $$slots.end}
|
||||
<div class="separator" use:melt={$separator} />
|
||||
<slot name="end" />
|
||||
{/if}
|
||||
</Card.Base>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.subMenu {
|
||||
min-width: 244px;
|
||||
margin-inline: -4px;
|
||||
margin-block: -4px;
|
||||
}
|
||||
</style>
|
||||
@@ -16,7 +16,7 @@
|
||||
<Typography.Text size="s" truncate color="--fgcolor-neutral-primary"
|
||||
>{value}</Typography.Text>
|
||||
{:else}
|
||||
<Skeleton variant="line" width={100} height={19.5} />
|
||||
<Skeleton variant="line" width="100%" height={19.5} />
|
||||
{/if}
|
||||
</slot>
|
||||
</Layout.Stack>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
|
||||
@@ -72,7 +56,7 @@
|
||||
id ?? ID.unique(),
|
||||
projectName,
|
||||
teamId,
|
||||
Region.Default
|
||||
region
|
||||
);
|
||||
trackEvent(Submit.ProjectCreate, {
|
||||
customId: !!id,
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -66,7 +68,7 @@
|
||||
|
||||
function handleCreateProject() {
|
||||
if (!$canWriteProjects) return;
|
||||
if (isCloud) wizard.start(Create);
|
||||
if (isCloud) showCreateProjectCloud = true;
|
||||
else showCreate = true;
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
@@ -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',
|
||||
@@ -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>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { CustomId } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { InputText, FormList } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { createProject, regions } from './store';
|
||||
|
||||
let showCustomId = false;
|
||||
|
||||
sdk.forConsole.billing.listRegions().then(regions.set);
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Details</svelte:fragment>
|
||||
<FormList>
|
||||
<InputText
|
||||
label="Name"
|
||||
id="name"
|
||||
placeholder="Project name"
|
||||
bind:value={$createProject.name}
|
||||
autofocus
|
||||
required />
|
||||
|
||||
{#if !showCustomId}
|
||||
<div>
|
||||
<Pill button on:click={() => (showCustomId = !showCustomId)}>
|
||||
<span class="icon-pencil" aria-hidden="true" />
|
||||
<span class="text">Project ID </span>
|
||||
</Pill>
|
||||
</div>
|
||||
{:else}
|
||||
<CustomId
|
||||
autofocus
|
||||
bind:show={showCustomId}
|
||||
name="Project"
|
||||
isProject={true}
|
||||
bind:id={$createProject.id}
|
||||
fullWidth />
|
||||
{/if}
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
@@ -1,133 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { RegionCard } from '$lib/components';
|
||||
import { Flag, Pill } from '$lib/elements';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { onMount } from 'svelte';
|
||||
import { createProject, regions } from './store';
|
||||
import type { Region } from '$lib/sdk/billing';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
let prefs: Models.Preferences;
|
||||
|
||||
onMount(async () => {
|
||||
prefs = $page.data.account.prefs;
|
||||
});
|
||||
|
||||
async function notifyRegion(selectedRegion: Region) {
|
||||
try {
|
||||
let newPrefs = { ...prefs };
|
||||
newPrefs.notifications ??= [];
|
||||
newPrefs.notifications = [...newPrefs.notifications, selectedRegion.$id];
|
||||
const response = await sdk.forConsole.account.updatePrefs(newPrefs);
|
||||
prefs = response.prefs;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
isHtml: true,
|
||||
message: `You will be notified via email when <b>${selectedRegion.name}</b> region is available`
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: 'Something went wrong, please try again later'
|
||||
});
|
||||
}
|
||||
}
|
||||
async function unNotifyRegion(selectedRegion: Region) {
|
||||
try {
|
||||
let newPrefs = { ...prefs };
|
||||
newPrefs.notifications = newPrefs.notifications ?? [];
|
||||
newPrefs.notifications = [...newPrefs.notifications, selectedRegion.$id];
|
||||
newPrefs.notifications = newPrefs.notifications.filter(
|
||||
(region: string) => region !== selectedRegion.$id
|
||||
);
|
||||
const response = await sdk.forConsole.account.updatePrefs(newPrefs);
|
||||
prefs = response.prefs;
|
||||
addNotification({
|
||||
type: 'info',
|
||||
isHtml: true,
|
||||
message: `You will no longer be notified when the <b>${selectedRegion.name}</b> region is available`
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: 'Something went wrong, please try again later'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: notifications = prefs?.notifications ?? [];
|
||||
</script>
|
||||
|
||||
<WizardStep>
|
||||
<svelte:fragment slot="title">Regions</svelte:fragment>
|
||||
<svelte:fragment slot="subtitle">
|
||||
Choose a deployment region for your project. This region cannot be changed.
|
||||
</svelte:fragment>
|
||||
{#if $regions}
|
||||
<ul
|
||||
class="grid-box u-margin-block-start-16"
|
||||
style="--p-grid-item-size:12em; --p-grid-item-size-small-screens:12rem; --grid-gap: 1rem;">
|
||||
{#each $regions.regions
|
||||
.filter((r) => r.$id !== 'default')
|
||||
.sort((regionA, regionB) => {
|
||||
if (regionA.disabled >= regionB.disabled) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}) as region}
|
||||
<li>
|
||||
<RegionCard
|
||||
name="region"
|
||||
bind:group={$createProject.region}
|
||||
value={region.$id}
|
||||
disabled={region.disabled}>
|
||||
<div
|
||||
class="u-flex u-flex-vertical u-gap-8 u-justify-main-center u-cross-center u-margin-inline-auto">
|
||||
{#if region.disabled}
|
||||
<Flag
|
||||
width={40}
|
||||
height={30}
|
||||
class={region.disabled ? 'u-opacity-50' : ''}
|
||||
flag={region.flag}
|
||||
name={region.name} />
|
||||
<p class:u-opacity-50={region.disabled}>{region.name}</p>
|
||||
{#if !notifications.includes(region.$id)}
|
||||
<Pill
|
||||
button
|
||||
event="region_notify"
|
||||
on:click={() => {
|
||||
notifyRegion(region);
|
||||
}}>
|
||||
<span class="icon-bell" aria-hidden="true" />
|
||||
<span class="text">Notify me</span>
|
||||
</Pill>
|
||||
{:else}
|
||||
<Pill
|
||||
selected
|
||||
button
|
||||
event="region_notify"
|
||||
on:click={() => {
|
||||
unNotifyRegion(region);
|
||||
}}>
|
||||
<span class="icon-check" aria-hidden="true" />
|
||||
<span class="text">Notify me</span>
|
||||
</Pill>
|
||||
{/if}
|
||||
{:else}
|
||||
<Flag
|
||||
width={40}
|
||||
height={30}
|
||||
flag={region.flag}
|
||||
name={region.name} />
|
||||
{region.name}
|
||||
{/if}
|
||||
</div>
|
||||
</RegionCard>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
</WizardStep>
|
||||
@@ -10,6 +10,7 @@
|
||||
import { installation, repository } from '$lib/stores/vcs';
|
||||
import { Repositories } from '$lib/components/git';
|
||||
import {
|
||||
Alert,
|
||||
Avatar,
|
||||
Badge,
|
||||
Card,
|
||||
@@ -21,6 +22,7 @@
|
||||
import { IconArrowSmRight } from '@appwrite.io/pink-icons-svelte';
|
||||
import Wizard from '$lib/layout/wizard.svelte';
|
||||
import { Link } from '$lib/elements';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -62,16 +64,35 @@
|
||||
`${wizardBase}/create-function/repository-${e.detail.id}?installation=${$installation.$id}`
|
||||
);
|
||||
}
|
||||
|
||||
$: console.log(data);
|
||||
</script>
|
||||
|
||||
<Wizard title="Create function" href={previousPage} column columnSize="l">
|
||||
<div class="git-container u-position-relative">
|
||||
<Layout.Stack gap="l">
|
||||
<!-- TODO: fix mobile -->
|
||||
<Layout.GridFraction start={4} end={6} gap="l" rowSize="auto">
|
||||
<Card.Base>
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.GridFraction start={4} end={6} gap="l" rowSize="auto">
|
||||
<Card.Base>
|
||||
{#if isSelfHosted && !isVcsEnabled}
|
||||
<Layout.Stack gap="xl">
|
||||
<Typography.Title size="s">Connect Git repository</Typography.Title>
|
||||
|
||||
<Alert.Inline
|
||||
status="info"
|
||||
title="Connect your self-hosted instance to Git ">
|
||||
<Layout.Stack>
|
||||
<p>
|
||||
Configure your self-hosted instance to connect your function to
|
||||
a Git repository.
|
||||
</p>
|
||||
<div>
|
||||
<Button
|
||||
compact
|
||||
external
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/functions#git"
|
||||
>Learn more</Button>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</Alert.Inline>
|
||||
</Layout.Stack>
|
||||
{:else}
|
||||
<Layout.Stack
|
||||
gap="xl"
|
||||
justifyContent="space-between"
|
||||
@@ -103,145 +124,106 @@
|
||||
</Layout.Stack>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
{/if}
|
||||
</Card.Base>
|
||||
|
||||
<Card.Base>
|
||||
<Layout.Stack gap="xl">
|
||||
<Typography.Title size="s">Quick start</Typography.Title>
|
||||
<Layout.Grid columnsXXS={1} columnsXS={2} columnsS={3} columns={4} gap="s">
|
||||
{#each starterTemplateRuntimes.slice(0, 6) as template}
|
||||
{@const iconName = template.name.split('-')[0]}
|
||||
{@const runtimeDetail = baseRuntimesList.find(
|
||||
(runtime) => runtime.$id === template.name
|
||||
)}
|
||||
<Card.Link
|
||||
variant="secondary"
|
||||
radius="s"
|
||||
padding="s"
|
||||
on:click={() => {
|
||||
trackEvent('click_connect_template', {
|
||||
from: 'cover',
|
||||
template: starterTemplate.id,
|
||||
runtime: template.name
|
||||
});
|
||||
}}
|
||||
href={`${wizardBase}/create-function/template-${starterTemplate.id}?runtime=${runtimeDetail.$id}`}>
|
||||
<Layout.Stack direction="row" gap="s" alignItems="center">
|
||||
<Avatar
|
||||
size="xs"
|
||||
alt={template.name}
|
||||
empty={!template.name}>
|
||||
<SvgIcon name={iconName} iconSize="small" />
|
||||
</Avatar>
|
||||
<Typography.Text color="--fgcolor-neutral-primary">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
gap="xs"
|
||||
alignItems="center">
|
||||
{runtimeDetail?.name}
|
||||
{#if runtimeDetail?.name?.toLowerCase() === 'deno'}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
size="xs"
|
||||
content="New" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card.Link>
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Layout.Grid columnsS={1} columns={2}>
|
||||
{#each featuredTemplatesList as template}
|
||||
<Card.Link
|
||||
radius="s"
|
||||
padding="xs"
|
||||
href={`${wizardBase}/create-function/template-${template.id}`}
|
||||
on:click={() => {
|
||||
trackEvent('click_connect_template', {
|
||||
from: 'cover',
|
||||
template: template.name
|
||||
});
|
||||
}}>
|
||||
<Layout.Stack gap="xxs">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
gap="s"
|
||||
alignItems="center"
|
||||
justifyContent="space-between">
|
||||
<Typography.Text
|
||||
variant="m-500"
|
||||
color="--fgcolor-neutral-primary">
|
||||
{template.name}
|
||||
</Typography.Text>
|
||||
<Icon
|
||||
icon={IconArrowSmRight}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
<Card.Base>
|
||||
<Layout.Stack gap="xl">
|
||||
<Typography.Title size="s">Quick start</Typography.Title>
|
||||
<Layout.Grid columnsXXS={1} columnsXS={2} columnsS={3} columns={4} gap="s">
|
||||
{#each starterTemplateRuntimes.slice(0, 6) as template}
|
||||
{@const iconName = template.name.split('-')[0]}
|
||||
{@const runtimeDetail = baseRuntimesList.find(
|
||||
(runtime) => runtime.$id === template.name
|
||||
)}
|
||||
<Card.Link
|
||||
variant="secondary"
|
||||
radius="s"
|
||||
padding="s"
|
||||
on:click={() => {
|
||||
trackEvent('click_connect_template', {
|
||||
from: 'cover',
|
||||
template: starterTemplate.id,
|
||||
runtime: template.name
|
||||
});
|
||||
}}
|
||||
href={`${wizardBase}/create-function/template-${starterTemplate.id}?runtime=${runtimeDetail.$id}`}>
|
||||
<Layout.Stack direction="row" gap="s" alignItems="center">
|
||||
<Avatar size="xs" alt={template.name} empty={!template.name}>
|
||||
<SvgIcon name={iconName} iconSize="small" />
|
||||
</Avatar>
|
||||
<Typography.Text color="--fgcolor-neutral-primary">
|
||||
<Layout.Stack direction="row" gap="xs" alignItems="center">
|
||||
{runtimeDetail?.name}
|
||||
{#if runtimeDetail?.name?.toLowerCase() === 'deno'}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
size="xs"
|
||||
content="New" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Typography.Text variant="m-400">
|
||||
{template.tagline}
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card.Link>
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Layout.Grid columnsS={1} columns={2}>
|
||||
{#each featuredTemplatesList as template}
|
||||
<Card.Link
|
||||
radius="s"
|
||||
padding="xs"
|
||||
href={`${wizardBase}/create-function/template-${template.id}`}
|
||||
on:click={() => {
|
||||
trackEvent('click_connect_template', {
|
||||
from: 'cover',
|
||||
template: template.name
|
||||
});
|
||||
}}>
|
||||
<Layout.Stack gap="xxs">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
gap="s"
|
||||
alignItems="center"
|
||||
justifyContent="space-between">
|
||||
<Typography.Text
|
||||
variant="m-500"
|
||||
color="--fgcolor-neutral-primary">
|
||||
{template.name}
|
||||
</Typography.Text>
|
||||
<Icon
|
||||
icon={IconArrowSmRight}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
</Layout.Stack>
|
||||
</Card.Link>
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
<Typography.Text variant="m-400">
|
||||
{template.tagline}
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card.Link>
|
||||
{/each}
|
||||
</Layout.Grid>
|
||||
|
||||
<Link variant="quiet" href={`${wizardBase}/templates`}>
|
||||
<Layout.Stack direction="row" gap="xs">
|
||||
Browse all templates <Icon icon={IconArrowSmRight} />
|
||||
</Layout.Stack>
|
||||
</Link>
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
</Layout.GridFraction>
|
||||
<Link variant="quiet" href={`${wizardBase}/templates`}>
|
||||
<Layout.Stack direction="row" gap="xs">
|
||||
Browse all templates <Icon icon={IconArrowSmRight} />
|
||||
</Layout.Stack>
|
||||
</Link>
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
</Layout.GridFraction>
|
||||
|
||||
<span>
|
||||
You can also create a function <Link
|
||||
on:click={() => {
|
||||
trackEvent('click_create_function_manual', { from: 'cover' });
|
||||
}}
|
||||
href={`${wizardBase}/create-function/manual`}>manually</Link>
|
||||
or using the CLI.
|
||||
<Link href="https://appwrite.io/docs/products/functions/deployment" external
|
||||
>Learn more</Link
|
||||
>.
|
||||
</span>
|
||||
</Layout.Stack>
|
||||
{#if isSelfHosted && !isVcsEnabled}
|
||||
<div
|
||||
class="overlay u-flex-vertical u-position-absolute u-height-100-percent u-width-full-line u-z-index-1 u-text-center u-inset-0"
|
||||
style="border-radius: var(--border-radius-medium); ">
|
||||
<div
|
||||
class="u-flex-vertical u-height-100-percent u-main-center u-cross-center u-gap-16 u-padding-inline-24">
|
||||
<Typography.Title size="s" align="center">
|
||||
Connect your self-hosted instance to Git
|
||||
</Typography.Title>
|
||||
<p style="max-width: 420px">
|
||||
Configure your self-hosted instance to connect your function to a Git
|
||||
repository.
|
||||
<a
|
||||
href="https://appwrite.io/docs/advanced/self-hosting/functions#git"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="link">Learn more</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<span>
|
||||
You can also create a function <Link
|
||||
on:click={() => {
|
||||
trackEvent('click_create_function_manual', { from: 'cover' });
|
||||
}}
|
||||
href={`${wizardBase}/create-function/manual`}>manually</Link>
|
||||
or using the CLI.
|
||||
<Link href="https://appwrite.io/docs/products/functions/deployment" external
|
||||
>Learn more</Link
|
||||
>.
|
||||
</span>
|
||||
</Layout.Stack>
|
||||
</Wizard>
|
||||
|
||||
<style lang="scss">
|
||||
.git-container .overlay {
|
||||
background: linear-gradient(
|
||||
0,
|
||||
var(--bgcolor-neutral-primary) 50%,
|
||||
color-mix(in srgb, var(--bgcolor-neutral-primary) 90%, transparent) 70%,
|
||||
color-mix(in srgb, var(--bgcolor-neutral-primary) 20%, transparent) 90%
|
||||
);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,7 +19,7 @@ export const load: LayoutLoad = async ({ params, depends }) => {
|
||||
Query.equal('type', RuleType.DEPLOYMENT),
|
||||
Query.equal('deploymentResourceType', DeploymentResourceType.FUNCTION),
|
||||
Query.equal('deploymentResourceId', params.function),
|
||||
Query.equal('deploymentId', func.deployment),
|
||||
Query.equal('deploymentId', func.deploymentId),
|
||||
Query.limit(1)
|
||||
]);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
} from '@appwrite.io/pink-icons-svelte';
|
||||
import { app } from '$lib/stores/app';
|
||||
import CreateActionMenu from './(components)/createActionMenu.svelte';
|
||||
import { QuickFilters } from '$lib/components/filters';
|
||||
import { ParsedTagList, QuickFilters } from '$lib/components/filters';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -171,23 +171,26 @@
|
||||
{/if}
|
||||
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<Layout.Stack direction="row" gap="s" wrap="wrap">
|
||||
{#if data.deploymentList.total}
|
||||
<QuickFilters {columns} analyticsSource="function_deployments" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" gap="s" inline>
|
||||
{#if data.deploymentList.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<CreateActionMenu let:toggle>
|
||||
<Button on:click={toggle} event="create_deployment">
|
||||
<Icon icon={IconPlus} size="s" slot="start" />
|
||||
Create deployment
|
||||
</Button>
|
||||
</CreateActionMenu>
|
||||
<Layout.Stack>
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
<Layout.Stack direction="row" gap="s" wrap="wrap">
|
||||
{#if data.deploymentList.total}
|
||||
<QuickFilters {columns} analyticsSource="function_deployments" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Layout.Stack direction="row" gap="s" inline>
|
||||
{#if data.deploymentList.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<CreateActionMenu let:toggle>
|
||||
<Button on:click={toggle} event="create_deployment">
|
||||
<Icon icon={IconPlus} size="s" slot="start" />
|
||||
Create deployment
|
||||
</Button>
|
||||
</CreateActionMenu>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
<ParsedTagList />
|
||||
</Layout.Stack>
|
||||
|
||||
{#if data.deploymentList.total}
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@
|
||||
<Button secondary href={getDownload(data.deployment.$id)}>Download</Button>
|
||||
{/if}
|
||||
|
||||
{#if data.func.deployment !== data.deployment.$id && data.deployment.status === 'ready'}
|
||||
{#if data.func.deploymentId !== data.deployment.$id && data.deployment.status === 'ready'}
|
||||
<Button
|
||||
disabled={data.activeDeployment}
|
||||
on:click={() => {
|
||||
|
||||
+1
-1
@@ -14,6 +14,6 @@ export const load: PageLoad = async ({ params, depends, parent }) => {
|
||||
return {
|
||||
func,
|
||||
deployment,
|
||||
activeDeployment: func.deployment === params.deployment
|
||||
activeDeployment: func.deploymentId === params.deployment
|
||||
};
|
||||
};
|
||||
|
||||
+17
-14
@@ -13,7 +13,7 @@
|
||||
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
|
||||
import Table from './table.svelte';
|
||||
import { columns } from './store';
|
||||
import { QuickFilters } from '$lib/components/filters';
|
||||
import { ParsedTagList, QuickFilters } from '$lib/components/filters';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -29,21 +29,24 @@
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||
<QuickFilters {columns} analyticsSource="function_executions" />
|
||||
<Layout.Stack>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||
<QuickFilters {columns} analyticsSource="function_executions" />
|
||||
|
||||
<Layout.Stack gap="s" inline direction="row" alignItems="center">
|
||||
{#if data?.executions?.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<Button
|
||||
event="execute_function"
|
||||
href={`${base}/project-${$project.$id}/functions/function-${data.func.$id}/executions/execute-function`}
|
||||
disabled={!data.func.$id || !data.func?.deployment}>
|
||||
<Icon icon={IconPlus} size="s" slot="start" />
|
||||
Create execution
|
||||
</Button>
|
||||
<Layout.Stack gap="s" inline direction="row" alignItems="center">
|
||||
{#if data?.executions?.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<Button
|
||||
event="execute_function"
|
||||
href={`${base}/project-${$project.$id}/functions/function-${data.func.$id}/executions/execute-function`}
|
||||
disabled={!data.func.$id || !data.func?.deploymentId}>
|
||||
<Icon icon={IconPlus} size="s" slot="start" />
|
||||
Create execution
|
||||
</Button>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
<ParsedTagList />
|
||||
</Layout.Stack>
|
||||
|
||||
{#if !data.func.logging}
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import type { PageLoad } from './$types';
|
||||
import { proxyRuleList } from '../../store';
|
||||
|
||||
export const load: PageLoad = async ({ params, depends, parent }) => {
|
||||
const data = await parent();
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
}}>
|
||||
Redeploy
|
||||
</ActionMenu.Item.Button>
|
||||
{#if deployment.status === 'ready' && deployment.$id !== $func.deployment}
|
||||
{#if deployment.status === 'ready' && deployment.$id !== $func.deploymentId}
|
||||
<ActionMenu.Item.Button
|
||||
trailingIcon={IconLightningBolt}
|
||||
on:click={(e) => {
|
||||
|
||||
+11
-12
@@ -12,8 +12,8 @@
|
||||
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
|
||||
import { roles } from '$lib/stores/billing';
|
||||
import InputSelect from '$lib/elements/forms/inputSelect.svelte';
|
||||
import Roles from '$lib/components/roles/roles.svelte';
|
||||
import { Layout } from '@appwrite.io/pink-svelte';
|
||||
import { isCloud, isSelfHosted } from '$lib/system';
|
||||
|
||||
export let show = false;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
let email: string,
|
||||
name: string,
|
||||
error: string,
|
||||
role: string = 'viewer';
|
||||
role: string = isSelfHosted ? 'owner' : 'viewer';
|
||||
|
||||
async function create() {
|
||||
try {
|
||||
@@ -59,8 +59,6 @@
|
||||
email = null;
|
||||
name = null;
|
||||
}
|
||||
|
||||
//TODO: fix popover
|
||||
</script>
|
||||
|
||||
<Modal title="Add collaborator" {error} bind:show onSubmit={create}>
|
||||
@@ -75,14 +73,15 @@
|
||||
placeholder="Enter email"
|
||||
autofocus={true}
|
||||
bind:value={email} />
|
||||
<InputSelect
|
||||
popover={Roles}
|
||||
id="role"
|
||||
label="Role"
|
||||
placeholder="Select role"
|
||||
required
|
||||
options={roles}
|
||||
bind:value={role} />
|
||||
{#if isCloud}
|
||||
<InputSelect
|
||||
id="role"
|
||||
label="Role"
|
||||
placeholder="Select role"
|
||||
required
|
||||
options={roles}
|
||||
bind:value={role} />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (show = false)}>Cancel</Button>
|
||||
|
||||
+47
-30
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { Menu } from '$lib/components/menu';
|
||||
import SubMenu from '$lib/components/menu/subMenu.svelte';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { DeploymentDownloadType, type Models } from '@appwrite.io/console';
|
||||
@@ -11,7 +13,7 @@
|
||||
IconTrash,
|
||||
IconXCircle
|
||||
} from '@appwrite.io/pink-icons-svelte';
|
||||
import { ActionMenu, Icon, Popover } from '@appwrite.io/pink-svelte';
|
||||
import { ActionMenu, Icon } from '@appwrite.io/pink-svelte';
|
||||
|
||||
export let selectedDeployment: Models.Deployment;
|
||||
export let deployment: Models.Deployment;
|
||||
@@ -22,28 +24,31 @@
|
||||
export let activeDeployment: string;
|
||||
export let inCard = false;
|
||||
|
||||
function getDownload(deploymentId: string) {
|
||||
function getOutputDownload(deploymentId: string) {
|
||||
return (
|
||||
sdk.forProject.sites.getDeploymentDownload($page.params.site, deploymentId).toString() +
|
||||
'&mode=admin',
|
||||
DeploymentDownloadType.Source
|
||||
sdk.forProject.sites.getDeploymentDownload(
|
||||
$page.params.site,
|
||||
deploymentId.toString(),
|
||||
DeploymentDownloadType.Output
|
||||
) + '&mode=admin'
|
||||
);
|
||||
}
|
||||
function getSourceDownload(deploymentId: string) {
|
||||
return (
|
||||
sdk.forProject.sites.getDeploymentDownload(
|
||||
$page.params.site,
|
||||
deploymentId.toString(),
|
||||
DeploymentDownloadType.Source
|
||||
) + '&mode=admin'
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Popover padding="none" placement="bottom-end" let:toggle>
|
||||
<Button
|
||||
text={!inCard}
|
||||
secondary={inCard}
|
||||
icon
|
||||
size="s"
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
toggle(e);
|
||||
}}>
|
||||
<Menu>
|
||||
<Button text={!inCard} secondary={inCard} icon size="s">
|
||||
<Icon size="s" icon={IconDotsHorizontal} />
|
||||
</Button>
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<svelte:fragment slot="menu" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
{#if !inCard}
|
||||
<ActionMenu.Item.Button
|
||||
@@ -52,7 +57,7 @@
|
||||
e.preventDefault();
|
||||
selectedDeployment = deployment;
|
||||
showRedeploy = true;
|
||||
toggle(e);
|
||||
toggle();
|
||||
}}>
|
||||
Redeploy
|
||||
</ActionMenu.Item.Button>
|
||||
@@ -64,21 +69,35 @@
|
||||
e.preventDefault();
|
||||
selectedDeployment = deployment;
|
||||
showActivate = true;
|
||||
toggle(e);
|
||||
toggle();
|
||||
}}>
|
||||
Activate
|
||||
</ActionMenu.Item.Button>
|
||||
{/if}
|
||||
{#if deployment?.status === 'ready' || deployment?.status === 'failed'}
|
||||
<ActionMenu.Item.Anchor
|
||||
href={getDownload(deployment.$id)}
|
||||
external
|
||||
leadingIcon={IconDownload}
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
}}>
|
||||
Download
|
||||
</ActionMenu.Item.Anchor>
|
||||
<SubMenu>
|
||||
<ActionMenu.Root noPadding>
|
||||
<ActionMenu.Item.Button leadingIcon={IconDownload}>
|
||||
Download
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
<svelte:fragment slot="menu">
|
||||
<ActionMenu.Root noPadding>
|
||||
<ActionMenu.Item.Anchor
|
||||
on:click={toggle}
|
||||
href={getSourceDownload(deployment.$id)}
|
||||
external>
|
||||
Download source
|
||||
</ActionMenu.Item.Anchor>
|
||||
<ActionMenu.Item.Anchor
|
||||
on:click={toggle}
|
||||
href={getOutputDownload(deployment.$id)}
|
||||
external>
|
||||
Download output
|
||||
</ActionMenu.Item.Anchor>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</SubMenu>
|
||||
{/if}
|
||||
|
||||
{#if deployment?.status === 'processing' || deployment?.status === 'building' || deployment.status === 'waiting'}
|
||||
@@ -89,7 +108,6 @@
|
||||
e.preventDefault();
|
||||
selectedDeployment = deployment;
|
||||
showCancel = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Cancel
|
||||
</ActionMenu.Item.Button>
|
||||
@@ -102,11 +120,10 @@
|
||||
e.preventDefault();
|
||||
selectedDeployment = deployment;
|
||||
showDelete = true;
|
||||
toggle(e);
|
||||
}}>
|
||||
Delete
|
||||
</ActionMenu.Item.Button>
|
||||
{/if}
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Menu>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import CreateCliModal from './createCliModal.svelte';
|
||||
import { QuickFilters } from '$lib/components/filters';
|
||||
import { ParsedTagList, QuickFilters } from '$lib/components/filters';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -45,54 +45,57 @@
|
||||
<Layout.Stack gap="xxxl">
|
||||
<DeploymentMetrics deploymentList={data.deploymentList} />
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.Stack justifyContent="space-between" direction="row">
|
||||
<Layout.Stack alignItems="center" direction="row">
|
||||
{#if data.deploymentList.total || data?.query}
|
||||
<QuickFilters {columns} analyticsSource="site_deployments" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<Layout.Stack>
|
||||
<Layout.Stack justifyContent="space-between" direction="row">
|
||||
<Layout.Stack alignItems="center" direction="row">
|
||||
{#if data.deploymentList.total || data?.query}
|
||||
<QuickFilters {columns} analyticsSource="site_deployments" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
<Layout.Stack direction="row" inline>
|
||||
{#if data.deploymentList.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<Popover padding="none" let:toggle>
|
||||
<Button size="s" on:click={toggle}>
|
||||
<Icon size="s" icon={IconPlus} />
|
||||
Create deployment
|
||||
</Button>
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
badge="Recommended"
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
if (!hasInstallation) {
|
||||
showConnectRepo = true;
|
||||
} else {
|
||||
showCreateDeployment = true;
|
||||
}
|
||||
}}>
|
||||
Git
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
showConnectCLI = true;
|
||||
}}>
|
||||
CLI
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
showConnectManual = true;
|
||||
}}>
|
||||
Manual
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
<Layout.Stack direction="row" inline>
|
||||
{#if data.deploymentList.total}
|
||||
<ViewSelector view={View.Table} {columns} hideView />
|
||||
{/if}
|
||||
<Popover padding="none" let:toggle>
|
||||
<Button size="s" on:click={toggle}>
|
||||
<Icon size="s" icon={IconPlus} />
|
||||
Create deployment
|
||||
</Button>
|
||||
<svelte:fragment slot="tooltip" let:toggle>
|
||||
<ActionMenu.Root>
|
||||
<ActionMenu.Item.Button
|
||||
badge="Recommended"
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
if (!hasInstallation) {
|
||||
showConnectRepo = true;
|
||||
} else {
|
||||
showCreateDeployment = true;
|
||||
}
|
||||
}}>
|
||||
Git
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
showConnectCLI = true;
|
||||
}}>
|
||||
CLI
|
||||
</ActionMenu.Item.Button>
|
||||
<ActionMenu.Item.Button
|
||||
on:click={(e) => {
|
||||
toggle(e);
|
||||
showConnectManual = true;
|
||||
}}>
|
||||
Manual
|
||||
</ActionMenu.Item.Button>
|
||||
</ActionMenu.Root>
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
<ParsedTagList />
|
||||
</Layout.Stack>
|
||||
|
||||
{#if data.deploymentList.total}
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { onMount } from 'svelte';
|
||||
import Table from './table.svelte';
|
||||
import { QuickFilters } from '$lib/components/filters';
|
||||
import { ParsedTagList, QuickFilters } from '$lib/components/filters';
|
||||
import { Card, Empty, Layout } from '@appwrite.io/pink-svelte';
|
||||
import { View } from '$lib/helpers/load';
|
||||
import { columns } from './store';
|
||||
import AppliedFilter from '$lib/components/filters/appliedFilter.svelte';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -35,7 +34,7 @@
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
<AppliedFilter />
|
||||
<ParsedTagList />
|
||||
</Layout.Stack>
|
||||
{#if data?.logs?.total}
|
||||
<Table columns={$columns} logs={data.logs} />
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
site.buildCommand || undefined,
|
||||
site.outputDirectory || undefined,
|
||||
(site?.buildRuntime as BuildRuntime) || undefined,
|
||||
site.adapter as Adapter,
|
||||
(site?.adapter as Adapter) || undefined,
|
||||
site.fallbackFile || undefined,
|
||||
'',
|
||||
'',
|
||||
|
||||
Reference in New Issue
Block a user