feat: overview screen

This commit is contained in:
Arman
2025-01-28 13:24:50 +01:00
parent b2cc177601
commit 2cd0ef9303
14 changed files with 210 additions and 115 deletions
@@ -4,7 +4,7 @@
import { page } from '$app/stores';
import { Empty, PaginationWithLimit, SearchQuery, ViewSelector } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Container, ContainerHeader } from '$lib/layout';
import { Container } from '$lib/layout';
import type { Models } from '@appwrite.io/console';
import type { PageData } from './$types';
@@ -14,7 +14,7 @@
import Table from './table.svelte';
import { registerCommands } from '$lib/commandCenter';
import { canWriteDatabases } from '$lib/stores/roles';
import { Layout, Tooltip } from '@appwrite.io/pink-svelte';
import { Layout } from '@appwrite.io/pink-svelte';
export let data: PageData;
@@ -1,29 +1,22 @@
<script lang="ts">
import { registerCommands, updateCommandGroupRanks } from '$lib/commandCenter';
import { Empty, PaginationWithLimit, SearchQuery } from '$lib/components';
import { Container, ContainerHeader } from '$lib/layout';
import { Empty, PaginationWithLimit, SearchQuery, ViewSelector } from '$lib/components';
import { Container } from '$lib/layout';
import { isServiceLimited } from '$lib/stores/billing';
// import { templatesList } from '$lib/stores/templates';
import { organization } from '$lib/stores/organization';
import { wizard } from '$lib/stores/wizard';
import { canWriteSites } from '$lib/stores/roles.js';
import { Icon, Popover, Image, ActionMenu, Layout } from '@appwrite.io/pink-svelte';
import { Icon, Image, Layout } from '@appwrite.io/pink-svelte';
import { Button } from '$lib/elements/forms';
import {
IconCog,
IconDotsHorizontal,
IconGlobeAlt,
IconRefresh
} from '@appwrite.io/pink-icons-svelte';
import { Card } from '@appwrite.io/pink-svelte';
import { base } from '$app/paths';
import { page } from '$app/stores';
import CreateSiteModal from './createSiteModal.svelte';
import { timeFromNow } from '$lib/helpers/date';
import EmptyLight from './(images)/empty-light.png';
import { app } from '$lib/stores/app';
import EmptyDark from './(images)/empty-dark.png';
import Grid from './grid.svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import { columns } from './store';
import { View } from '$lib/helpers/load';
import Table from './table.svelte';
export let data;
let show = false;
@@ -57,57 +50,21 @@
<SearchQuery search={data.search} placeholder="Search sites" />
</Layout.Stack>
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
<Button on:mousedown={() => (show = true)} event="create_site" size="s">
<span class="icon-plus" aria-hidden="true" />
<span class="text">Create site</span>
</Button>
<ViewSelector {columns} view={data.view} hideColumns hideView={!data.siteList.total} />
{#if $canWriteSites}
<Button on:mousedown={() => (show = true)} event="create_site" size="s">
<Icon icon={IconPlus} />
Create site
</Button>
{/if}
</Layout.Stack>
</Layout.Stack>
{#if data.siteList.total}
<section class="sites-grid">
{#each data.siteList.sites as site}
<Card.Link
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}`}
padding="xxs">
<Card.Media
title={site.name}
description={`Deployed ${timeFromNow(site.$updatedAt)}`}
src={site.preview ??
`https://placehold.co/600x400/111/bbb?text=Screenshot+coming+soon&font=inter`}
alt={site.name}>
<Popover placement="bottom-end" let:toggle>
<Button
text
icon
size="s"
on:click={(e) => {
e.preventDefault();
toggle(e);
}}>
<Icon size="s" icon={IconDotsHorizontal} /></Button>
<svelte:fragment slot="tooltip">
<ActionMenu.Root>
<ActionMenu.Item.Button leadingIcon={IconRefresh} disabled>
Redeploy
</ActionMenu.Item.Button>
<ActionMenu.Item.Anchor
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}/domains`}
leadingIcon={IconGlobeAlt}>
Domains
</ActionMenu.Item.Anchor>
<ActionMenu.Item.Anchor
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}/settings`}
leadingIcon={IconCog}>
Settings
</ActionMenu.Item.Anchor>
</ActionMenu.Root>
</svelte:fragment>
</Popover>
</Card.Media>
</Card.Link>
{/each}
</section>
{#if data.view === View.Grid}
<Grid siteList={data.siteList} />
{:else}
<Table siteList={data.siteList} />
{/if}
<PaginationWithLimit
name="Sites"
limit={data.limit}
@@ -132,11 +89,3 @@
</Container>
<CreateSiteModal bind:show />
<style lang="scss">
.sites-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(237.5px, 1fr));
gap: 1rem;
}
</style>
@@ -1,6 +1,6 @@
import { Query } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
import { getLimit, getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
export const load = async ({ url, depends, route }) => {
@@ -10,6 +10,7 @@ export const load = async ({ url, depends, route }) => {
const search = getSearch(url);
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
const view = getView(url, route, View.Grid);
const siteList = await sdk.forProject.sites.list(
[Query.limit(limit), Query.offset(offset), Query.orderDesc('')],
@@ -20,6 +21,7 @@ export const load = async ({ url, depends, route }) => {
offset,
limit,
search,
siteList
siteList,
view
};
};
@@ -4,7 +4,7 @@
import { IconGithub, IconGitBranch } from '@appwrite.io/pink-icons-svelte';
import { consoleVariables } from '$routes/(console)/store';
import type { Models } from '@appwrite.io/console';
import { getFrameworkIcon } from './store';
import { getFrameworkIcon } from '../store';
export let framework: Partial<Models.Framework>;
export let repositoryName: string;
@@ -24,7 +24,6 @@
import SecretVariableModal from '../secretVariableModal.svelte';
import ImportSiteVariablesModal from '../importSiteVariablesModal.svelte';
import type { Models } from '@appwrite.io/console';
import { getFrameworkIcon } from '../store';
export let frameworks: Models.Framework[];
export let selectedFramework: Models.Framework;
@@ -24,7 +24,7 @@
import SecretVariableModal from '../../secretVariableModal.svelte';
import ImportSiteVariablesModal from '../../importSiteVariablesModal.svelte';
import type { Models } from '@appwrite.io/console';
import { getFrameworkIcon } from '../../store';
import { getFrameworkIcon } from '../../../store';
export let frameworks: Models.Framework[];
export let selectedFramework: Models.Framework;
@@ -1,30 +0,0 @@
import {
IconAngular,
IconNuxt,
IconReact,
IconSvelte,
IconVue
} from '@appwrite.io/pink-icons-svelte';
export function getFrameworkIcon(framework: string) {
console.log(framework);
switch (true) {
case framework.toLocaleLowerCase().includes('sveltekit'):
return IconSvelte;
case framework.toLocaleLowerCase().includes('nuxt'):
return IconNuxt;
case framework.toLocaleLowerCase().includes('vue'):
return IconVue;
case framework.toLocaleLowerCase().includes('react'):
return IconReact;
case framework.toLocaleLowerCase().includes('angular'):
return IconAngular;
case framework.toLocaleLowerCase().includes('svelte'):
return IconSvelte;
case framework.toLocaleLowerCase().includes('next'):
return IconReact; //TODO: add next icon
default:
return undefined;
}
}
@@ -29,7 +29,7 @@
import { BuildRuntime, Framework, ID, Query } from '@appwrite.io/console';
import Domain from '../../domain.svelte';
import { NewRepository, Repositories, RepositoryBehaviour } from '$lib/components/git';
import { getFrameworkIcon } from '../../store';
import { getFrameworkIcon } from '../../../store';
export let data;
@@ -0,0 +1,86 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Button } from '$lib/elements/forms';
import { timeFromNow } from '$lib/helpers/date';
import type { Models } from '@appwrite.io/console';
import {
IconCog,
IconDotsHorizontal,
IconGlobeAlt,
IconRefresh
} from '@appwrite.io/pink-icons-svelte';
import { ActionMenu, Card, Icon, Popover } from '@appwrite.io/pink-svelte';
import RedeployModal from './redeployModal.svelte';
export let siteList: Models.SiteList;
let showRedeploy = false;
let selectedSite: Models.Site = null;
</script>
<section class="sites-grid">
{#each siteList.sites as site}
<Card.Link
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}`}
padding="xxs">
<Card.Media
title={site.name}
description={`Updated ${timeFromNow(site.$updatedAt)}`}
src={site.preview ??
`https://placehold.co/600x400/111/bbb?text=Screenshot+coming+soon&font=inter`}
alt={site.name}>
<Popover placement="bottom-end" let:toggle>
<Button
text
icon
size="s"
on:click={(e) => {
e.preventDefault();
toggle(e);
}}>
<Icon size="s" icon={IconDotsHorizontal} /></Button>
<svelte:fragment slot="tooltip" let:toggle>
<ActionMenu.Root>
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
on:click={(e) => {
e.preventDefault();
selectedSite = site;
showRedeploy = true;
toggle(e);
}}>
Redeploy
</ActionMenu.Item.Button>
<ActionMenu.Item.Anchor
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}/domains`}
leadingIcon={IconGlobeAlt}>
Domains
</ActionMenu.Item.Anchor>
<ActionMenu.Item.Anchor
href={`${base}/project-${$page.params.project}/sites/site-${site.$id}/settings`}
leadingIcon={IconCog}>
Settings
</ActionMenu.Item.Anchor>
</ActionMenu.Root>
</svelte:fragment>
</Popover>
</Card.Media>
</Card.Link>
{/each}
</section>
{#if selectedSite?.$id && showRedeploy}
<RedeployModal
selectedDeploymentId={selectedSite.deploymentId}
bind:show={showRedeploy}
site={selectedSite} />
{/if}
<style lang="scss">
.sites-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(237.5px, 1fr));
gap: 1rem;
}
</style>
@@ -9,13 +9,13 @@
import type { Models } from '@appwrite.io/console';
export let show = false;
export let selectedDeployment: Models.Deployment = null;
export let selectedDeploymentId: string;
export let site: Models.Site;
let error: string;
async function redeploy() {
try {
await sdk.forProject.sites.createBuild(site.$id, selectedDeployment.$id);
await sdk.forProject.sites.updateDeploymentBuild(site.$id, selectedDeploymentId);
addNotification({
type: 'success',
message: `Redeploying ${site.name}`
@@ -14,7 +14,7 @@
import { toLocaleDate } from '$lib/helpers/date';
import Table from './table.svelte';
import QuickFilters from './quickFilters.svelte';
import RedeployModal from './redeployModal.svelte';
import RedeployModal from '../../redeployModal.svelte';
import CreateGitDeploymentModal from './createGitDeploymentModal.svelte';
import UsageCard from './usageCard.svelte';
import ConnectRepoModal from '../../(components)/connectRepoModal.svelte';
@@ -237,7 +237,10 @@
</Layout.Stack>
</Container>
{#if selectedDeployment}
<RedeployModal {selectedDeployment} bind:show={showRedeploy} site={data.site} />
<RedeployModal
selectedDeploymentId={selectedDeployment.$id}
bind:show={showRedeploy}
site={data.site} />
{/if}
{#if showConnectRepo}
@@ -9,7 +9,7 @@
import { calculateSize } from '$lib/helpers/sizeConvertion';
import { page } from '$app/stores';
import Delete from './deleteDeploymentModal.svelte';
import RedeployModal from './redeployModal.svelte';
import RedeployModal from '../../redeployModal.svelte';
import Cancel from './cancelDeploymentModal.svelte';
import { base } from '$app/paths';
import { ActionMenu, Popover, Status, Table } from '@appwrite.io/pink-svelte';
@@ -174,5 +174,8 @@
<Delete {selectedDeployment} bind:showDelete />
<!-- <Activate {selectedDeployment} bind:showActivate on:activated={handleActivate} /> -->
<Cancel {selectedDeployment} bind:showCancel />
<RedeployModal {selectedDeployment} bind:show={showRedeploy} site={data.site} />
<RedeployModal
selectedDeploymentId={selectedDeployment.$id}
bind:show={showRedeploy}
site={data.site} />
{/if}
@@ -1,5 +1,44 @@
import type { Column } from '$lib/helpers/types';
import { Framework, type Models } from '@appwrite.io/console';
import {
IconAngular,
IconNuxt,
IconReact,
IconSvelte,
IconVue
} from '@appwrite.io/pink-icons-svelte';
import { writable } from 'svelte/store';
export function getEnumFromModel(model: Models.Framework): Framework {
return Framework[model.name];
}
export const columns = writable<Column[]>([
{ id: 'name', title: 'Name', type: 'string', show: true, width: 100 },
// { id: 'domains', title: 'Domains', type: 'string', show: true, width: 120 },
{ id: '$updatedAt', title: 'Updated', type: 'datetime', show: true, width: 120 },
{ id: '$createdAt', title: 'Created', type: 'datetime', show: true, width: 120 }
]);
export function getFrameworkIcon(framework: string) {
console.log(framework);
switch (true) {
case framework.toLocaleLowerCase().includes('sveltekit'):
return IconSvelte;
case framework.toLocaleLowerCase().includes('nuxt'):
return IconNuxt;
case framework.toLocaleLowerCase().includes('vue'):
return IconVue;
case framework.toLocaleLowerCase().includes('react'):
return IconReact;
case framework.toLocaleLowerCase().includes('angular'):
return IconAngular;
case framework.toLocaleLowerCase().includes('svelte'):
return IconSvelte;
case framework.toLocaleLowerCase().includes('next'):
return IconReact; //TODO: add next icon
default:
return undefined;
}
}
@@ -0,0 +1,44 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { toLocaleDateTime } from '$lib/helpers/date';
import { Icon, Table } from '@appwrite.io/pink-svelte';
import { columns } from './store';
import type { Models } from '@appwrite.io/console';
export let siteList: Models.SiteList;
</script>
<Table.Root>
<svelte:fragment slot="header">
{#each $columns as column}
{#if column.show}
<Table.Header.Cell width={column?.width?.toString() ?? ''}>
{column.title}
</Table.Header.Cell>
{/if}
{/each}
</svelte:fragment>
{#each siteList.sites as site}
<Table.Link href={`${base}/project-${$page.params.project}/sites/site-${site.$id}`}>
{#each $columns as column}
{#if column.show}
{#if column.id === 'name'}
<Table.Cell width={column?.width?.toString() ?? ''}>
<Icon
{site.name}
</Table.Cell>
{:else if column.id === '$updatedAt'}
<Table.Cell width={column?.width?.toString() ?? ''}>
{toLocaleDateTime(site[column.id])}
</Table.Cell>
{:else if column.id === '$createdAt'}
<Table.Cell width={column?.width?.toString() ?? ''}>
{toLocaleDateTime(site[column.id])}
</Table.Cell>
{/if}
{/if}
{/each}
</Table.Link>
{/each}
</Table.Root>