From b15d7cbb56a0b9cfd2d771ea79b1bd395c3df6da Mon Sep 17 00:00:00 2001
From: Arman
Date: Wed, 13 Nov 2024 15:30:44 +0100
Subject: [PATCH] feat: deployments
---
src/lib/components/emptyFilter.svelte | 40 +--
src/lib/components/emptySearch.svelte | 2 +-
src/lib/components/filters/filters.svelte | 15 +-
src/lib/components/viewSelector.svelte | 1 +
src/lib/elements/forms/button.svelte | 2 +-
.../sites/site-[site]/breadcrumbs.svelte | 5 +
.../site-[site]/deployments/+layout.svelte | 153 ++++++++++
.../sites/site-[site]/deployments/+layout.ts | 28 ++
.../site-[site]/deployments/+page.svelte | 198 ++++++++++++
.../sites/site-[site]/deployments/+page.ts | 32 ++
.../site-[site]/deployments/cancel.svelte | 49 +++
.../site-[site]/deployments/delete.svelte | 49 +++
.../deployment-[deployment]/+page.svelte | 36 +++
.../deployment-[deployment]/+page.ts | 13 +
.../deployment-[deployment]/store.ts | 5 +
.../deployments/deploymentCard.svelte | 121 ++++++++
.../deployments/deploymentCreatedBy.svelte | 14 +
.../deployments/deploymentDomains.svelte | 38 +++
.../deployments/deploymentSource.svelte | 38 +++
.../deployments/quickFilters.svelte | 281 ++++++++++++++++++
.../deployments/redeployModal.svelte | 56 ++++
.../sites/site-[site]/deployments/store.ts | 25 ++
.../site-[site]/deployments/table.svelte | 196 ++++++++++++
23 files changed, 1369 insertions(+), 28 deletions(-)
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.ts
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.ts
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancel.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/delete.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.ts
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/store.ts
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCard.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCreatedBy.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentDomains.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentSource.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/redeployModal.svelte
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
create mode 100644 src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
diff --git a/src/lib/components/emptyFilter.svelte b/src/lib/components/emptyFilter.svelte
index 6e13c0cd8c..41b7fcccae 100644
--- a/src/lib/components/emptyFilter.svelte
+++ b/src/lib/components/emptyFilter.svelte
@@ -1,26 +1,28 @@
-
-
-
-
Sorry, we couldn't find any {resource}.
-
There are no {resource} that match your filters.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/emptySearch.svelte b/src/lib/components/emptySearch.svelte
index 151ddcdc73..5a0b7e00dd 100644
--- a/src/lib/components/emptySearch.svelte
+++ b/src/lib/components/emptySearch.svelte
@@ -9,7 +9,7 @@
diff --git a/src/lib/components/filters/filters.svelte b/src/lib/components/filters/filters.svelte
index af3920fff6..c6e64f47d7 100644
--- a/src/lib/components/filters/filters.svelte
+++ b/src/lib/components/filters/filters.svelte
@@ -158,13 +158,13 @@
{/if}
{#if singleCondition}
-
+
{:else}
-
@@ -174,7 +174,7 @@
-
+
Filters
{#if applied > 0}
@@ -219,11 +219,12 @@
{/if}
{#if singleCondition}
- (showFiltersMobile = false)}>Cancel
+ (showFiltersMobile = false)}
+ >Cancel
{:else}
- Clear all
+ Clear all
{/if}
- Apply
+ Apply
diff --git a/src/lib/components/viewSelector.svelte b/src/lib/components/viewSelector.svelte
index d0d69ed658..83779794b5 100644
--- a/src/lib/components/viewSelector.svelte
+++ b/src/lib/components/viewSelector.svelte
@@ -78,6 +78,7 @@
{#if $columns?.length}
(showSelectColumns = !showSelectColumns)}
{fullWidthMobile}>
diff --git a/src/lib/elements/forms/button.svelte b/src/lib/elements/forms/button.svelte
index 4c43c9afd8..efc18e9238 100644
--- a/src/lib/elements/forms/button.svelte
+++ b/src/lib/elements/forms/button.svelte
@@ -14,7 +14,7 @@
export let danger = false;
export let icon = false;
export let link = false;
- export let size: Props['size'] = 'medium';
+ export let size: Props['size'] = 'm';
export let disabled = false;
export let external = false;
export let href: string = null;
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/breadcrumbs.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/breadcrumbs.svelte
index 1aff177352..5eac410de6 100644
--- a/src/routes/(console)/project-[project]/sites/site-[site]/breadcrumbs.svelte
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/breadcrumbs.svelte
@@ -1,5 +1,6 @@
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.svelte
new file mode 100644
index 0000000000..5c24d2f0f6
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.svelte
@@ -0,0 +1,153 @@
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.ts
new file mode 100644
index 0000000000..83a292b194
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+layout.ts
@@ -0,0 +1,28 @@
+import { sdk } from '$lib/stores/sdk';
+import { Dependencies } from '$lib/constants';
+import type { LayoutLoad } from './$types';
+import { error } from '@sveltejs/kit';
+import { Query } from '@appwrite.io/console';
+
+export const load: LayoutLoad = async ({ params, depends }) => {
+ depends(Dependencies.SITE);
+ depends(Dependencies.DEPLOYMENTS);
+
+ try {
+ const [site, proxyRuleList] = await Promise.all([
+ sdk.forProject.sites.get(params.site),
+ sdk.forProject.proxy.listRules([
+ Query.equal('resourceType', 'sites'),
+ Query.equal('resourceId', params.site),
+ Query.limit(1)
+ ])
+ ]);
+
+ return {
+ site,
+ proxyRuleList
+ };
+ } catch (e) {
+ error(e.code, e.message);
+ }
+};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
new file mode 100644
index 0000000000..dbc47e8344
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.svelte
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+ More filters
+
+ {#if $tags?.length}
+
+
+
+ Clear all
+ {/if}
+
+
+
+
+
+
+
+ (showMobileFilters = !showMobileFilters)}
+ ariaLabel="toggle filters">
+
+ Filters
+
+
+
+
+
+
+
+
+
+
+ More filters
+
+
+
+
+
+
+ {#if $deploymentList.total}
+
+ {:else if data?.query}
+
+ {/if}
+
+
+
+
+{#if selectedDeployment}
+
+{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.ts
new file mode 100644
index 0000000000..aad33a0ee1
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/+page.ts
@@ -0,0 +1,32 @@
+import { Query } from '@appwrite.io/console';
+import { sdk } from '$lib/stores/sdk';
+import { getLimit, getPage, getQuery, pageToOffset } from '$lib/helpers/load';
+import { Dependencies, PAGE_LIMIT } from '$lib/constants';
+import type { PageLoad } from './$types';
+import { queries, queryParamToMap } from '$lib/components/filters';
+
+export const load: PageLoad = async ({ params, depends, url, route, parent }) => {
+ const data = await parent();
+ depends(Dependencies.DEPLOYMENTS);
+ const page = getPage(url);
+ const limit = getLimit(url, route, PAGE_LIMIT);
+ const offset = pageToOffset(page, limit);
+ const query = getQuery(url);
+
+ const parsedQueries = queryParamToMap(query || '[]');
+ queries.set(parsedQueries);
+ return {
+ offset,
+ limit,
+ query,
+ activeDeployment: data.site.deploymentId
+ ? await sdk.forProject.sites.getDeployment(params.site, data.site.deploymentId)
+ : null,
+ deploymentList: await sdk.forProject.sites.listDeployments(params.site, [
+ Query.limit(limit),
+ Query.offset(offset),
+ Query.orderDesc(''),
+ ...parsedQueries.values()
+ ])
+ };
+};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancel.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancel.svelte
new file mode 100644
index 0000000000..77f91bca23
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/cancel.svelte
@@ -0,0 +1,49 @@
+
+
+
+ Are you sure you want to cancel this deployment?
+
+ (showCancel = false)}>Cancel
+ Continue
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/delete.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/delete.svelte
new file mode 100644
index 0000000000..b0b9ce6bf3
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/delete.svelte
@@ -0,0 +1,49 @@
+
+
+
+ Are you sure you want to delete this deployment?
+
+ (showDelete = false)}>Cancel
+ Delete
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
new file mode 100644
index 0000000000..456ed16e28
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte
@@ -0,0 +1,36 @@
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.ts
new file mode 100644
index 0000000000..a50f78e131
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.ts
@@ -0,0 +1,13 @@
+import { sdk } from '$lib/stores/sdk';
+import { Dependencies } from '$lib/constants';
+import type { PageLoad } from './$types';
+
+export const load: PageLoad = async ({ params, depends }) => {
+ depends(Dependencies.DEPLOYMENT);
+
+ const deployment = await sdk.forProject.sites.getDeployment(params.site, params.deployment);
+
+ return {
+ deployment
+ };
+};
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/store.ts
new file mode 100644
index 0000000000..337a6b456e
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deployment-[deployment]/store.ts
@@ -0,0 +1,5 @@
+import { page } from '$app/stores';
+import type { Models } from '@appwrite.io/console';
+import { derived } from 'svelte/store';
+
+export const deployment = derived(page, ($page) => $page.data.deployment as Models.Deployment);
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCard.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCard.svelte
new file mode 100644
index 0000000000..e304a32ce1
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCard.svelte
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
Deployment ID
+
+
+ {deployment.$id}
+
+
+
+
+ {@const status = deployment.status}
+ {@const deploymentSize = humanFileSize(deployment.size)}
+ {@const buildSize = humanFileSize(deployment.buildSize)}
+ {@const totalSize = humanFileSize(deployment.buildSize + deployment.size)}
+
+ -
+
Status
+
+
+
+
+ {status === 'ready' ? 'active' : status}
+
+
+
+
+ -
+
Build time
+
+ {calculateTime(deployment.buildTime)}
+
+
+ -
+
Total size
+
+ {totalSize.value + totalSize.unit}
+ Deployment size: ${deploymentSize.value + deploymentSize.unit}
+ Build size: ${buildSize.value + buildSize.unit}
+ `,
+ allowHTML: true,
+ appendTo: 'parent'
+ }}>
+
+
+
+
+
+ Updated
+
+
+
+
+
+
+
+
+ {#if $proxyRuleList?.rules?.length}
+
+ {/if}
+
+
+
+
+
+
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCreatedBy.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCreatedBy.svelte
new file mode 100644
index 0000000000..15e429722e
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentCreatedBy.svelte
@@ -0,0 +1,14 @@
+
+
+{timeFromNow(deployment.$updatedAt)}
+{#if deployment.providerCommitAuthor}
+ by {deployment.providerCommitAuthor}
+{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentDomains.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentDomains.svelte
new file mode 100644
index 0000000000..bd441f17c7
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentDomains.svelte
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+ {domain.rules[0].domain}
+
+
+
+
+ {#if domain.rules.length > 1}
+
+ (showDropdown = !showDropdown)}>
+ +{domain.rules.length - 1}
+
+
+ {#each domain.rules as rule, i}
+ {#if i !== 0}
+
+ {rule.domain}
+
+ {/if}
+ {/each}
+
+
+ {/if}
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentSource.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentSource.svelte
new file mode 100644
index 0000000000..0c5b765de1
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/deploymentSource.svelte
@@ -0,0 +1,38 @@
+
+
+{#if deployment.type === 'vcs'}
+
+ (showDropdown = !showDropdown)}
+ type="button"
+ class="u-flex u-gap-4 u-cross-center">
+ GitHub
+
+
+
+ {deployment.providerRepositoryOwner}/{deployment.providerRepositoryName}
+
+
+ {deployment.providerBranch}
+
+ {#if deployment?.providerCommitMessage && deployment?.providerCommitHash && deployment?.providerCommitUrl}
+
+
+ {deployment?.providerCommitHash?.substring(0, 7)}
+ {deployment.providerCommitMessage}
+
+
+ {/if}
+
+
+{:else if deployment.type === 'manual'}
+ Manual
+{:else if deployment.type === 'cli'}
+ CLI
+{/if}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
new file mode 100644
index 0000000000..efbbe4f066
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/quickFilters.svelte
@@ -0,0 +1,281 @@
+
+
+{#each [typeFilter] as filter}
+
+ (filter.show = !filter.show)}
+ event="apply_quick_filter"
+ eventData={{ source: 'function_deployments', column: filter.title }}>
+ {#key filter.tag}
+
+ {filter?.tag ?? filter.title}
+
+ {/key}
+
+
+
+
+ {#each filter.options as option (option.value + option.checked)}
+ {
+ option.checked = !option.checked;
+ addFilterAndApply(
+ filter.id,
+ filter.title,
+ filter.operator,
+ filter?.array ? null : option.checked ? option.value : null,
+ filter?.array
+ ? (filter.options
+ .filter((opt) => opt.checked)
+ .map((opt) => opt.value) ?? [])
+ : []
+ );
+ }}>
+ {option.label}
+
+ {/each}
+ {#if filter.options.some((option) => option.checked)}
+ {
+ filter.show = false;
+ filter.tag = null;
+ addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
+ }}>
+ Clear selection
+
+ {/if}
+
+
+{/each}
+{#each [sizeFilter] as filter}
+
+ (filter.show = !filter.show)}
+ event="apply_quick_filter"
+ eventData={{ source: 'function_deployments', column: filter.title }}>
+ {#key filter.tag}
+
+ {filter?.tag ?? filter.title}
+
+ {/key}
+
+
+
+
+ {#each filter.options as option (option.value + option.checked)}
+ {
+ filter.show = false;
+
+ addFilterAndApply(
+ filter.id,
+ filter.title,
+ filter.operator,
+ filter?.array ? null : option.value,
+ []
+ );
+ }}>
+ {option.label}
+
+ {/each}
+ {#if filter?.tag}
+ {
+ filter.show = false;
+ filter.tag = null;
+ addFilterAndApply(filter.id, filter.title, filter.operator, null, []);
+ }}>
+ Clear selection
+
+ {/if}
+
+
+{/each}
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/redeployModal.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/redeployModal.svelte
new file mode 100644
index 0000000000..dce772c9a4
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/redeployModal.svelte
@@ -0,0 +1,56 @@
+
+
+
+
+ Are you sure you want to redeploy {$func.name}? Redeploying may affect your
+ production code.
+
+
+
+ (show = false)}>Cancel
+ Redeploy
+
+
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
new file mode 100644
index 0000000000..b38f241a94
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/store.ts
@@ -0,0 +1,25 @@
+import { page } from '$app/stores';
+import { derived, writable, type Writable } from 'svelte/store';
+import type { Models } from '@appwrite.io/console';
+
+export const func = derived(page, ($page) => $page.data.function as Models.Function);
+export const deploymentList = derived(
+ page,
+ ($page) => $page.data.deploymentList as Models.DeploymentList
+);
+export const proxyRuleList = derived(
+ page,
+ ($page) => $page.data.proxyRuleList as Models.ProxyRuleList
+);
+
+export const repositories: Writable<{
+ search: string;
+ installationId: string;
+ repositories: Models.ProviderRepository[];
+}> = writable({
+ search: '',
+ installationId: '',
+ repositories: []
+});
+
+export const showCreateDeployment: Writable = writable(false);
diff --git a/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
new file mode 100644
index 0000000000..3886ba2916
--- /dev/null
+++ b/src/routes/(console)/project-[project]/sites/site-[site]/deployments/table.svelte
@@ -0,0 +1,196 @@
+
+
+
+
+ {#each columns as column}
+ {#if column.show}
+ {column.title}
+ {/if}
+ {/each}
+
+
+
+ {#each data.deploymentList.deployments as deployment, index (deployment.$id)}
+
+ {#each columns as column}
+ {#if column.show}
+ {#if column.id === '$id'}
+ {#key column.id}
+
+ {deployment.$id}
+
+ {/key}
+ {:else if column.id === 'status'}
+
+ {@const status = deployment.status}
+ {#if data?.activeDeployment?.$id === deployment?.$id}
+
+
+ active
+
+ {:else}
+
+ {status}
+
+ {/if}
+
+ {:else if column.id === 'type'}
+
+
+
+ {:else if column.id === '$updatedAt'}
+
+
+
+ {:else if column.id === 'buildTime'}
+
+ {#if ['processing', 'building'].includes(deployment.status)}
+
+ {:else}
+ {calculateTime(deployment.buildTime)}
+ {/if}
+
+ {:else if column.id === 'size'}
+
+ {calculateSize(deployment.size)}
+
+ {:else if column.id === 'buildSize'}
+
+ {calculateSize(deployment.buildSize)}
+
+ {/if}
+ {/if}
+ {/each}
+
+
+ {
+ showDropdown[index] = !showDropdown[index];
+ }}>
+
+
+
+ {
+ selectedDeployment = deployment;
+ showRedeploy = true;
+ showDropdown = [];
+ }}>
+ Redeploy
+
+ {#if deployment.status === 'ready' && deployment.$id !== $func.deployment}
+ {
+ selectedDeployment = deployment;
+ showActivate = true;
+ showDropdown = [];
+ }}>
+ Activate
+
+ {/if}
+
+ Logs
+
+ (showDropdown[index] = false)}>
+ Download
+
+ {#if deployment.status === 'processing' || deployment.status === 'building' || deployment.status === 'waiting'}
+ {
+ selectedDeployment = deployment;
+ showDropdown = [];
+ showCancel = true;
+ }}>
+ Cancel
+
+ {/if}
+ {#if deployment.status !== 'building' && deployment.status !== 'processing' && deployment.status !== 'waiting'}
+ {
+ selectedDeployment = deployment;
+ showDropdown = [];
+ showDelete = true;
+ }}>
+ Delete
+
+ {/if}
+
+
+
+
+ {/each}
+
+
+
+{#if selectedDeployment}
+
+
+
+
+{/if}