Merge branch 'feat-pink-v2' of https://github.com/appwrite/console into feat-pink-v2

This commit is contained in:
Torsten Dittmann
2025-02-26 17:01:07 +04:00
39 changed files with 375 additions and 317 deletions
+1 -1
View File
@@ -405,7 +405,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--space-1, 2px) var(--space-1, 2px) var(--space-1, 2px) var(--space-3, 6px);
padding: var(--space-1, 2px) var(--space-2, 4px) var(--space-1, 2px) var(--space-3, 6px);
gap: var(--space-2, 4px);
margin: 0 var(--space-5, 10px) 0 var(--space-5, 10px);
+3 -3
View File
@@ -14,7 +14,7 @@
import type { Column } from '$lib/helpers/types';
import type { Writable } from 'svelte/store';
import { TagList } from '.';
import { Icon } from '@appwrite.io/pink-svelte';
import { Icon, Layout } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
// We cast to any to not cause type errors in the input components
@@ -71,7 +71,7 @@
<div>
<form on:submit|preventDefault={addFilterAndReset}>
<ul class="selects u-flex u-gap-8 u-margin-block-start-16 u-flex-vertical-mobile">
<Layout.Stack gap="s" direction="row" alignItems="flex-start">
<InputSelect
id="column"
options={$columns
@@ -88,7 +88,7 @@
options={operatorsForColumn}
placeholder="Select operator"
bind:value={operatorKey} />
</ul>
</Layout.Stack>
{#if column && operator && !operator?.hideInput}
{#if column?.array}
<FormList class="u-margin-block-start-8">
+5 -6
View File
@@ -14,8 +14,8 @@
ValidOperators
} from './store';
import { createEventDispatcher } from 'svelte';
import { Icon, Popover } from '@appwrite.io/pink-svelte';
import { IconFilter } from '@appwrite.io/pink-icons-svelte';
import { Icon, Layout, Popover } from '@appwrite.io/pink-svelte';
import { IconFilter, IconFilterLine } from '@appwrite.io/pink-icons-svelte';
export let query = '[]';
export let columns: Writable<Column[]>;
@@ -119,7 +119,7 @@
<div class="is-not-mobile">
<Popover let:toggle placement="bottom-start">
<Button secondary on:click={toggle} {disabled}>
<Icon icon={IconFilter} slot="start" size="s" />
<Icon icon={IconFilterLine} slot="start" size="s" />
Filters
{#if applied > 0}
<span class="inline-tag">
@@ -128,7 +128,7 @@
{/if}
</Button>
<svelte:fragment slot="tooltip">
<div class="dropped card">
<Layout.Stack gap="s">
{#if displayQuickFilters}
<slot name="quick" />
{:else}
@@ -143,7 +143,6 @@
on:apply={afterApply}
on:clear={() => (applied = 0)} />
{/if}
<hr />
<div
class="u-flex u-cross-center u-margin-block-start-16"
class:u-main-end={!quickFilters}
@@ -167,7 +166,7 @@
<Button size="s" on:click={apply} disabled={isButtonDisabled}>Apply</Button>
</div>
</div>
</div>
</Layout.Stack>
</svelte:fragment>
</Popover>
</div>
+3 -12
View File
@@ -355,7 +355,7 @@
}
.link-icon {
color: var(--color-fgcolor-neutral-primary);
color: var(--color-fgcolor-neutral-tertiary);
}
}
}
@@ -365,7 +365,7 @@
color: var(--color-fgcolor-neutral-primary);
}
.link-icon {
color: var(--color-fgcolor-neutral-primary);
color: var(--color-fgcolor-neutral-tertiary);
}
}
@@ -419,15 +419,6 @@
border-bottom: var(--border-width-s, 1px) solid var(--color-border-neutral, #ededf0);
background: var(--color-bgcolor-neutral-primary, #fff);
.icon {
display: flex;
padding: var(--space-3, 6px);
justify-content: center;
align-items: center;
color: var(--color-fgcolor-neutral-weak);
}
}
.products-label-container {
@@ -440,7 +431,7 @@
}
.icons .products-label-container {
margin-block-start: var(--base-32, 32px);
margin-block-start: var(--base-20, 20px);
margin-block-end: var(--base-8, 8px);
}
+2 -2
View File
@@ -27,8 +27,8 @@
margin-inline: 1rem;
}
@media (min-width: 1024px) {
margin-inline: 2.5rem;
max-width: 944px;
margin-inline: auto;
max-width: min(944px, calc(944px - 5rem));
}
@media (min-width: 1280px) {
margin-inline: auto;
+2 -2
View File
@@ -40,8 +40,8 @@
margin-inline: 1rem;
}
@media (min-width: 1024px) {
margin-inline: 2.5rem;
max-width: 944px;
margin-inline: auto;
max-width: min(944px, calc(944px - 5rem));
}
@media (min-width: 1280px) {
margin-inline: auto;
+1 -2
View File
@@ -6,7 +6,7 @@
import { log } from '$lib/stores/logs';
import { wizard } from '$lib/stores/wizard';
import { activeHeaderAlert } from '$routes/(console)/store';
import { type ComponentType, onDestroy, setContext } from 'svelte';
import { type ComponentType, setContext } from 'svelte';
import { writable } from 'svelte/store';
import { showSubNavigation } from '$lib/stores/layout';
import { organization, organizationList } from '$lib/stores/organization';
@@ -135,7 +135,6 @@
<svelte:window on:resize={handleResize} />
<svelte:body use:style={$bodyStyle} />
<main
class:grid-with-side={showSideNavigation}
class:is-open={$showSubNavigation}
class:u-hide={$wizard.show || $log.show || $wizard.cover}
class:is-fixed-layout={$activeHeaderAlert?.show}
+8 -2
View File
@@ -34,8 +34,14 @@ export const load: LayoutLoad = async ({ params, fetch, depends, parent }) => {
}, new Map<Tier, Plan>());
}
const organizations = await sdk.forConsole.teams.list();
let projects = [];
const currentOrgId = params.organization ? params.organization : prefs.organization;
let currentOrgId = params.organization ? params.organization : prefs.organization;
if (!currentOrgId && organizations.teams.length > 0) {
currentOrgId = organizations.teams[0].$id;
}
if (currentOrgId) {
const orgProjects = await sdk.forConsole.projects.list([
Query.equal('teamId', currentOrgId),
@@ -53,6 +59,6 @@ export const load: LayoutLoad = async ({ params, fetch, depends, parent }) => {
scopes: [],
projects: projects,
currentProjectId: params.project ?? '',
organizations: await sdk.forConsole.teams.list()
organizations: organizations
};
};
@@ -27,4 +27,4 @@
</svelte:fragment>
</CardGrid>
<Delete bind:showDelete />
<Delete projectFunction={$func} bind:showDelete />
@@ -6,13 +6,18 @@
import Confirm from '$lib/components/confirm.svelte';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { type Models } from '@appwrite.io/console';
import { FormList, InputCheckbox } from '$lib/elements/forms';
export let showDelete = false;
const functionId = $page.params.function;
export let projectFunction: Models.Function;
let error: string;
let confirmedDeletion = false;
const handleSubmit = async () => {
try {
await sdk.forProject.functions.delete(functionId);
await sdk.forProject.functions.delete(projectFunction.$id);
showDelete = false;
addNotification({
type: 'success',
@@ -27,6 +32,25 @@
};
</script>
<Confirm onSubmit={handleSubmit} title="Delete function" bind:open={showDelete} bind:error>
Are you sure you want to delete this function and all associated deployments from your project?
<Confirm
onSubmit={handleSubmit}
disabled={!confirmedDeletion}
title="Delete function"
bind:open={showDelete}
bind:error>
<FormList>
<p data-private>Are you sure you want to delete <strong>{projectFunction.name}</strong>?</p>
<p data-private>
The function and all associated deployments will be permanently deleted. This action is
irreversible.
</p>
<InputCheckbox
size="s"
required
id="delete_function"
bind:checked={confirmedDeletion}
label="I understand and confirm" />
</FormList>
</Confirm>
@@ -48,10 +48,8 @@
on:click={async () => {
trackEvent('onboarding_hub_platform_dismiss');
await setHasOnboardingDismissed($project.$id);
await invalidate(Dependencies.ORGANIZATION);
goto(`${base}/project-${$project.$id}/overview`);
requestAnimationFrame(() => {
invalidate(Dependencies.ORGANIZATION);
});
}}>Dismiss this page</Button.Button>
{/if}
</div>
@@ -93,7 +93,9 @@
hideFooter={!repositoryBehaviour}
onSubmit={connectRepo}
bind:error>
<span slot="description"> Connect to a new repository or an existing one. </span>
<span slot="description">
Connect your site to an existing repository or create a new one.
</span>
{#if hasInstallations}
<Layout.Stack gap="xl">
<RepositoryBehaviour bind:repositoryBehaviour />
@@ -127,7 +129,10 @@
{#if repositoryBehaviour === 'existing'}
<Layout.Stack>
<Link variant="quiet" href="#/">
Missing a repository? check your permissions <Icon icon={IconArrowSmRight} />
<Layout.Stack direction="row" gap="xs">
Missing a repository? check your permissions <Icon
icon={IconArrowSmRight} />
</Layout.Stack>
</Link>
</Layout.Stack>
{:else if repositoryBehaviour === 'new'}
@@ -1,5 +1,4 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Button } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
@@ -9,7 +8,6 @@
IconDownload,
IconLightningBolt,
IconRefresh,
IconTerminal,
IconTrash,
IconXCircle
} from '@appwrite.io/pink-icons-svelte';
@@ -22,6 +20,7 @@
export let showRedeploy = false;
export let showCancel = false;
export let activeDeployment: string;
export let inCard = false;
function getDownload(deploymentId: string) {
return (
@@ -33,7 +32,8 @@
<Popover placement="bottom-end" let:toggle>
<Button
text
text={!inCard}
secondary={inCard}
icon
size="s"
on:click={(e) => {
@@ -43,26 +43,19 @@
<Icon size="s" icon={IconDotsHorizontal} />
</Button>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root>
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
on:click={(e) => {
e.preventDefault();
selectedDeployment = deployment;
showRedeploy = true;
toggle(e);
}}>
Redeploy
</ActionMenu.Item.Button>
<ActionMenu.Item.Anchor
leadingIcon={IconTerminal}
href={`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/deployments/deployment-${deployment.$id}`}
on:click={(e) => {
e.preventDefault();
toggle(e);
}}>
View details
</ActionMenu.Item.Anchor>
<ActionMenu.Root noPadding>
{#if !inCard}
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
on:click={(e) => {
e.preventDefault();
selectedDeployment = deployment;
showRedeploy = true;
toggle(e);
}}>
Redeploy
</ActionMenu.Item.Button>
{/if}
{#if deployment?.status === 'ready' && deployment?.$id !== activeDeployment}
<ActionMenu.Item.Button
leadingIcon={IconLightningBolt}
@@ -75,7 +68,7 @@
Activate
</ActionMenu.Item.Button>
{/if}
{#if deployment?.status === 'ready'}
{#if deployment?.status === 'ready' || deployment?.status === 'failed'}
<ActionMenu.Item.Anchor
href={getDownload(deployment.$id)}
external
@@ -16,6 +16,7 @@
export let site: Models.Site;
export let deployment: Models.Deployment;
export let hideTitle = false;
let { status, buildLogs } = deployment;
@@ -76,32 +77,34 @@
</script>
<Layout.Stack gap="xl">
<Layout.Stack direction="row" justifyContent="space-between">
<Layout.Stack direction="row" alignItems="center" gap="s" inline>
<Typography.Text variant="m-500" color="--color-fgcolor-neutral-primary">
Deployment logs
</Typography.Text>
<Badge
content={capitalize(status)}
size="xs"
variant="secondary"
type={badgeType(status)} />
{#if !hideTitle}
<Layout.Stack direction="row" justifyContent="space-between">
<Layout.Stack direction="row" alignItems="center" gap="s" inline>
<Typography.Text variant="m-500" color="--color-fgcolor-neutral-primary">
Deployment logs
</Typography.Text>
<Badge
content={capitalize(status)}
size="xs"
variant="secondary"
type={badgeType(status)} />
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" inline>
{#if ['processing', 'building'].includes(status)}
<Typography.Code color="--color-fgcolor-neutral-secondary">
<Layout.Stack direction="row" alignItems="center" inline>
<p use:timer={{ start: deployment.$createdAt }} />
<Spinner size="s" />
</Layout.Stack>
</Typography.Code>
{:else}
<Typography.Code color="--color-fgcolor-neutral-secondary">
{formatTimeDetailed(deployment.buildTime)}
</Typography.Code>
{/if}
</Layout.Stack>
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" inline>
{#if ['processing', 'building'].includes(status)}
<Typography.Code color="--color-fgcolor-neutral-secondary">
<Layout.Stack direction="row" alignItems="center" inline>
<p use:timer={{ start: deployment.$createdAt }} />
<Spinner size="s" />
</Layout.Stack>
</Typography.Code>
{:else}
<Typography.Code color="--color-fgcolor-neutral-secondary">
{formatTimeDetailed(deployment.buildTime)}
</Typography.Code>
{/if}
</Layout.Stack>
</Layout.Stack>
{/if}
{#key buildLogs}
<Logs logs={buildLogs || 'No logs available'} bind:theme={$app.themeInUse} />
{/key}
@@ -23,7 +23,7 @@
<Modal title="Open on mobile" bind:show>
<span slot="description">Open the preview of your site on any mobile or tablet device.</span>
<Layout.Stack gap="l">
<Card>
<Card padding="l" radius="l">
<Layout.Stack justifyContent="center" alignItems="center">
<Image src={image} height={176} width={176} alt="QR code" />
</Layout.Stack>
@@ -1,6 +1,5 @@
<script lang="ts">
import { Card, Trim } from '$lib/components/index.js';
import Link from '$lib/elements/link.svelte';
import { Card } from '$lib/components/index.js';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
import type { Models } from '@appwrite.io/console';
@@ -17,22 +16,20 @@
import DeploymentSource from './deploymentSource.svelte';
import DeploymentCreatedBy from './deploymentCreatedBy.svelte';
import { Button } from '$lib/elements/forms';
import { IconExternalLink, IconInfo, IconQrcode } from '@appwrite.io/pink-icons-svelte';
import { IconInfo, IconQrcode } from '@appwrite.io/pink-icons-svelte';
import OpenOnMobileModal from './openOnMobileModal.svelte';
import DeploymentDomains from './deploymentDomains.svelte';
import { protocol } from '$routes/(console)/store';
import { app } from '$lib/stores/app';
import { base } from '$app/paths';
import { isCloud } from '$lib/system';
import { getApiEndpoint } from '$lib/stores/sdk';
export let deployment: Models.Deployment;
export let proxyRuleList: Models.ProxyRuleList = { total: 0, rules: [] };
export let proxyRuleList: Models.ProxyRuleList;
export let hideQRCode = false;
let show = false;
const siteUrl =
deployment.domain ?? (proxyRuleList.total > 0 ? proxyRuleList.rules[0].domain : undefined);
const siteUrl = proxyRuleList.total > 0 ? proxyRuleList.rules[0].domain : deployment.domain;
$: totalSize = humanFileSize((deployment?.buildSize ?? 0) + (deployment?.size ?? 0));
@@ -60,7 +57,6 @@
<Card padding="s" radius="m">
<Layout.Stack gap="l">
<!-- <Layout.Stack gap="xl" direction="row" alignItems="center"> -->
<div class="card-grid">
<Image
border
@@ -72,34 +68,11 @@
<Layout.Stack gap="xl">
<Layout.Stack direction="row" alignItems="flex-start">
<Layout.Stack direction="row" gap="xl">
{#if deployment.status === 'failed'}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Status
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
<Status status={deployment.status} label={deployment.status} />
</Typography.Text>
</Layout.Stack>
{:else}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Deployed
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
<DeploymentCreatedBy {deployment} />
</Typography.Text>
</Layout.Stack>
{/if}
<Layout.Stack gap="xxs">
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
Domains
</Typography.Text>
<DeploymentDomains domains={proxyRuleList} />
</Layout.Stack>
{#if siteUrl && !hideQRCode}
<Button icon secondary on:click={() => (show = true)}>
@@ -107,93 +80,110 @@
</Button>
{/if}
</Layout.Stack>
{#if proxyRuleList?.total}
<Layout.Stack gap="xxs">
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
Domains
</Typography.Text>
<DeploymentDomains domains={proxyRuleList} />
</Layout.Stack>
{:else if deployment.domain}
<Layout.Stack gap="xxs">
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
Domains
</Typography.Text>
<Link external href={`${$protocol}${deployment.domain}`} variant="muted">
<Layout.Stack gap="xxs" direction="row" alignItems="center">
<Trim alternativeTrim>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
{deployment.domain}
</Typography.Text>
</Trim>
<Icon icon={IconExternalLink} size="s" />
</Layout.Stack>
</Link>
</Layout.Stack>
{/if}
<Layout.Stack gap="xxl" direction="row" wrap="wrap">
{#if deployment?.buildTime}
<Layout.Stack direction="row" gap="xl">
{#if deployment.status === 'failed'}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Build time
Status
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
{formatTimeDetailed(deployment.buildTime)}
<Status status={deployment.status} label={deployment.status} />
</Typography.Text>
</Layout.Stack>
{:else}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Deployed
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
<DeploymentCreatedBy {deployment} />
</Typography.Text>
</Layout.Stack>
{/if}
<Layout.Stack gap="xxs" inline>
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
Total size
</Typography.Text>
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-primary">
{totalSize.value}{totalSize.unit}
</Typography.Text>
</Layout.Stack>
<Layout.Stack gap="xxs" inline>
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
<Layout.Stack direction="row" gap="xxs" alignItems="center">
Global CDN <Tooltip>
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
Optimized speed by caching content on servers closer to
users.
</span>
</Tooltip>
</Layout.Stack>
<Layout.Stack gap="xxl" direction="row" wrap="wrap">
<Layout.Stack gap="xxl" direction="row" wrap="wrap" inline>
{#if deployment?.buildTime}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Build time
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
{formatTimeDetailed(deployment.buildTime)}
</Typography.Text>
</Layout.Stack>
</Typography.Text>
<Layout.Stack inline alignItems="flex-start">
<Badge
size="xs"
variant="secondary"
type={isCloud ? 'success' : null}
content={isCloud ? 'Connected' : 'Available on Cloud'} />
{/if}
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
Total size
</Typography.Text>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-primary">
{totalSize.value}{totalSize.unit}
</Typography.Text>
</Layout.Stack>
</Layout.Stack>
<Layout.Stack gap="xxs" inline>
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-tertiary">
<Layout.Stack direction="row" gap="xxs" alignItems="center">
DDoS protection <Tooltip>
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
Safeguards your site by detecting and blocking malicious
traffic.
</span>
</Tooltip>
<Layout.Stack gap="xxl" direction="row" wrap="wrap" inline>
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
<Layout.Stack direction="row" gap="xxs" alignItems="center">
Global CDN <Tooltip>
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
Optimized speed by caching content on servers closer to
users.
</span>
</Tooltip>
</Layout.Stack>
</Typography.Text>
<Layout.Stack inline alignItems="flex-start">
<Badge
size="xs"
variant="secondary"
type={isCloud ? 'success' : null}
content={isCloud ? 'Connected' : 'Available on Cloud'} />
</Layout.Stack>
</Layout.Stack>
<Layout.Stack gap="xxs" inline>
<Typography.Text
variant="m-400"
color="--color-fgcolor-neutral-tertiary">
<Layout.Stack direction="row" gap="xxs" alignItems="center">
DDoS protection <Tooltip>
<Icon icon={IconInfo} size="s" />
<span slot="tooltip">
Safeguards your site by detecting and blocking malicious
traffic.
</span>
</Tooltip>
</Layout.Stack>
</Typography.Text>
<Layout.Stack inline alignItems="flex-start">
<Badge
size="xs"
variant="secondary"
type={isCloud ? 'success' : null}
content={isCloud ? 'Connected' : 'Available on Cloud'} />
</Layout.Stack>
</Typography.Text>
<Layout.Stack inline alignItems="flex-start">
<Badge
size="xs"
variant="secondary"
type={isCloud ? 'success' : null}
content={isCloud ? 'Connected' : 'Available on Cloud'} />
</Layout.Stack>
</Layout.Stack>
</Layout.Stack>
@@ -206,7 +196,6 @@
</Typography.Text>
</Layout.Stack>
</Layout.Stack>
<!-- </Layout.Stack> -->
</div>
{#if $$slots.footer}
<span
@@ -204,23 +204,26 @@
size="s" />
</PinkButton.Button>
<svelte:fragment slot="tooltip">
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root noPadding>
{#if !variable?.secret}
<ActionMenu.Item.Button
leadingIcon={IconPencil}
on:click={() => {
on:click={(e) => {
toggle(e);
currentVariable =
variable;
showUpdate = true;
}}>
Edit
Update
</ActionMenu.Item.Button>
{/if}
{#if !variable?.secret}
<ActionMenu.Item.Button
leadingIcon={IconEyeOff}
on:click={() => {
on:click={(e) => {
toggle(e);
currentVariable =
variable;
showSecretModal = true;
@@ -231,7 +234,8 @@
<ActionMenu.Item.Button
status="danger"
leadingIcon={IconTrash}
on:click={() => {
on:click={(e) => {
toggle(e);
currentVariable = variable;
showDelete = true;
}}>
@@ -1,12 +1,10 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import Card from '$lib/components/card.svelte';
import { Wizard } from '$lib/layout';
import { Layout, Typography, Icon, Lights, Step } from '@appwrite.io/pink-svelte';
import { Layout, Typography, Icon, Lights, Step, Card } from '@appwrite.io/pink-svelte';
import { IconArrowSmRight } from '@appwrite.io/pink-icons-svelte';
import Check from './(components)/check.svelte';
import type { PageData } from './$types';
import Button from '$lib/elements/forms/button.svelte';
import OpenOnMobileModal from '../../(components)/openOnMobileModal.svelte';
import SiteCard from '../../(components)/siteCard.svelte';
@@ -15,7 +13,7 @@
import AddCollaboratorModal from './(components)/addCollaboratorModal.svelte';
import { protocol } from '$routes/(console)/store';
export let data: PageData;
export let data;
let showConnectRepositry = false;
let showOpenOnMobile = false;
@@ -46,26 +44,31 @@
</Layout.Stack>
</Layout.Stack>
<Lights style="top: -100px; height:200px; width: 50%" />
<SiteCard deployment={data.deployment} hideQRCode>
<SiteCard
deployment={data.deployment}
proxyRuleList={data.proxyRuleList}
hideQRCode>
<svelte:fragment slot="footer">
<Button href={`${$protocol}${data.deployment.domain}`} external>
<Button href={`${$protocol}${data.proxyRuleList.rules[0].domain}`} external>
Visit site
</Button>
</svelte:fragment>
</SiteCard>
</Layout.Stack>
<div style="margin-block-start: var(--gap-xxl);">
<Step.List>
<Step.Item state="current" shortLine={true}>
<Layout.Stack direction="row" gap="l" wrap="wrap">
{#if !data.site.installationId && !data.site.providerRepositoryId}
<Card
isTile
<!-- To add spacing -->
<div></div>
<Step.List>
<Step.Item state="current" shortLine={true} badgeText="Next steps">
<Layout.Stack>
<Layout.Grid columns={!data.site.providerRepositoryId ? 4 : 3} columnsS={1}>
{#if !data.site.providerRepositoryId}
<Card.Button
radius="s"
padding="s"
isButton
on:click={() => (showConnectRepositry = true)}>
<Layout.Stack gap="s">
<Layout.Stack gap="s" style="height: 100%">
<Layout.Stack
direction="row"
justifyContent="space-between"
@@ -82,14 +85,13 @@
Connect to a new repository or an existing one.
</Typography.Text>
</Layout.Stack>
</Card>
</Card.Button>
{/if}
<Card
isTile
<Card.Link
radius="s"
padding="s"
href={`${base}/project-${$page.params.project}/sites/site-${data.site.$id}/domains`}>
<Layout.Stack gap="s">
<Layout.Stack gap="s" style="height: 100%">
<Layout.Stack
direction="row"
justifyContent="space-between"
@@ -104,14 +106,12 @@
Connect to an existing domain or add a new one.
</Typography.Text>
</Layout.Stack>
</Card>
<Card
isTile
</Card.Link>
<Card.Button
radius="s"
isButton
padding="s"
on:click={() => (showInviteCollaborator = true)}>
<Layout.Stack gap="s" justifyContent="flex-start">
<Layout.Stack gap="s" style="height: 100%">
<Layout.Stack
direction="row"
justifyContent="space-between"
@@ -126,14 +126,12 @@
Share your progress and start collaborating with your team.
</Typography.Text>
</Layout.Stack>
</Card>
<Card
isTile
</Card.Button>
<Card.Button
radius="s"
isButton
padding="s"
on:click={() => (showOpenOnMobile = true)}>
<Layout.Stack gap="s">
<Layout.Stack gap="s" style="height: 100%">
<Layout.Stack
direction="row"
justifyContent="space-between"
@@ -149,11 +147,11 @@
device.
</Typography.Text>
</Layout.Stack>
</Card>
</Layout.Stack>
</Step.Item>
</Step.List>
</div>
</Card.Button>
</Layout.Grid>
</Layout.Stack>
</Step.Item>
</Step.List>
</Layout.Stack>
</div>
@@ -7,16 +7,16 @@ export const load = async ({ url, depends }) => {
depends(Dependencies.SITE);
if (!url.searchParams.has('site')) error(404, 'Deployment is not optional');
const siteId = url.searchParams.get('site');
const site = await sdk.forProject.sites.get(siteId);
const deployment = await sdk.forProject.sites.getDeployment(siteId, site.deploymentId);
const { rules } = await sdk.forProject.proxy.listRules([
Query.equal('resourceId', site.$id),
Query.equal('resourceType', 'site'),
Query.limit(1)
const [site, proxyRuleList] = await Promise.all([
sdk.forProject.sites.get(siteId),
sdk.forProject.proxy.listRules([
Query.equal('resourceId', siteId),
Query.equal('resourceType', 'site')
])
]);
return {
site,
deployment,
rule: rules[0]
deployment: await sdk.forProject.sites.getDeployment(siteId, site.deploymentId),
proxyRuleList
};
};
@@ -15,7 +15,7 @@
import Details from '../../details.svelte';
import ProductionBranch from '../../productionBranch.svelte';
import Aside from '../../aside.svelte';
import { BuildRuntime, Framework, ID, Query, ResourceType, Type } from '@appwrite.io/console';
import { BuildRuntime, Framework, ID, ResourceType, Type } from '@appwrite.io/console';
import type { Models } from '@appwrite.io/console';
import { onMount } from 'svelte';
import Configuration from '../../configuration.svelte';
@@ -1,6 +1,6 @@
<script lang="ts">
import { base } from '$app/paths';
import { EmptySearch, Pagination, PaginationWithLimit } from '$lib/components';
import { EmptySearch, PaginationWithLimit } from '$lib/components';
import { Button, InputSearch } from '$lib/elements/forms';
import { page } from '$app/stores';
import Wizard from '$lib/layout/wizard.svelte';
@@ -116,7 +116,7 @@
</svelte:fragment>
<Layout.Stack gap="l">
{#if data.templates?.length > 0}
<Layout.GridBox>
<Layout.Grid columns={3} columnsXS={2} columnsXXS={1}>
{#each data.templates as template}
{@const templateFrameworks = template.frameworks.map((t) => t.name)}
@@ -135,7 +135,7 @@
</Card.Media>
</Card.Link>
{/each}
</Layout.GridBox>
</Layout.Grid>
{:else}
<EmptySearch
hidePagination
@@ -134,7 +134,7 @@
framework.buildCommand,
framework.outputDirectory,
framework.adapter,
selectedInstallationId || undefined,
connectBehaviour === 'later' ? undefined : selectedInstallationId || undefined,
framework.fallbackFile,
selectedRepository || undefined,
branch || undefined,
@@ -1,12 +1,13 @@
<script lang="ts">
import { LabelCard } from '$lib/components';
import { consoleVariables } from '$routes/(console)/store';
import { Layout } from '@appwrite.io/pink-svelte';
export let connectBehaviour: 'now' | 'later' = 'now';
const isVcsEnabled = $consoleVariables?._APP_VCS_ENABLED === true;
</script>
<div style="display: grid; gap: 1rem; grid-template-columns: 1fr 1fr;">
<Layout.Grid columns={2} columnsXS={1}>
<LabelCard
value="now"
bind:group={connectBehaviour}
@@ -18,4 +19,4 @@
<svelte:fragment slot="title">Connect later</svelte:fragment>
Deploy now and connect your version control later via CLI or Git integration in your settings.
</LabelCard>
</div>
</Layout.Grid>
@@ -1,5 +1,5 @@
<script lang="ts">
import { Button, InputPassword } from '$lib/elements/forms';
import { Button } from '$lib/elements/forms';
import { Modal } from '$lib/components';
import { InputText } from '$lib/elements/forms';
import type { Models } from '@appwrite.io/console';
@@ -40,14 +40,13 @@
<Modal bind:show onSubmit={handleVariable} title="Update variable">
<span slot="description">
Set the environment variables or secret that will be passed to your site. Global variables
can be set in <Link
Update the environment variable for your site. Global variables can be set in <Link
variant="muted"
href={`${base}/project-${$page.params.project}/settings`}>project settings</Link
>.
</span>
<Layout.Stack gap="xxl">
<Layout.Stack>
<Layout.Stack direction="row">
<InputText
id="key"
label="Key"
@@ -56,12 +55,7 @@
required
autofocus
autocomplete={false} />
<InputPassword
id="value"
label="Value"
placeholder="Enter value"
bind:value={pair.value}
minlength={0} />
<InputText id="value" label="Value" placeholder="Enter value" bind:value={pair.value} />
</Layout.Stack>
<Selector.Checkbox
size="s"
@@ -2,24 +2,15 @@ import Breadcrumbs from './breadcrumbs.svelte';
import Header from './header.svelte';
import { Dependencies } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import { Query } from '@appwrite.io/console';
import { error } from '@sveltejs/kit';
export const load = async ({ depends, params }) => {
depends(Dependencies.SITE);
try {
const [site, proxyRuleList] = await Promise.all([
sdk.forProject.sites.get(params.site),
sdk.forProject.proxy.listRules([
Query.equal('resourceType', 'site'),
Query.equal('resourceId', params.site),
Query.orderDesc('')
])
]);
const [site] = await Promise.all([sdk.forProject.sites.get(params.site)]);
return {
site,
proxyRuleList,
header: Header,
breadcrumbs: Breadcrumbs
};
@@ -5,14 +5,20 @@ import { Query } from '@appwrite.io/console';
export const load = async ({ params, depends, parent }) => {
depends(Dependencies.SITE);
depends(Dependencies.SITES_DOMAINS);
const { site, proxyRuleList } = await parent();
const { site } = await parent();
const [deploymentList, prodReadyDeployments] = await Promise.all([
const [deploymentList, prodReadyDeployments, proxyRuleList] = await Promise.all([
sdk.forProject.sites.listDeployments(params.site, [Query.limit(4), Query.orderDesc('')]),
sdk.forProject.sites.listDeployments(params.site, [
Query.limit(1)
// Query.equal('status', 'ready')
// Query.equal('live', true)
]),
sdk.forProject.proxy.listRules([
Query.equal('resourceType', 'site'),
Query.equal('resourceId', params.site),
Query.orderDesc('')
])
]);
return {
@@ -104,7 +104,7 @@
<Filters query={data.query} {columns} clearOnClick>
<svelte:fragment slot="mobile" let:disabled let:toggle>
<Tag on:click={toggle} {disabled}>
<Tag size="m" on:click={toggle} {disabled}>
<span class="text">More filters</span>
<span class="icon-cheveron-down" />
</Tag>
@@ -36,7 +36,7 @@
<span slot="description"> Manually deploy a site by uploading any file(s) or folder. </span>
<InputFile
label="Upload a zip file (tar.gz) containing your function source code"
label="Upload a zip file (tar.gz) containing your sites source code"
allowedFileExtensions={['gz']}
bind:files
required />
@@ -10,6 +10,15 @@
import SiteCard from '../../../(components)/siteCard.svelte';
import Logs from '../../../(components)/logs.svelte';
import Card from '$lib/components/card.svelte';
import { Button } from '$lib/elements/forms';
import DeploymentActionMenu from '../../../(components)/deploymentActionMenu.svelte';
import DeleteDeploymentModal from '../deleteDeploymentModal.svelte';
import CancelDeploymentModal from '../cancelDeploymentModal.svelte';
import RedeployModal from '../../../redeployModal.svelte';
import ActivateDeploymentModal from '../../../activateDeploymentModal.svelte';
import { protocol } from '$routes/(console)/store';
import { Accordion } from '@appwrite.io/pink-svelte';
import { capitalize } from '$lib/helpers/string';
export let data;
@@ -33,11 +42,54 @@
}
});
});
let showRedeploy = false;
let showActivate = false;
let showDelete = false;
let showCancel = false;
</script>
<Container>
<SiteCard deployment={data.deployment} proxyRuleList={data.proxyRuleList} />
<Card isTile>
<Logs site={data.site} deployment={data.deployment} />
<SiteCard deployment={data.deployment} proxyRuleList={data.proxyRuleList}>
<svelte:fragment slot="footer">
{#if data.deployment?.status === 'ready'}
<Button href={`${$protocol}${data.proxyRuleList.rules[0].domain}`} external>
Visit
</Button>
{/if}
<Button secondary on:click={() => (showRedeploy = true)}>Redeploy</Button>
<DeploymentActionMenu
inCard
deployment={data.deployment}
selectedDeployment={data.deployment}
bind:showRedeploy
bind:showActivate
bind:showDelete
bind:showCancel
activeDeployment={data.site.deploymentId} />
</svelte:fragment>
</SiteCard>
<Card isTile padding="s">
<Accordion
title="Deployment Actions"
badge={capitalize(data.deployment.status)}
open={data.deployment.status !== 'ready'}
hideDivider>
<Logs site={data.site} deployment={data.deployment} hideTitle />
</Accordion>
</Card>
</Container>
<DeleteDeploymentModal selectedDeployment={data.deployment} bind:showDelete />
<CancelDeploymentModal selectedDeployment={data.deployment} bind:showCancel />
<RedeployModal
selectedDeploymentId={data.deployment.$id}
bind:show={showRedeploy}
site={data.site} />
{#if showActivate}
<ActivateDeploymentModal
siteId={data.site.$id}
selectedDeploymentId={data.deployment.$id}
bind:show={showActivate} />
{/if}
@@ -1,14 +1,19 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import type { PageLoad } from './$types';
import { Query } from '@appwrite.io/console';
export const load: PageLoad = async ({ params, depends, parent }) => {
depends(Dependencies.DEPLOYMENT);
const { site, proxyRuleList } = await parent();
const { site } = await parent();
const [deployment] = await Promise.all([
sdk.forProject.sites.getDeployment(params.site, params.deployment)
const [deployment, proxyRuleList] = await Promise.all([
sdk.forProject.sites.getDeployment(params.site, params.deployment),
sdk.forProject.proxy.listRules([
Query.equal('resourceId', params.deployment),
Query.equal('resourceType', 'deployment')
])
]);
return {
@@ -12,7 +12,8 @@
} from '$lib/components/filters/store';
import { SelectSearchCheckbox } from '$lib/elements';
import type { Column } from '$lib/helpers/types';
import { ActionMenu, Popover, Tag } from '@appwrite.io/pink-svelte';
import { IconChevronDown, IconChevronUp } from '@appwrite.io/pink-icons-svelte';
import { ActionMenu, Icon, Popover, Tag } from '@appwrite.io/pink-svelte';
import { type Writable } from 'svelte/store';
export let columns: Writable<Column[]>;
@@ -184,13 +185,13 @@
{#each [typeFilter] as filter}
<Popover let:toggle let:showing>
<!--TODO: add tracking back event="apply_quick_filter" -->
<Tag size="s" on:click={toggle}>
<Tag on:click={toggle}>
{#key filter.tag}
<span use:tagFormat>
{filter?.tag ?? filter.title}
</span>
{/key}
<span class:icon-cheveron-down={!showing} class:icon-cheveron-up={showing}> </span>
<Icon icon={showing ? IconChevronUp : IconChevronDown} slot="end" size="s" />
</Tag>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root noPadding>
@@ -233,14 +234,14 @@
<Popover let:toggle let:showing>
<!--TODO: add tracking back event="apply_quick_filter" -->
<Tag size="s" on:click={toggle}>
<Tag on:click={toggle}>
{#key filter.tag}
<span use:tagFormat>
{filter?.tag ?? filter.title}
</span>
{/key}
<span class:icon-cheveron-down={!showing} class:icon-cheveron-up={showing}> </span>
<Icon icon={showing ? IconChevronUp : IconChevronDown} slot="end" size="s" />
</Tag>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root noPadding>
@@ -16,16 +16,7 @@ export const columns = writable<Column[]>([
elements: ['ready', 'processing', 'building', 'waiting', 'cancelled', 'failed'],
filter: false
},
{
id: 'domains',
title: 'Domains',
type: 'string',
show: true,
width: 150,
array: true,
format: 'string',
filter: false
},
{
id: 'buildTime',
title: 'Build time',
@@ -1,5 +1,5 @@
<script lang="ts">
import { Id, Trim } from '$lib/components';
import { Id } from '$lib/components';
import type { PageData } from './$types';
import { type Models } from '@appwrite.io/console';
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
@@ -13,7 +13,6 @@
import Cancel from './cancelDeploymentModal.svelte';
import { base } from '$app/paths';
import { Layout, Status, Table } from '@appwrite.io/pink-svelte';
import { columns } from './store';
import ActivateDeploymentModal from '../../activateDeploymentModal.svelte';
import { deploymentStatusConverter } from '../store';
@@ -63,14 +62,6 @@
label={capitalize(status)} />
{/if}
</Table.Cell>
{:else if column.id === 'domains'}
<Table.Cell width={column?.width?.toString() ?? ''}>
<div style="max-width: 150px">
<Trim>
{deployment.domain}
</Trim>
</div>
</Table.Cell>
{:else if column.id === 'type'}
<Table.Cell width={column?.width?.toString() ?? ''}>
<DeploymentSource {deployment} />
@@ -6,7 +6,6 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { invalidate } from '$app/navigation';
import { Heading } from '$lib/components';
import { page } from '$app/stores';
import UpdateBuildSettings from './updateBuildSettings.svelte';
import UpdateTimeout from './updateTimeout.svelte';
@@ -57,7 +56,6 @@
</script>
<Container>
<Heading tag="h2" size="5">Settings</Heading>
<UpdateName site={data.site} />
<UpdateRepository site={data.site} installations={data.installations} />
<UpdateBuildSettings site={data.site} frameworks={data.frameworks.frameworks} />
@@ -1,6 +1,5 @@
<script lang="ts">
import { BoxAvatar, CardGrid } from '$lib/components';
import Heading from '$lib/components/heading.svelte';
import { Button } from '$lib/elements/forms';
import { toLocaleDateTime } from '$lib/helpers/date';
import type { Models } from '@appwrite.io/console';
@@ -28,4 +27,4 @@
</svelte:fragment>
</CardGrid>
<Delete bind:showDelete />
<Delete {site} bind:showDelete />
@@ -6,13 +6,15 @@
import Confirm from '$lib/components/confirm.svelte';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { type Models } from '@appwrite.io/console';
export let site: Models.Site;
export let showDelete = false;
const siteId = $page.params.site;
let error: string;
const handleSubmit = async () => {
try {
await sdk.forProject.sites.delete(siteId);
await sdk.forProject.sites.delete(site.$id);
showDelete = false;
addNotification({
type: 'success',
@@ -116,7 +116,7 @@
<Form onSubmit={updateConfiguration}>
<CardGrid>
<svelte:fragment slot="title">Repository</svelte:fragment>
<svelte:fragment slot="title">Git repository</svelte:fragment>
Automatically deploy changes for every commit pushed to your Git repository.
<svelte:fragment slot="aside">
{#if repository === false}
@@ -204,12 +204,13 @@
{:else if site.installationId || installations?.total}
<PinkCard.Base padding="none" border="dashed">
<Empty
type="secondary"
title="No repository is connected to this site yet"
description="Connect to enable automatic deployments">
<svelte:fragment slot="actions">
<Button secondary on:click={() => showConnectRepo.set(true)}>
<Icon icon={IconGithub} size="s" />
Connect repository
<Icon icon={IconGithub} size="s" slot="start" />
Connect Git repository
</Button>
</svelte:fragment>
</Empty>
@@ -1,5 +1,9 @@
<script lang="ts">
import { Container } from '$lib/layout';
export let data;
$: console.log(data.usage);
</script>
<Container>Coming soon</Container>
@@ -0,0 +1,13 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { Query } from '@appwrite.io/console';
export const load = async ({ params, depends, parent }) => {
depends(Dependencies.SITES);
const usage = await sdk.forProject.sites.listUsage();
return {
usage
};
};