design review: deployment and other screns

This commit is contained in:
Arman
2025-02-20 14:28:16 +01:00
parent 5849a2bc19
commit 7132a87d9a
12 changed files with 195 additions and 146 deletions
+1 -1
View File
@@ -23,7 +23,7 @@
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332",
"@appwrite.io/pink-legacy": "^1.0.1",
"@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d",
"@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
+12 -12
View File
@@ -21,8 +21,8 @@ importers:
specifier: ^1.0.1
version: 1.0.1
'@appwrite.io/pink-svelte':
specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d
version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552
version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
@@ -215,14 +215,14 @@ packages:
resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@d13e864}
version: 1.2.1
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@134aa5d0d1920f2524d866d213e1134cb62f8962':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@134aa5d0d1920f2524d866d213e1134cb62f8962}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@e87d5523b50e063bfe0d3b846d5db171a24b0792':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@e87d5523b50e063bfe0d3b846d5db171a24b0792}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
@@ -236,8 +236,8 @@ packages:
'@appwrite.io/pink-legacy@1.0.1':
resolution: {integrity: sha512-e5IZx2drqSxgl2WXvmr0eLfg/WiOCzuqQE8oksD+9GoFBkcL9HWvXul5GjFni3RBAN9XFRL3nUExGk4T0H8sFw==}
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d}
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552}
version: 1.0.0-next.85
peerDependencies:
react-dom: ^18.0.0
@@ -4099,11 +4099,11 @@ snapshots:
'@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@d13e864': {}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@134aa5d0d1920f2524d866d213e1134cb62f8962(svelte@4.2.19)':
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@2ff4e332(svelte@4.2.19)':
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@e87d5523b50e063bfe0d3b846d5db171a24b0792(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
@@ -4116,9 +4116,9 @@ snapshots:
'@appwrite.io/pink-icons': 1.0.0
the-new-css-reset: 1.11.3
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@134aa5d(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@e87d552(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
dependencies:
'@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@134aa5d0d1920f2524d866d213e1134cb62f8962(svelte@4.2.19)
'@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@e87d5523b50e063bfe0d3b846d5db171a24b0792(svelte@4.2.19)
'@floating-ui/dom': 1.6.13
'@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.3(svelte@4.2.19))(svelte@4.2.19)
'@melt-ui/svelte': 0.86.3(svelte@4.2.19)
+1 -1
View File
@@ -16,7 +16,7 @@
<Typography.Text size="s" truncate color="--color-fgcolor-neutral-primary"
>{value}</Typography.Text>
{:else}
<Skeleton variant="line" width={100} height={20} />
<Skeleton variant="line" width={100} height={19.5} />
{/if}
</slot>
</Layout.Stack>
@@ -11,6 +11,7 @@
element?: HTMLInputElement | undefined;
indeterminate?: boolean;
size?: 's' | 'm';
description?: string;
}
export let id: string = '';
@@ -20,6 +21,7 @@
export let disabled = false;
export let element: HTMLInputElement | undefined = undefined;
export let size: $$Props['size'] = 's';
export let description = '';
let error: string;
const handleInvalid = (event: Event) => {
@@ -47,6 +49,7 @@
{size}
{label}
{required}
{description}
on:invalid={handleInvalid}
on:click
on:change />
@@ -1,22 +1,29 @@
<script lang="ts">
import Link from '$lib/elements/link.svelte';
import { timeFromNow } from '$lib/helpers/date';
import { timeFromNow, toLocaleDateTime } from '$lib/helpers/date';
import { capitalize } from '$lib/helpers/string';
import type { Models } from '@appwrite.io/console';
import { Tooltip } from '@appwrite.io/pink-svelte';
export let deployment: Models.Deployment;
</script>
<p>
{#if deployment.providerCommitAuthor}
<span title={deployment.$updatedAt}>
{capitalize(timeFromNow(deployment.$updatedAt))}
</span>
<Tooltip>
<span>
{capitalize(timeFromNow(deployment.$updatedAt))}
</span>
<span slot="tooltip">{toLocaleDateTime(deployment.$updatedAt)}</span>
</Tooltip>
by <Link href={deployment.providerCommitAuthorUrl} external
>{deployment.providerCommitAuthor}</Link>
{:else}
<span title={deployment.$updatedAt}>
{capitalize(timeFromNow(deployment.$updatedAt))}
</span>
<Tooltip>
<span>
{capitalize(timeFromNow(deployment.$updatedAt))}
</span>
<span slot="tooltip">{toLocaleDateTime(deployment.$updatedAt)}</span>
</Tooltip>
{/if}
</p>
@@ -28,7 +28,7 @@
</Link>
</Layout.Stack>
<svelte:fragment slot="tooltip">
<ActionMenu.Root>
<ActionMenu.Root noPadding>
<ActionMenu.Item.Anchor
href={deployment.providerRepositoryUrl}
external
@@ -42,7 +42,6 @@
{deployment.providerBranch}
</ActionMenu.Item.Anchor>
{#if deployment?.providerCommitMessage && deployment?.providerCommitHash && deployment?.providerCommitUrl}
<!-- TODO: either the Popover or this Anchor needs to correctly manage the width -->
<ActionMenu.Item.Anchor
href={deployment.providerCommitUrl}
external
@@ -7,6 +7,7 @@
import { Button } from '$lib/elements/forms';
import { capitalize } from '$lib/helpers/string';
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
import { app } from '$lib/stores/app';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import type { Models } from '@appwrite.io/console';
@@ -102,7 +103,7 @@
</Layout.Stack>
</Layout.Stack>
{#key buildLogs}
<Logs logs={buildLogs || 'No logs available'} />
<Logs logs={buildLogs || 'No logs available'} bind:theme={$app.themeInUse} />
{/key}
{#if ['processing', 'building'].includes(status)}
<Layout.Stack alignItems="flex-end">
@@ -7,23 +7,33 @@
import { Button } from '$lib/elements/forms';
import { protocol } from '$routes/(console)/store';
import InstantRollbackDomain from './instantRollbackDomain.svelte';
import { base } from '$app/paths';
import { page } from '$app/stores';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { app } from '$lib/stores/app';
import EmptyDeploymentDark from './empty-deployment-dark.svg';
import EmptyDeploymentLight from './empty-deployment-light.svg';
import { sdk } from '$lib/stores/sdk';
import { invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
import { onMount } from 'svelte';
import { page } from '$app/stores';
export let data;
let showRollback = false;
$: console.log(data.site);
$: console.log(data.deployment);
$: console.log(data.deploymentList);
$: console.log(data.proxyRuleList);
let unsubscribe: { (): void };
// TODO: dark mode empty state
onMount(() => {
unsubscribe = sdk.forConsole.client.subscribe('console', (response) => {
if (response.events.includes(`sites.${$page.params.site}.deployments.*`)) {
console.log('test');
invalidate(Dependencies.SITE);
}
});
});
// $: console.log(data.site);
$: console.log(data.deployment);
// $: console.log(data.deploymentList);
// $: console.log(data.proxyRuleList);
</script>
<Container>
@@ -37,7 +47,7 @@
>Instant rollback</Button>
</svelte:fragment>
</SiteCard>
{:else}
{:else if data.deployment?.status === 'building'}
<Card.Base padding="none">
<Empty
title="Deployment is still building"
@@ -46,21 +56,17 @@
Your build is running. When it completes, this page will automatically
update with the latest deployment.
</span>
<Layout.Stack
direction="row"
gap="s"
alignItems="center"
justifyContent="center"
slot="actions">
<!-- TODO: enable it after we have copy again-->
<!-- <Button
text
href={`${base}/console/project-${$page.params.project}/sites/site-${data.site.$id}/deployments/deployment-${data.deployment.$id}`}>
View logs
</Button> -->
<Button secondary on:click={() => invalidate(Dependencies.SITE)}
>Reload</Button>
</Layout.Stack>
</Empty>
</Card.Base>
{:else}
<Card.Base padding="none">
<Empty
title="No deployments found"
src={$app.themeInUse === 'dark' ? EmptyDeploymentDark : EmptyDeploymentLight}>
<span slot="description">
You haven't deployed any sites yet. Get started by deploying your first
site.
</span>
</Empty>
</Card.Base>
{/if}
@@ -94,11 +94,12 @@
<Icon size="s" icon={IconPlus} />
Create deployment
</Button>
<svelte:fragment slot="tooltip">
<ActionMenu.Root>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root noPadding>
<ActionMenu.Item.Button
badge="Recommended"
on:click={() => {
on:click={(e) => {
toggle(e);
if (!hasInstallation) {
showConnectRepo = true;
} else {
@@ -108,13 +109,15 @@
Git
</ActionMenu.Item.Button>
<ActionMenu.Item.Button
on:click={() => {
on:click={(e) => {
toggle(e);
showConnectCLI = true;
}}>
CLI
</ActionMenu.Item.Button>
<ActionMenu.Item.Button
on:click={() => {
on:click={(e) => {
toggle(e);
showConnectManual = true;
}}>
Manual
@@ -4,80 +4,81 @@
import { Repositories } from '$lib/components/git';
import { Dependencies } from '$lib/constants';
import { Link } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import InputSelectSearch from '$lib/elements/forms/inputSelectSearch.svelte';
import { Button, InputCheckbox, InputSelect } from '$lib/elements/forms';
import { timeFromNow } from '$lib/helpers/date';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { installation, repository, sortBranches } from '$lib/stores/vcs';
import type { BuildRuntime, Framework, Models } from '@appwrite.io/console';
import { Type, type Models } from '@appwrite.io/console';
import { IconGithub } from '@appwrite.io/pink-icons-svelte';
import { Icon, InlineCode, Layout, Spinner, Typography } from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
import { Icon, Layout, Skeleton, Typography } from '@appwrite.io/pink-svelte';
export let show = false;
export let site: Models.Site;
let installations = { installations: [], total: 0 };
let hasRepository = !!site?.providerRepositoryId;
let selectedRepository: string = null;
let selectedRepository: string = site.providerRepositoryId;
let branch: string = null;
let activate = true;
let error = '';
onMount(async () => {
installations = await sdk.forProject.vcs.listInstallations();
if (!site?.installationId && installations.total > 0) {
installation.set(installations.installations[0]);
}
if (!$repository?.id && hasRepository) {
$repository = await sdk.forProject.vcs.getRepository(
$installation.$id,
site.providerRepositoryId
async function loadInstallations() {
try {
installations = await sdk.forProject.vcs.listInstallations();
if (!site?.installationId && installations.total > 0) {
installation.set(installations.installations[0]);
}
$installation = installations.installations.find(
(installation) => installation.$id === site.installationId
);
if (!$installation?.$id) {
$installation = installations.installations[0];
}
} catch (error) {
console.log(error);
}
console.log(installations);
});
}
async function loadBranches() {
const { branches } = await sdk.forProject.vcs.listRepositoryBranches(
$installation.$id,
selectedRepository
);
const sorted = sortBranches(branches);
branch = sorted[0]?.name ?? null;
async function load() {
try {
await loadInstallations();
if (!$repository?.id && hasRepository) {
$repository = await sdk.forProject.vcs.getRepository(
$installation.$id,
site.providerRepositoryId
);
}
const branchList = await sdk.forProject.vcs.listRepositoryBranches(
$installation.$id,
selectedRepository
);
if (!branch) {
branch = 'main';
console.log(branchList);
const sorted = sortBranches(branchList.branches);
branch = sorted[0]?.name ?? null;
if (!branch) {
branch = 'main';
}
return sorted;
} catch (error) {
console.log(installations);
console.log(error);
}
return sorted;
}
async function createDeployment() {
try {
if (!site.installationId || !site.providerRepositoryId || !branch) {
await sdk.forProject.sites.update(
site.$id,
site.name,
site?.framework as Framework,
site.enabled || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
site.outputDirectory || undefined,
(site?.buildRuntime as BuildRuntime) || undefined,
site.adapter || undefined,
site.fallbackFile || undefined,
site.installationId || $installation.$id || undefined,
site.providerRepositoryId || $repository.id || undefined,
branch,
site.providerSilentMode || undefined,
undefined //TODO: add dir?
);
}
await sdk.forProject.sites.createVcsDeployment(site.$id, Type.Branch, branch, activate);
show = false;
invalidate(Dependencies.DEPLOYMENTS);
addNotification({
message: 'Deployment has been created successfully',
message: activate
? 'Deployment is in progress. It will be automatically activated after build step completes.'
: 'Deployment is in progress. You can activate it after build step completes.',
type: 'success'
});
} catch (e) {
@@ -88,26 +89,26 @@
<Modal title="Create Git deployment" bind:show onSubmit={createDeployment} bind:error>
<span slot="description">
Enter a valid commit reference to create a new deployment from <InlineCode code="test" /> or
use the CLI to deploy. <Link href="#">Learn more</Link>
Enter a valid commit reference to create a new deployment. <Link href="#">Learn more</Link>
</span>
{#if installations && hasRepository}
<Card isTile padding="s" radius="s">
<Layout.Stack
direction="row"
justifyContent="space-between"
alignItems="center"
gap="xs">
<Layout.Stack direction="row" alignItems="center" gap="s">
<Icon size="s" icon={IconGithub} />
<Typography.Text variant="m-400" color="--color-fgcolor-neutral-primary">
{$repository?.organization}/{$repository?.name}
</Typography.Text>
{#if hasRepository}
{#await load()}
<Card isTile padding="xs" radius="s" variant="secondary">
<Layout.Stack
direction="row"
justifyContent="space-between"
alignItems="center"
gap="xs">
<Layout.Stack direction="row" alignItems="center" gap="s">
<Icon size="s" icon={IconGithub} />
<Skeleton variant="line" width={100} height={19.6} />
</Layout.Stack>
</Layout.Stack>
</Card>
<Layout.Stack gap="s">
<Skeleton variant="line" width={100} height={19.6} />
<Skeleton variant="line" width={350} height={31} />
</Layout.Stack>
</Card>
{#await loadBranches()}
<Spinner size="s" />
{:then branches}
{@const options =
branches
@@ -120,24 +121,48 @@
?.sort((a, b) => {
return a.label > b.label ? 1 : -1;
}) ?? []}
<InputSelectSearch
<Card isTile padding="xs" radius="s" variant="secondary">
<Layout.Stack
direction="row"
justifyContent="space-between"
alignItems="center"
gap="xs">
<Layout.Stack direction="row" alignItems="center" gap="s" inline>
<Icon icon={IconGithub} />
<Link
external
href={`https://github.com/${$repository?.organization}/${$repository?.name}`}>
<Layout.Stack direction="row" alignItems="center" gap="s" inline>
{$repository?.organization}/{$repository?.name}
</Layout.Stack>
</Link>
</Layout.Stack>
<Typography.Caption variant="400" color="--color-fgcolor-neutral-tertiary">
Last updated {timeFromNow($repository?.pushedAt)}
</Typography.Caption>
</Layout.Stack>
</Card>
<InputSelect
required={true}
id="branch"
label="Production branch"
placeholder="Select branch"
hideRequired
bind:value={branch}
bind:search={branch}
isSearchable
on:select={(event) => {
branch = event.detail.value;
}}
interactiveOutput
name="branch"
{options} />
{#if branch}
<InputCheckbox
label="Activate deployment after build"
id="activate"
description="This deployment will automatically activate after the build completes. If
unchecked, it will remain inactive, and you can activate it manually later."
bind:checked={activate} />
{/if}
{/await}
{/if}
{#if !hasRepository}
{:else}
<Repositories
bind:selectedRepository
installationList={installations}
@@ -153,7 +178,8 @@
{/if}
<svelte:fragment slot="footer">
<Button text size="s" on:click={() => (show = false)}>Cancel</Button>
<Button size="s" disabled={!$installation?.$id || !selectedRepository || !branch}
>Create</Button>
<Button submit size="s" disabled={!$installation?.$id || !selectedRepository || !branch}>
Create
</Button>
</svelte:fragment>
</Modal>
@@ -55,21 +55,25 @@
});
async function fetchUsage() {
metrics.forEach((metric) => {
metric.value = null;
});
metrics = metrics;
try {
const usage = await sdk.forProject.sites.getUsage($page.params.site, range);
metrics = metrics.map((metric) => {
metric.value = usage[metric.id] ?? '-';
return metric;
// Add timeout to make it look nicer
setTimeout(async () => {
metrics.forEach((metric) => {
metric.value = null;
});
metrics = metrics;
console.log(usage);
} catch (error) {
console.log(error);
}
try {
const usage = await sdk.forProject.sites.getUsage($page.params.site, range);
metrics = metrics.map((metric) => {
metric.value = usage[metric.id] ?? '-';
return metric;
});
metrics = metrics;
console.log(usage);
} catch (error) {
console.log(error);
}
}, 800);
}
$: console.log(metrics);
@@ -95,9 +99,9 @@
on:change={fetchUsage} />
</div>
</Layout.Stack>
<Layout.GridBox gap="m" itemSize="154px">
<Layout.Stack gap="m" direction="row">
{#each metrics as metric}
<UsageCard description={metric.description} bind:value={metric.value} />
{/each}
</Layout.GridBox>
</Layout.Stack>
</Layout.Stack>
@@ -193,7 +193,7 @@
<span class:icon-cheveron-down={!showing} class:icon-cheveron-up={showing}> </span>
</Tag>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root>
<ActionMenu.Root noPadding>
{#each filter.options as option (option.value + option.checked)}
<SelectSearchCheckbox
padding={8}