mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge pull request #2935 from appwrite/fix-uploadvas-flow
fix: upload vars and mobile ux
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
|
||||
<Card.Base>
|
||||
<Layout.Stack gap="xl" justifyContent="space-around">
|
||||
<Layout.GridFraction gap="xxxl" rowGap="xl" start={1} end={2}>
|
||||
<Layout.Stack gap="xxs">
|
||||
<div class="card-grid-content">
|
||||
<Layout.Stack gap="xxs" class="card-grid-main">
|
||||
<Typography.Title size="s" truncate><slot name="title" /></Typography.Title>
|
||||
{#if $$slots.default}
|
||||
<Typography.Text>
|
||||
@@ -17,12 +17,12 @@
|
||||
</Typography.Text>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
<div style:overflow={overflow ? 'visible' : 'hidden'}>
|
||||
<div class="card-grid-aside" style:overflow={overflow ? 'visible' : 'hidden'}>
|
||||
<Layout.Stack {gap}>
|
||||
<slot name="aside" />
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
</Layout.GridFraction>
|
||||
</div>
|
||||
{#if $$slots.actions && !hideFooter}
|
||||
<span
|
||||
style="margin-left: calc(-1* var(--space-9));margin-right: calc(-1* var(--space-9));width:auto;">
|
||||
@@ -34,3 +34,25 @@
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Card.Base>
|
||||
|
||||
<style>
|
||||
.card-grid-content {
|
||||
display: grid;
|
||||
gap: var(--space-10);
|
||||
align-items: start;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.card-grid-main,
|
||||
.card-grid-aside {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.card-grid-content {
|
||||
column-gap: var(--space-13);
|
||||
row-gap: var(--space-10);
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
import DeleteVariableModal from './deleteVariableModal.svelte';
|
||||
import UpdateVariableModal from './updateVariableModal.svelte';
|
||||
import { Click, trackEvent } from '$lib/actions/analytics';
|
||||
import { isSmallViewport } from '$lib/stores/viewport';
|
||||
|
||||
const DOCS_LINKS: Record<ProductLabel, string> = {
|
||||
site: 'https://appwrite.io/docs/products/sites/develop#accessing-environment-variables',
|
||||
@@ -62,18 +63,26 @@
|
||||
const createSource = $derived(analyticsCreateSource || analyticsSource);
|
||||
const docsLink = $derived(DOCS_LINKS[productLabel]);
|
||||
|
||||
const tableColumns = [
|
||||
{ id: 'key', width: { min: 300 } },
|
||||
{ id: 'value', width: { min: 280 } },
|
||||
{ id: 'actions', width: 40 }
|
||||
];
|
||||
const tableColumns = $derived(
|
||||
$isSmallViewport
|
||||
? [
|
||||
{ id: 'key', width: { min: 420 } },
|
||||
{ id: 'value', width: { min: 240 } },
|
||||
{ id: 'actions', width: 40 }
|
||||
]
|
||||
: [
|
||||
{ id: 'key', width: { min: 300 } },
|
||||
{ id: 'value', width: { min: 280 } },
|
||||
{ id: 'actions', width: 40 }
|
||||
]
|
||||
);
|
||||
</script>
|
||||
|
||||
<Accordion title="Environment variables" badge="Optional" hideDivider>
|
||||
<Layout.Stack gap="xl">
|
||||
Set up environment variables to securely manage keys and settings for your project.
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.Stack direction="row">
|
||||
<Layout.Stack direction="row" gap="s">
|
||||
<Layout.Stack direction="row" gap="s">
|
||||
<Button
|
||||
secondary
|
||||
@@ -137,7 +146,7 @@
|
||||
{:else if variables?.length}
|
||||
<Paginator items={variables} limit={6} hideFooter={variables.length <= 6}>
|
||||
{#snippet children(paginatedItems)}
|
||||
<Table.Root let:root columns={tableColumns}>
|
||||
<Table.Root class="responsive-table" let:root columns={tableColumns}>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell column="key" {root}>Key</Table.Header.Cell>
|
||||
<Table.Header.Cell column="value" {root}>Value</Table.Header.Cell>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
|
||||
import { Icon, Layout, Selector, Tooltip, Typography, Upload } from '@appwrite.io/pink-svelte';
|
||||
import { parse } from '$lib/helpers/envfile';
|
||||
import { removeFile } from '$lib/helpers/files';
|
||||
|
||||
export let show = false;
|
||||
export let variables: Partial<Models.Variable>[];
|
||||
@@ -13,6 +14,15 @@
|
||||
let files: FileList;
|
||||
let error: string;
|
||||
let secret = false;
|
||||
$: filesList = files?.length
|
||||
? Array.from(files).map((file) => ({
|
||||
...file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
extension: file.type,
|
||||
removable: true
|
||||
}))
|
||||
: [];
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
@@ -52,28 +62,32 @@
|
||||
<Layout.Stack>
|
||||
<Upload.Dropzone bind:files>
|
||||
<Layout.Stack alignItems="center" gap="s">
|
||||
<Layout.Stack
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
direction="row"
|
||||
gap="s">
|
||||
<Typography.Text variant="l-500">
|
||||
<Layout.Stack alignItems="center" justifyContent="center" inline>
|
||||
<Typography.Text variant="l-500" align="center" inline>
|
||||
Drag and drop files here or click to upload
|
||||
</Typography.Text>
|
||||
<Tooltip>
|
||||
<Layout.Stack alignItems="center" justifyContent="center" inline>
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Layout.Stack
|
||||
style="display: inline-flex; vertical-align: middle;"
|
||||
inline
|
||||
alignItems="center"
|
||||
justifyContent="center">
|
||||
<Tooltip>
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<svelte:fragment slot="tooltip"
|
||||
>Only .env files allowed</svelte:fragment>
|
||||
</Tooltip>
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="tooltip">
|
||||
Only .env files allowed
|
||||
</svelte:fragment>
|
||||
</Tooltip>
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Typography.Caption variant="400">
|
||||
<Typography.Caption variant="400" align="center">
|
||||
Up to 100 variables allowed
|
||||
</Typography.Caption>
|
||||
</Layout.Stack>
|
||||
</Upload.Dropzone>
|
||||
{#if files?.length}
|
||||
<Upload.List
|
||||
bind:files={filesList}
|
||||
on:remove={(e) => (files = removeFile(e.detail, files))} />
|
||||
{/if}
|
||||
{#if variables?.length > 0}
|
||||
<Alert.Inline status="info" dismissible>
|
||||
This action can create and update variables but can not delete them.
|
||||
|
||||
@@ -76,6 +76,20 @@
|
||||
showAccountMenu = false;
|
||||
}
|
||||
|
||||
function closeOpenDialogs() {
|
||||
if (typeof document === 'undefined') return;
|
||||
|
||||
const openDialogs = Array.from(
|
||||
document.querySelectorAll('dialog[open]')
|
||||
) as HTMLDialogElement[];
|
||||
|
||||
for (const dialog of openDialogs) {
|
||||
dialog.close();
|
||||
}
|
||||
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel navigation when wizard is open and triggered by popstate
|
||||
*/
|
||||
@@ -184,6 +198,7 @@
|
||||
$: isProjectBlocked = getIsProjectBlocked(selectedProject);
|
||||
$: {
|
||||
if ($isSidebarOpen) {
|
||||
closeOpenDialogs();
|
||||
yOnMenuOpen = window.scrollY;
|
||||
bodyStyle.set({ position: 'fixed', top: `-${window.scrollY}px` });
|
||||
} else if (!$isSidebarOpen) {
|
||||
@@ -260,7 +275,7 @@
|
||||
<style lang="scss">
|
||||
.shell-sidebar-area {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.content {
|
||||
@@ -335,7 +350,7 @@
|
||||
height: 100vh;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
z-index: 19;
|
||||
background-color: #56565c1a;
|
||||
backdrop-filter: blur(5px);
|
||||
transition:
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<Modal
|
||||
bind:show={showCreate}
|
||||
onSubmit={handleVariable}
|
||||
title={`Create' ${isGlobal ? 'global' : 'environment'} variable`}>
|
||||
title={`Create ${isGlobal ? 'global' : 'environment'} variables`}>
|
||||
<svelte:fragment slot="description">
|
||||
<span>
|
||||
Set the environment variables or secret keys that will be passed to {!isGlobal
|
||||
|
||||
+15
-2
@@ -84,7 +84,7 @@
|
||||
<svelte:fragment slot="aside">
|
||||
{#if total > 0}
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
<div class="installations-action-row">
|
||||
<FormButton
|
||||
secondary
|
||||
href={configureGitHub()}
|
||||
@@ -94,7 +94,7 @@
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Add installation
|
||||
</FormButton>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
|
||||
<Table.Root
|
||||
let:root
|
||||
@@ -233,3 +233,16 @@
|
||||
</Card.Base>
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
<style>
|
||||
.installations-action-row {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.installations-action-row {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
import SecretVariableModal from './secretVariableModal.svelte';
|
||||
import { Confirm } from '$lib/components';
|
||||
import { resolveRoute, withPath } from '$lib/stores/navigation';
|
||||
import { isSmallViewport } from '$lib/stores/viewport';
|
||||
|
||||
export let project: Models.Project;
|
||||
export let variableList: Models.VariableList;
|
||||
@@ -266,6 +267,18 @@
|
||||
});
|
||||
})
|
||||
: false;
|
||||
|
||||
$: variableColumns = $isSmallViewport
|
||||
? [
|
||||
{ id: 'key', width: { min: 380, max: 520 } },
|
||||
{ id: 'value', width: { min: 200, max: 320 } },
|
||||
{ id: 'actions', width: 50 }
|
||||
]
|
||||
: [
|
||||
{ id: 'key', width: { min: 280, max: 420 } },
|
||||
{ id: 'value', width: { min: 200, max: 400 } },
|
||||
{ id: 'actions', width: 50 }
|
||||
];
|
||||
</script>
|
||||
|
||||
<CardGrid>
|
||||
@@ -288,8 +301,8 @@
|
||||
{/if}
|
||||
<svelte:fragment slot="aside">
|
||||
<Layout.Stack gap="l">
|
||||
<Layout.Stack direction="row">
|
||||
<Layout.Stack direction="row" gap="s">
|
||||
<Layout.Stack direction="row" gap="s" wrap={$isSmallViewport ? 'wrap' : 'nowrap'}>
|
||||
<Layout.Stack direction="row" gap="s" wrap={$isSmallViewport ? 'wrap' : 'nowrap'}>
|
||||
<Button
|
||||
secondary
|
||||
on:mousedown={() => {
|
||||
@@ -345,13 +358,7 @@
|
||||
</p>
|
||||
</Alert.Inline>
|
||||
{/if}
|
||||
<Table.Root
|
||||
columns={[
|
||||
{ id: 'key', width: { min: 200, max: 400 } },
|
||||
{ id: 'value', width: { min: 200, max: 400 } },
|
||||
{ id: 'actions', width: 50 }
|
||||
]}
|
||||
let:root>
|
||||
<Table.Root class="responsive-table" columns={variableColumns} let:root>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Table.Header.Cell column="key" {root}>Key</Table.Header.Cell>
|
||||
<Table.Header.Cell column="value" {root}>Value</Table.Header.Cell>
|
||||
@@ -366,7 +373,11 @@
|
||||
) !== undefined
|
||||
: false}
|
||||
|
||||
<Layout.Stack gap="xxs" alignItems="center" direction="row">
|
||||
<Layout.Stack
|
||||
gap="xxs"
|
||||
alignItems="center"
|
||||
direction="row"
|
||||
class="variable-key-cell">
|
||||
{#if isConflicting && hasConflictOnPage}
|
||||
<span
|
||||
class="icon-exclamation u-color-text-warning"
|
||||
@@ -526,3 +537,16 @@
|
||||
<p>Are you sure you want to delete this variable? This action is irreversible.</p>
|
||||
</Confirm>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
:global(.variable-key-cell) {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:global(.variable-key-cell > :last-child) {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
Upload
|
||||
} from '@appwrite.io/pink-svelte';
|
||||
import { parse } from '$lib/helpers/envfile';
|
||||
import { removeFile } from '$lib/helpers/files';
|
||||
|
||||
export let show = false;
|
||||
export let variableList: Models.VariableList;
|
||||
@@ -33,6 +34,15 @@
|
||||
let files: FileList;
|
||||
let secret = false;
|
||||
let error: string;
|
||||
$: filesList = files?.length
|
||||
? Array.from(files).map((file) => ({
|
||||
...file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
extension: file.type,
|
||||
removable: true
|
||||
}))
|
||||
: [];
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
@@ -87,21 +97,33 @@
|
||||
<Upload.Dropzone bind:files>
|
||||
<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">
|
||||
<Layout.Stack alignItems="center" justifyContent="center" inline>
|
||||
<Typography.Text variant="l-500" align="center" inline>
|
||||
Drag and drop files here or click to upload
|
||||
</Typography.Text>
|
||||
<Tooltip>
|
||||
<Layout.Stack alignItems="center" justifyContent="center" inline>
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<Layout.Stack
|
||||
style="display: inline-flex; vertical-align: middle;"
|
||||
inline
|
||||
alignItems="center"
|
||||
justifyContent="center">
|
||||
<Tooltip>
|
||||
<Icon icon={IconInfo} size="s" />
|
||||
<svelte:fragment slot="tooltip"
|
||||
>Only .env files allowed</svelte:fragment>
|
||||
</Tooltip>
|
||||
</Layout.Stack>
|
||||
<svelte:fragment slot="tooltip">Only .env files allowed</svelte:fragment>
|
||||
</Tooltip>
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<Typography.Caption variant="400">Up to 100 variables allowed</Typography.Caption>
|
||||
<Typography.Caption variant="400" align="center">
|
||||
Up to 100 variables allowed
|
||||
</Typography.Caption>
|
||||
</Layout.Stack>
|
||||
</Layout.Stack>
|
||||
</Upload.Dropzone>
|
||||
{#if files?.length}
|
||||
<Upload.List
|
||||
bind:files={filesList}
|
||||
on:remove={(e) => (files = removeFile(e.detail, files))} />
|
||||
{/if}
|
||||
|
||||
{#if variableList.total > 0}
|
||||
<Alert.Inline>
|
||||
|
||||
Reference in New Issue
Block a user