Merge branch 'main' into fix-SER-26-connect-button-not-shown-if-repo-name-to-long

This commit is contained in:
Harsh Mahajan
2025-07-09 13:42:50 +05:30
committed by GitHub
9 changed files with 176 additions and 106 deletions
+127 -65
View File
@@ -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

+22 -1
View File
@@ -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() {
@@ -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}
@@ -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}>
@@ -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 />