mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' into fix-SER-26-connect-button-not-shown-if-repo-name-to-long
This commit is contained in:
@@ -23,7 +23,8 @@
|
||||
import { page } from '$app/state';
|
||||
import Card from '../card.svelte';
|
||||
import SkeletonRepoList from './skeletonRepoList.svelte';
|
||||
import { onMount, untrack } from 'svelte';
|
||||
import { onMount, untrack, onDestroy } from 'svelte';
|
||||
import { debounce } from '$lib/helpers/debounce';
|
||||
|
||||
let {
|
||||
action = $bindable('select'),
|
||||
@@ -52,6 +53,28 @@
|
||||
loadInstallations();
|
||||
});
|
||||
|
||||
const debouncedLoadRepositories = debounce(
|
||||
async (installationId: string, searchTerm: string) => {
|
||||
isLoadingRepositories = true;
|
||||
try {
|
||||
await loadRepositories(installationId, searchTerm);
|
||||
} finally {
|
||||
isLoadingRepositories = false;
|
||||
}
|
||||
},
|
||||
300
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
if (selectedInstallation && search !== undefined) {
|
||||
debouncedLoadRepositories(selectedInstallation, search);
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
debouncedLoadRepositories.cancel();
|
||||
});
|
||||
|
||||
async function loadInstallations() {
|
||||
if (installationList) {
|
||||
if (installationList.installations.length) {
|
||||
@@ -71,7 +94,7 @@
|
||||
.vcs.listInstallations();
|
||||
if (installations.length) {
|
||||
if (!selectedInstallation) {
|
||||
untrack(() => (selectedInstallation = installationList.installations[0].$id));
|
||||
untrack(() => (selectedInstallation = installations[0].$id));
|
||||
}
|
||||
installation.set(installations.find((entry) => entry.$id === selectedInstallation));
|
||||
}
|
||||
@@ -80,22 +103,6 @@
|
||||
}
|
||||
|
||||
async function loadRepositories(installationId: string, search: string) {
|
||||
if (
|
||||
!$repositories ||
|
||||
$repositories.installationId !== installationId ||
|
||||
$repositories.search !== search
|
||||
) {
|
||||
await fetchRepos(installationId, search);
|
||||
}
|
||||
|
||||
if ($repositories.repositories.length && action === 'select') {
|
||||
selectedRepository = $repositories.repositories[0].id;
|
||||
$repository = $repositories.repositories[0];
|
||||
}
|
||||
return $repositories.repositories;
|
||||
}
|
||||
|
||||
async function fetchRepos(installationId: string, search: string) {
|
||||
if (product === 'functions') {
|
||||
$repositories.repositories = (
|
||||
(await sdk
|
||||
@@ -117,9 +124,9 @@
|
||||
)) as unknown as Models.ProviderRepositoryFrameworkList
|
||||
).frameworkProviderRepositories;
|
||||
}
|
||||
|
||||
$repositories.search = search;
|
||||
$repositories.installationId = installationId;
|
||||
return $repositories.repositories;
|
||||
}
|
||||
|
||||
selectedRepository;
|
||||
@@ -168,10 +175,7 @@
|
||||
installationsMap.find((entry) => entry.$id === selectedInstallation)
|
||||
);
|
||||
|
||||
isLoadingRepositories = true;
|
||||
loadRepositories(selectedInstallation, search).then(() => {
|
||||
isLoadingRepositories = false;
|
||||
});
|
||||
debouncedLoadRepositories.cancel();
|
||||
}}
|
||||
bind:value={selectedInstallation} />
|
||||
<InputSearch
|
||||
@@ -185,20 +189,52 @@
|
||||
<!-- manual installation change -->
|
||||
{#if isLoadingRepositories}
|
||||
<SkeletonRepoList />
|
||||
{:else}
|
||||
{#await loadRepositories(selectedInstallation, search)}
|
||||
<SkeletonRepoList />
|
||||
{:then response}
|
||||
{#if response?.length}
|
||||
<Paginator items={response} hideFooter={response?.length <= 6} limit={6}>
|
||||
{#snippet children(
|
||||
paginatedItems: Models.ProviderRepositoryRuntime[] &
|
||||
Models.ProviderRepositoryFramework[]
|
||||
)}
|
||||
<Table.Root columns={1} let:root>
|
||||
{#each paginatedItems as repo}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>
|
||||
{:else if $repositories?.repositories?.length}
|
||||
<Paginator
|
||||
items={$repositories.repositories}
|
||||
hideFooter={$repositories.repositories?.length <= 6}
|
||||
limit={6}>
|
||||
{#snippet children(
|
||||
paginatedItems: Models.ProviderRepositoryRuntime[] &
|
||||
Models.ProviderRepositoryFramework[]
|
||||
)}
|
||||
<Table.Root columns={1} let:root>
|
||||
{#each paginatedItems as repo}
|
||||
<Table.Row.Base {root}>
|
||||
<Table.Cell {root}>
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
{#if action === 'select'}
|
||||
<input
|
||||
class="is-small u-margin-inline-end-8"
|
||||
type="radio"
|
||||
name="repositories"
|
||||
bind:group={selectedRepository}
|
||||
onchange={() => repository.set(repo)}
|
||||
value={repo.id} />
|
||||
{/if}
|
||||
{#if product === 'sites'}
|
||||
{#if repo?.framework && repo.framework !== 'other'}
|
||||
<Avatar size="xs" alt={repo.name}>
|
||||
<SvgIcon
|
||||
name={getFrameworkIcon(repo.framework)}
|
||||
iconSize="small" />
|
||||
</Avatar>
|
||||
{:else}
|
||||
<Avatar size="xs" alt={repo.name} empty />
|
||||
{/if}
|
||||
{:else}
|
||||
{@const iconName = repo?.runtime
|
||||
? repo.runtime.split('-')[0]
|
||||
: undefined}
|
||||
<Avatar size="xs" alt={repo.name} empty={!iconName}>
|
||||
<SvgIcon name={iconName} iconSize="small" />
|
||||
</Avatar>
|
||||
{/if}
|
||||
<Layout.Stack
|
||||
gap="s"
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="space-between">
|
||||
<Layout.Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
@@ -279,36 +315,62 @@
|
||||
on:click={() => connect(repo)}>
|
||||
Connect
|
||||
</PinkButton.Button>
|
||||
gap="s"
|
||||
alignItems="center">
|
||||
<Typography.Text
|
||||
truncate
|
||||
color="--fgcolor-neutral-secondary">
|
||||
{repo.name}
|
||||
</Typography.Text>
|
||||
{#if repo.private}
|
||||
<Icon
|
||||
size="s"
|
||||
icon={IconLockClosed}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
{/if}
|
||||
{#if !$isSmallViewport}
|
||||
<time datetime={repo.pushedAt}>
|
||||
<Typography.Caption
|
||||
variant="400"
|
||||
truncate
|
||||
color="--fgcolor-neutral-tertiary">
|
||||
{timeFromNow(repo.pushedAt)}
|
||||
</Typography.Caption>
|
||||
</time>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/snippet}
|
||||
</Paginator>
|
||||
{:else if search}
|
||||
<EmptySearch hidePages hidePagination bind:search target="repositories">
|
||||
<svelte:fragment slot="actions">
|
||||
{#if search}
|
||||
<Button secondary on:click={() => (search = '')}>
|
||||
Clear search
|
||||
</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Card>
|
||||
<Layout.Stack alignItems="center" justifyContent="center">
|
||||
<Typography.Text
|
||||
variation="m-500"
|
||||
color="--fgcolor-neutral-tertiary">
|
||||
No repositories available
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
{/if}
|
||||
{/await}
|
||||
{#if action === 'button'}
|
||||
<PinkButton.Button
|
||||
size="xs"
|
||||
variant="secondary"
|
||||
on:click={() => connect(repo)}>
|
||||
Connect
|
||||
</PinkButton.Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row.Base>
|
||||
{/each}
|
||||
</Table.Root>
|
||||
{/snippet}
|
||||
</Paginator>
|
||||
{:else if search}
|
||||
<EmptySearch hidePages hidePagination bind:search target="repositories">
|
||||
<svelte:fragment slot="actions">
|
||||
{#if search}
|
||||
<Button secondary on:click={() => (search = '')}>Clear search</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Card>
|
||||
<Layout.Stack alignItems="center" justifyContent="center">
|
||||
<Typography.Text variation="m-500" color="--fgcolor-neutral-tertiary">
|
||||
No repositories available
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
</Card>
|
||||
{/if}
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 563 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 306 KiB |
@@ -7,6 +7,8 @@ import BulkApiLight from '$lib/images/promos/bulk-api-light.png';
|
||||
|
||||
import CSVImportDark from '$lib/images/promos/csv-import-placeholder-dark.png';
|
||||
import CSVImportLight from '$lib/images/promos/csv-import-placeholder-light.png';
|
||||
import DatabaseUpsertDark from '$lib/images/promos/database-upsert-dark.png';
|
||||
import DatabaseUpsertLight from '$lib/images/promos/database-upsert-light.png';
|
||||
|
||||
const listOfPromotions: BottomModalAlertItem[] = [];
|
||||
|
||||
@@ -52,8 +54,27 @@ if (isCloud) {
|
||||
},
|
||||
show: true
|
||||
};
|
||||
const databaseUpsert: BottomModalAlertItem = {
|
||||
id: 'modal:database_upsert_announcement',
|
||||
src: {
|
||||
dark: DatabaseUpsertDark,
|
||||
light: DatabaseUpsertLight
|
||||
},
|
||||
title: 'Introducing Database Upsert',
|
||||
message: 'A new Appwrite Database feature, built to simplify your database interactions.',
|
||||
plan: 'free',
|
||||
importance: 8,
|
||||
scope: 'project',
|
||||
cta: {
|
||||
text: 'Read announcement',
|
||||
link: () => 'https://appwrite.io/blog/post/announcing-database-upsert',
|
||||
external: true,
|
||||
hideOnClick: true
|
||||
},
|
||||
show: true
|
||||
};
|
||||
|
||||
listOfPromotions.push(bulkApiPromo, csvImportPromo);
|
||||
listOfPromotions.push(databaseUpsert, bulkApiPromo, csvImportPromo);
|
||||
}
|
||||
|
||||
export function addBottomModalAlerts() {
|
||||
|
||||
+7
-3
@@ -23,7 +23,11 @@
|
||||
selectedRelationship = null;
|
||||
}
|
||||
|
||||
$: tableColumns = [{ id: '$id', width: 200 }, ...args.map((id) => ({ id }))];
|
||||
$: tableColumns = [
|
||||
// take full width if no display names set
|
||||
{ id: '$id', width: args.length ? 200 : undefined },
|
||||
...args.map((id) => ({ id }))
|
||||
];
|
||||
</script>
|
||||
|
||||
<Modal bind:show title={selectedRelationship?.key} hideFooter>
|
||||
@@ -33,7 +37,7 @@
|
||||
<Table.Root let:root columns={tableColumns}>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell column="$id" {root}>Document ID</Table.Header.Cell>
|
||||
{#if args?.length}
|
||||
{#if args.length}
|
||||
{#each args as arg}
|
||||
<Table.Header.Cell column={arg} {root}>{arg}</Table.Header.Cell>
|
||||
{/each}
|
||||
@@ -47,7 +51,7 @@
|
||||
<Table.Cell column="$id" {root}>
|
||||
<Id value={doc.$id}>{doc.$id}</Id>
|
||||
</Table.Cell>
|
||||
{#if args?.length}
|
||||
{#if args.length}
|
||||
{#each args as arg}
|
||||
<Table.Cell column={arg} {root}>{doc[arg]}</Table.Cell>
|
||||
{/each}
|
||||
|
||||
+3
-1
@@ -73,7 +73,9 @@
|
||||
(names?.length && !last(names))
|
||||
);
|
||||
|
||||
const hasExhaustedOptions = $derived(getValidAttributes().length === names?.length);
|
||||
const hasExhaustedOptions = $derived(
|
||||
getValidAttributes().length === names.filter(Boolean).length
|
||||
);
|
||||
</script>
|
||||
|
||||
<Form onSubmit={updateDisplayName}>
|
||||
|
||||
+15
-30
@@ -24,8 +24,7 @@
|
||||
APNSProviderParams
|
||||
} from './store';
|
||||
import TooltipPopover from './tooltipPopover.svelte';
|
||||
import { Icon, Tooltip, Upload, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Upload, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import { InvalidFileType, removeFile } from '$lib/helpers/files';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
|
||||
@@ -44,18 +43,6 @@
|
||||
| FCMProviderParams
|
||||
| APNSProviderParams
|
||||
>;
|
||||
const popover = input.popover ? PopoverContent : null;
|
||||
const popoverProps = getPopoverProps(input);
|
||||
|
||||
function getPopoverProps(input: ProviderInput) {
|
||||
if (!input.popover) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
lines: input.popover,
|
||||
image: input.popoverImage
|
||||
};
|
||||
}
|
||||
|
||||
function handleInvalid(e: CustomEvent) {
|
||||
const reason = e.detail?.reason ?? '';
|
||||
@@ -72,6 +59,14 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: popover = input.popover ? PopoverContent : null;
|
||||
$: popoverProps = !input.popover
|
||||
? {}
|
||||
: {
|
||||
lines: input.popover,
|
||||
image: input.popoverImage
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if input.type === 'text'}
|
||||
@@ -122,25 +117,15 @@
|
||||
{:else if input.type === 'file'}
|
||||
<Upload.Dropzone
|
||||
on:invalid={handleInvalid}
|
||||
extensions={['json']}
|
||||
extensions={input.allowedFileExtensions}
|
||||
bind:files={files[input.name]}
|
||||
maxSize={10000000}
|
||||
required={!input.optional}>
|
||||
<Layout.Stack alignItems="center" gap="s">
|
||||
<Layout.Stack alignItems="center" gap="s">
|
||||
<Layout.Stack alignItems="center" justifyContent="center" direction="row" gap="s">
|
||||
<Typography.Text variant="l-500">
|
||||
Drag and drop service account JSON here or click to upload
|
||||
</Typography.Text>
|
||||
<Tooltip>
|
||||
<Layout.Stack alignItems="center" justifyContent="center" inline>
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="tooltip">Only .json files allowed</svelte:fragment>
|
||||
</Tooltip>
|
||||
</Layout.Stack>
|
||||
<Typography.Caption variant="400">Max file size 10MB</Typography.Caption>
|
||||
</Layout.Stack>
|
||||
<Layout.Stack alignItems="center" justifyContent="center" direction="row" gap="xxs">
|
||||
<Typography.Text variant="l-500">
|
||||
Drag and drop your {input.label} here or click to upload
|
||||
</Typography.Text>
|
||||
<TooltipPopover {popover} {popoverProps} tooltip={input.tooltip} />
|
||||
</Layout.Stack>
|
||||
</Upload.Dropzone>
|
||||
{#if files[input.name]?.length}
|
||||
|
||||
@@ -85,7 +85,7 @@ export const providers: ProvidersMap = {
|
||||
],
|
||||
configure: [
|
||||
{
|
||||
label: 'Service account JSON (.json file)',
|
||||
label: 'service account JSON (.json file)',
|
||||
name: 'serviceAccountJSON',
|
||||
type: 'file',
|
||||
allowedFileExtensions: ['json'],
|
||||
@@ -164,7 +164,7 @@ export const providers: ProvidersMap = {
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Auth key (.p8 file)',
|
||||
label: 'auth key (.p8 file)',
|
||||
name: 'authKey',
|
||||
type: 'file',
|
||||
allowedFileExtensions: ['p8'],
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
$: $updateCommandGroupRanks({ webhooks: 20, domains: 10 });
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Webhooks - Appwrite</title>
|
||||
</svelte:head>
|
||||
|
||||
<Container>
|
||||
<Layout.Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<ViewSelector {columns} view={View.Table} hideView />
|
||||
|
||||
Reference in New Issue
Block a user