mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: overview screen
This commit is contained in:
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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>
|
||||
+2
-2
@@ -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>
|
||||
Reference in New Issue
Block a user