Merge pull request #1769 from appwrite/feat-pink-v2-svelte5

feat: svelte 5
This commit is contained in:
Torsten Dittmann
2025-03-31 16:50:36 +02:00
committed by GitHub
204 changed files with 2254 additions and 5793 deletions
-10
View File
@@ -1,10 +0,0 @@
src/sdk.ts
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
/playwright-report
-43
View File
@@ -1,43 +0,0 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
parserOptions: {
extraFileExtensions: ['.svelte'], // This is a required setting in `@typescript-eslint/parser` v4.24.0.
sourceType: 'module',
ecmaVersion: 2020
},
ignorePatterns: ['*.cjs'],
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser' //This is required to parse TypeScript inside Svelte files.
}
}
],
rules: {
'no-redeclare': 'off',
'@typescript-eslint/no-duplicate-enum-values': 'off',
'svelte/no-at-html-tags': 'off',
'no-unused-vars': 'off', // This rule is handled by `@typescript-eslint/no-unused-vars` so it needs to be disabled to avoid conflicts.
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^(_|\\$\\$)' } // Ignore unused variables starting with `_` or `$$`.
]
},
env: {
browser: true,
es2017: true,
node: true
},
globals: {
globalThis: false // false means it is not writeable
}
};
-2
View File
@@ -25,8 +25,6 @@ jobs:
run: pnpm audit --audit-level high
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run sync
run: pnpm run sync
- name: Svelte Diagnostics
run: pnpm run check
- name: Linter
+1 -1
View File
@@ -32,7 +32,7 @@ ENV PUBLIC_STRIPE_KEY=$PUBLIC_STRIPE_KEY
ENV SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN
ENV NODE_OPTIONS=--max_old_space_size=8192
RUN pnpm run sync && pnpm run build
RUN pnpm run build
FROM nginx:1.25-alpine
+51
View File
@@ -0,0 +1,51 @@
import prettier from 'eslint-config-prettier';
import js from '@eslint/js';
import { includeIgnoreFile } from '@eslint/compat';
import svelte from 'eslint-plugin-svelte';
import globals from 'globals';
import { fileURLToPath } from 'node:url';
import ts from 'typescript-eslint';
import svelteConfig from './svelte.config.js';
const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
export default ts.config(
includeIgnoreFile(gitignorePath),
js.configs.recommended,
...ts.configs.recommended,
...svelte.configs.recommended,
prettier,
...svelte.configs.prettier,
{
languageOptions: {
globals: { ...globals.browser, ...globals.node }
},
rules: {
// TODO: remove them one by one
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-duplicate-enum-values': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'svelte/infinite-reactive-loop': 'off',
'svelte/require-each-key': 'off',
'svelte/no-immutable-reactive-statements': 'off',
'svelte/no-at-html-tags': 'off',
'svelte/no-useless-mustaches': 'off',
'svelte/no-reactive-reassign': 'off',
'svelte/no-reactive-literals': 'off'
}
},
{
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
ignores: ['eslint.config.js', 'svelte.config.js'],
languageOptions: {
parserOptions: {
// Only uncomment this if you want it to take 3 minutes https://github.com/sveltejs/eslint-plugin-svelte/issues/1084
// projectService: true,
extraFileExtensions: ['.svelte'],
parser: ts.parser,
svelteConfig
}
}
}
);
+42 -33
View File
@@ -1,5 +1,6 @@
{
"name": "@appwrite/console",
"type": "module",
"engines": {
"node": ">=20"
},
@@ -7,16 +8,16 @@
"dev": "vite dev",
"build": "node build.js",
"preview": "vite preview",
"sync": "svelte-kit sync",
"check": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings --threshold warning",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"lint": "prettier --check . && eslint .",
"test": "TZ=EST vitest run",
"test:ui": "TZ=EST vitest --ui",
"test:watch": "TZ=EST vitest watch",
"e2e": "playwright test tests/e2e",
"e2e:ui": "playwright test tests/e2e --ui"
"e2e": "playwright test",
"e2e:ui": "playwright test --ui"
},
"dependencies": {
"@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@fbd0051",
@@ -28,57 +29,65 @@
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
"ai": "^2.2.37",
"analytics": "^0.8.14",
"analytics": "^0.8.16",
"cron-parser": "^4.9.0",
"dayjs": "^1.11.13",
"deep-equal": "^2.2.3",
"echarts": "^5.5.1",
"echarts": "^5.6.0",
"envfile": "^7.1.0",
"ignore": "^6.0.2",
"nanoid": "^5.0.8",
"nanoid": "^5.1.5",
"nanotar": "^0.1.1",
"plausible-tracker": "^0.3.9",
"pretty-bytes": "^6.1.1",
"prismjs": "^1.29.0",
"prismjs": "^1.30.0",
"remarkable": "^2.0.1",
"svelte-confetti": "^1.4.0",
"tippy.js": "^6.3.7"
},
"devDependencies": {
"@eslint/compat": "^1.2.7",
"@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.86.2",
"@playwright/test": "^1.49.0",
"@sveltejs/adapter-static": "^3.0.6",
"@sveltejs/kit": "^2.8.1",
"@sveltejs/vite-plugin-svelte": "^3.1.2",
"@melt-ui/svelte": "^0.86.5",
"@playwright/test": "^1.51.1",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.2",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/svelte": "^5.2.4",
"@testing-library/user-event": "^14.5.2",
"@testing-library/user-event": "^14.6.1",
"@types/deep-equal": "^1.0.4",
"@types/prismjs": "^1.26.5",
"@types/remarkable": "^2.0.8",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@vitest/ui": "^1.6.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.46.0",
"jsdom": "^22.1.0",
"@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0",
"@vitest/ui": "^3.0.9",
"eslint": "^9.23.0",
"eslint-config-prettier": "^10.1.0",
"eslint-plugin-svelte": "^3.3.3",
"globals": "^16.0.0",
"jsdom": "^26.0.0",
"kleur": "^4.1.5",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.8",
"sass": "^1.81.0",
"svelte": "^4.2.19",
"svelte-check": "^3.8.6",
"svelte-jester": "^2.3.2",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"sass": "^1.86.0",
"svelte": "^5.25.3",
"svelte-check": "^4.1.5",
"svelte-preprocess": "^6.0.3",
"svelte-sequential-preprocessor": "^2.0.2",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vitest": "^1.6.0"
"typescript": "^5.8.2",
"vite": "^6.2.3",
"vitest": "^3.0.0"
},
"type": "module",
"packageManager": "pnpm@10.4.1"
"pnpm": {
"onlyBuiltDependencies": [
"@parcel/watcher",
"@sentry/cli",
"esbuild",
"svelte-preprocess"
]
},
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
}
+1
View File
@@ -5,6 +5,7 @@ const config: PlaywrightTestConfig = {
reportSlowTests: null,
reporter: [['html', { open: 'never' }]],
retries: 3,
testDir: 'e2e',
use: {
baseURL: 'http://localhost:4173/console/',
trace: 'on-first-retry'
+1342 -3204
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -88,7 +88,7 @@
<svelte:window on:resize={onResize} />
<div class="echart" bind:this={container} />
<div class="echart" bind:this={container}></div>
<style>
.echart {
+2 -2
View File
@@ -158,7 +158,7 @@
</div>
<div slot="option" let:option class="u-flex u-cross-center u-gap-8">
<i class="icon-question-mark-circle" />
<i class="icon-question-mark-circle"></i>
<span>{option.label}</span>
</div>
@@ -248,7 +248,7 @@
aria-label="ask AI"
type="submit"
disabled={!$input.trim() || $isLoading}>
<span class="icon-arrow-sm-right" aria-hidden="true" />
<span class="icon-arrow-sm-right" aria-hidden="true"></span>
</button>
</div>
</form>
@@ -22,7 +22,7 @@
<Template options={filteredOptions} bind:search>
<div class="u-flex u-cross-center u-gap-8" slot="option" let:option>
<i class="icon-{option.icon}" />
<i class="icon-{option.icon}"></i>
<span>{option.label}</span>
</div>
</Template>
@@ -67,7 +67,7 @@
<Template options={filteredOptions} bind:search>
<div class="u-flex u-cross-center u-gap-8" slot="option" let:option>
<i class="icon-{option.icon}" />
<i class="icon-{option.icon}"></i>
<span>{option.label}</span>
</div>
</Template>
@@ -50,7 +50,7 @@
<Template options={filteredPlatforms} bind:search>
<div class="u-flex u-cross-center u-gap-8" slot="option" let:option>
<i class="icon-{option.icon}" />
<i class="icon-{option.icon}"></i>
<span>{option.label}</span>
</div>
</Template>
+2 -2
View File
@@ -262,7 +262,7 @@
{@const isLast = i === breadcrumbs.length - 1}
<button class="crumb" on:click={() => handleCrumbClick(i)}>
<span>{crumb}</span>
<i class="icon-x" />
<i class="icon-x"></i>
</button>
{#if !isLast}
<span style="opacity: 50%">/</span>
@@ -296,7 +296,7 @@
class:first-nested={isFirstNested(i)}
class:last-nested={isLastNested(i)}>
{#if isSelected}
<div class="bg" />
<div class="bg"></div>
{/if}
<button
class="option"
+2 -2
View File
@@ -1,9 +1,9 @@
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
import { writable } from 'svelte/store';
export type SubPanel = {
name: string;
component: typeof SvelteComponent<unknown>;
component: Component;
};
type CastSubPanel = Omit<SubPanel, 'component'> & {
+2 -2
View File
@@ -31,7 +31,7 @@
class="button is-text is-only-icon"
aria-label="close alert box"
on:click={() => dispatch('dismiss')}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
{/if}
<span
@@ -39,7 +39,7 @@
class:icon-check-circle={type === 'success'}
class:icon-exclamation={type === 'warning'}
class:icon-exclamation-circle={type === 'error'}
aria-hidden="true" />
aria-hidden="true"></span>
<div class="alert-content" data-private>
{#if $$slots.title}
<h6 class="alert-title">
+4 -3
View File
@@ -158,13 +158,13 @@
on:click={() => {
openStates[key] = !openStates[key];
}}>
<span class="icon-cheveron-up" aria-hidden="true" />
<span class="icon-cheveron-up" aria-hidden="true"></span>
</button>
<button
class="upload-box-button"
aria-label="close backup restore box"
on:click={() => handleClose(key)}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</header>
@@ -186,7 +186,8 @@
<div
class="progress-bar-container"
class:is-danger={item.status === 'failed'}
style="--graph-size:{graphSize(item.status)}%" />
style="--graph-size:{graphSize(item.status)}%">
</div>
</section>
</li>
{/each}
@@ -49,7 +49,7 @@
</InputText>
{#if couponData?.status === 'error'}
<div>
<span class="icon-exclamation-circle u-color-text-danger" />
<span class="icon-exclamation-circle u-color-text-danger"></span>
<span>
{couponData.code.toUpperCase()} is not a valid promo code
</span>
@@ -57,7 +57,7 @@
{:else if couponData?.status === 'active'}
<div class="u-flex u-main-space-between u-cross-center">
<div>
<span class="icon-tag u-color-text-success" />
<span class="icon-tag u-color-text-success"></span>
<slot data={couponData}>
<span>
{couponData.code.toUpperCase()} applied (-{formatCurrency(couponData.credits)})
@@ -15,7 +15,7 @@
<span class="u-flex u-main-space-between">
<div class="u-flex u-cross-center u-gap-4">
<p class="text">
<span class="icon-tag u-color-text-success" aria-hidden="true" />
<span class="icon-tag u-color-text-success" aria-hidden="true"></span>
{#if couponData.credits >= 100}
{couponData?.code?.toUpperCase()}
{:else}
@@ -40,7 +40,7 @@
status: null,
credits: null
})}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
{/if}
</div>
+4 -4
View File
@@ -76,7 +76,7 @@
<Table.Cell {root}>{plan.members} members</Table.Cell>
<Table.Cell {root}>
<p class="u-color-text-danger u-flex u-cross-center u-gap-4">
<span class="icon-arrow-up" />
<span class="icon-arrow-up"></span>
{excess?.members} members
</p>
</Table.Cell>
@@ -88,7 +88,7 @@
<Table.Cell {root}>{plan.storage} GB</Table.Cell>
<Table.Cell {root}>
<p class="u-color-text-danger">
<span class="icon-arrow-up" />
<span class="icon-arrow-up"></span>
{humanFileSize(excess?.storage).value}
{humanFileSize(excess?.storage).unit}
</p>
@@ -103,7 +103,7 @@
</Table.Cell>
<Table.Cell {root}>
<p class="u-color-text-danger">
<span class="icon-arrow-up" />
<span class="icon-arrow-up"></span>
<span
title={excess?.executions
? excess.executions.toString()
@@ -122,7 +122,7 @@
</Table.Cell>
<Table.Cell column="usage" {root}>
<p class="u-color-text-danger">
<span class="icon-arrow-up" />
<span class="icon-arrow-up"></span>
<span title={excess?.users ? excess.users.toString() : 'users'}>
{formatNum(excess?.users)} users
</span>
+4 -7
View File
@@ -132,14 +132,14 @@
class="icon-cheveron-left"
on:click={showPrevious}
disabled={currentIndex === 0}
class:active={currentIndex > 0} />
class:active={currentIndex > 0}></button>
<button
class="icon-cheveron-right"
on:click={showNext}
disabled={currentIndex === filteredModalAlerts.length - 1}
class:active={currentIndex !==
filteredModalAlerts.length - 1} />
filteredModalAlerts.length - 1}></button>
</div>
</div>
{/if}
@@ -242,7 +242,7 @@
class="icon-cheveron-left"
on:click={showPrevious}
disabled={currentIndex === 0}
class:active={currentIndex > 0} />
class:active={currentIndex > 0}></button>
<button
class="icon-cheveron-right"
@@ -250,7 +250,7 @@
disabled={currentIndex ===
filteredModalAlerts.length - 1}
class:active={currentIndex !==
filteredModalAlerts.length - 1} />
filteredModalAlerts.length - 1}></button>
</div>
</div>
{/if}
@@ -319,9 +319,6 @@
<div class="u-flex-vertical u-gap-4">
<div class="u-flex u-cross-center u-main-space-between">
<h3 class="body-text-2 u-bold">New features available</h3>
<button on:click={hideAllModalAlerts}>
<span class="icon-x" />
</button>
</div>
<span class="u-width-fit-content">
+5 -5
View File
@@ -224,7 +224,7 @@
></ActionMenu.Root>
</div>
{#if organizations.length > 1}
<div class="separator" use:melt={$separatorOrganizations} />
<div class="separator" use:melt={$separatorOrganizations}></div>
<div use:melt={$subTriggerOrganizations}>
<ActionMenu.Root>
@@ -244,7 +244,7 @@
</ActionMenu.Root>
</div>
{/each}
<div class="separator" use:melt={$separatorOrganizations} />
<div class="separator" use:melt={$separatorOrganizations}></div>
<div use:melt={$itemOrganizations}>
<ActionMenu.Root>
<ActionMenu.Item.Button
@@ -257,7 +257,7 @@
</Card.Base>
</div>
{:else}
<div class="separator" use:melt={$separatorOrganizations} />
<div class="separator" use:melt={$separatorOrganizations}></div>
<div use:melt={$itemOrganizations}>
<ActionMenu.Root>
<ActionMenu.Item.Button leadingIcon={IconPlusSm} on:click={createOrg}
@@ -275,7 +275,7 @@
></ActionMenu.Root>
</div>
{/each}
<div class="separator" use:melt={$separatorOrganizations} />
<div class="separator" use:melt={$separatorOrganizations}></div>
<div use:melt={$itemOrganizations}>
<ActionMenu.Root>
<ActionMenu.Item.Button leadingIcon={IconPlusSm} on:click={createOrg}
@@ -329,7 +329,7 @@
</div>
{/if}
{/each}
<div class="separator" use:melt={$separatorProjects} />
<div class="separator" use:melt={$separatorProjects}></div>
{/if}
<div use:melt={$itemProjects}>
<ActionMenu.Root>
+2 -2
View File
@@ -51,7 +51,7 @@
{#if label}
<Pill>
{#if labelIcon}
<span class={`icon-${labelIcon}`} aria-hidden="true" />
<span class={`icon-${labelIcon}`} aria-hidden="true"></span>
{/if}
{label}
</Pill>
@@ -59,7 +59,7 @@
{#if withCopy}
<Copy value={code}>
<button class="button is-small is-text is-only-icon" aria-label="copy code">
<span class="icon-duplicate" aria-hidden="true" />
<span class="icon-duplicate" aria-hidden="true"></span>
</button>
</Copy>
{/if}
+1 -1
View File
@@ -44,7 +44,7 @@
<span
class="icon-cheveron-down u-font-size-20"
class:u-color-text-disabled={disabled}
aria-hidden="true" />
aria-hidden="true"></span>
</div>
</slot>
</summary>
+2 -1
View File
@@ -125,7 +125,8 @@
class="drop-arrow"
class:is-popover={isPopover}
class:u-hide={!show || (show && noArrow)}
bind:this={arrow} />
bind:this={arrow}>
</div>
{#if show}
<slot name="list" />
{/if}
+2 -2
View File
@@ -28,10 +28,10 @@
{disabled}>
<span class="text"><slot /></span>
{#if icon}
<span class={`icon-${icon}`} aria-hidden="true" />
<span class={`icon-${icon}`} aria-hidden="true"></span>
{/if}
{#if loading}
<span class="loader is-small u-line-height-1-5" aria-hidden="true" />
<span class="loader is-small u-line-height-1-5" aria-hidden="true"></span>
{/if}
</button>
</li>
+1 -1
View File
@@ -30,7 +30,7 @@
rel={external ? 'noopener noreferrer' : ''}>
<span class="text"><slot /></span>
{#if icon}
<span class={`icon-${icon}`} style={iconStyle} aria-hidden="true" />
<span class={`icon-${icon}`} style={iconStyle} aria-hidden="true"></span>
{/if}
</a>
</li>
+3 -5
View File
@@ -82,7 +82,7 @@
class:is-warning={state === 'warning'}
class:is-danger={state === 'error'}
class:is-info={state === 'info'}>
<span class={`icon-${icon}`} aria-hidden="true" />
<span class={`icon-${icon}`} aria-hidden="true"></span>
</div>
{/if}
@@ -104,7 +104,7 @@
from: 'button'
})}
on:click={closeModal}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
{/if}
</div>
@@ -149,9 +149,7 @@
display: flex;
align-items: center;
justify-content: center;
:global() {
background-color: hsl(240 5% 8% / 0.6);
}
background-color: hsl(240 5% 8% / 0.6);
& :global(.modal-form) {
position: unset;
+1 -1
View File
@@ -150,7 +150,7 @@
<Typography.Caption variant="500">Buckets</Typography.Caption>
{#await buckets}
<div class="u-flex u-main-center">
<div class="loader" />
<div class="loader"></div>
</div>
{:then response}
<ActionMenu.Root>
@@ -58,7 +58,6 @@
$columns,
analyticsSource
);
subSheets = subSheets;
}
};
})
@@ -86,7 +86,7 @@
{/if}
{/each}
{#if filter.options.some((option) => option.checked)}
<div class="separator" use:melt={$separator} />
<div class="separator" use:melt={$separator}></div>
<div use:melt={$item}>
<ActionMenu.Root>
<ActionMenu.Item.Button
+1 -1
View File
@@ -18,7 +18,7 @@
</div>
<div class="file-preview-content">
<div class="avatar">
<span class="icon-external-link" aria-hidden="true" />
<span class="icon-external-link" aria-hidden="true"></span>
</div>
</div>
</a>
+1 -1
View File
@@ -20,7 +20,7 @@
aria-label="Close"
title="Close"
on:click={() => (show = false)}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
{/if}
</div>
+1 -1
View File
@@ -3,6 +3,6 @@
</script>
<li class="list-item">
<span class={icon ? `icon-${icon}` : 'icon-check-circle'} aria-hidden="true" />
<span class={icon ? `icon-${icon}` : 'icon-check-circle'} aria-hidden="true"></span>
<slot />
</li>
+3 -3
View File
@@ -5,9 +5,9 @@
</script>
<div class="loading-dots {className}">
<div class="dot" />
<div class="dot" />
<div class="dot" />
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<style>
+2 -2
View File
@@ -26,11 +26,11 @@
<Card.Base padding="xxxs">
{#if $$slots.start}
<slot name="start" />
<div class="separator" use:melt={$separator} />
<div class="separator" use:melt={$separator}></div>
{/if}
<slot name="menu" {toggle} />
{#if $$slots.end}
<div class="separator" use:melt={$separator} />
<div class="separator" use:melt={$separator}></div>
<slot name="end" {toggle} />
{/if}
</Card.Base>
+2 -2
View File
@@ -24,11 +24,11 @@
<Card.Base padding="xxxs">
{#if $$slots.start}
<slot name="start" />
<div class="separator" use:melt={$separator} />
<div class="separator" use:melt={$separator}></div>
{/if}
<slot name="menu" />
{#if $$slots.end}
<div class="separator" use:melt={$separator} />
<div class="separator" use:melt={$separator}></div>
<slot name="end" />
{/if}
</Card.Base>
+3 -2
View File
@@ -69,7 +69,7 @@
class="upload-box-button"
aria-label="close migration box"
on:click={() => ($showMigrationBox = false)}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</header>
<div class="upload-box-content is-open">
@@ -80,7 +80,8 @@
<div
class="progress-bar-container"
class:is-danger={migration.status === 'failed'}
style="--graph-size:{percentage}%" />
style="--graph-size:{percentage}%">
</div>
</section>
</div>
</section>
+1 -1
View File
@@ -32,7 +32,7 @@
from: 'button'
})}
on:click={close}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</div>
<p class="u-margin-block-start-4">
+1 -1
View File
@@ -274,7 +274,7 @@
class="account-backdrop"
on:click={() => {
showAccountMenu = false;
}} />
}}></button>
{/if}
</div>
</div>
+1 -1
View File
@@ -14,7 +14,7 @@
{#if !hideCopyIcon}
<div class="u-flex u-cross-child-start u-gap-8">
<button class="interactive-text-output-button" aria-label="copy text">
<span class="icon-duplicate" aria-hidden="true" />
<span class="icon-duplicate" aria-hidden="true"></span>
</button>
</div>
{/if}
+2 -5
View File
@@ -17,18 +17,15 @@
function handleOptionClick(page: number) {
if (currentPage !== page) {
offset = limit * (page - 1);
currentPage = page;
dispatch('change');
}
}
function handleButtonPage(direction: string) {
if (direction === 'next' && currentPage < totalPages) {
currentPage += 1;
offset = limit * (currentPage - 1);
dispatch('change');
} else if (direction === 'prev' && currentPage > 1) {
currentPage -= 1;
offset = limit * (currentPage - 1);
dispatch('change');
}
@@ -97,7 +94,7 @@
{:else}
<nav class="pagination">
<button type="button" class="button is-text is-disabled" aria-label="prev page">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="icon-cheveron-left" aria-hidden="true"></span>
<span class="text">Prev</span>
</button>
{#if !hidePages}
@@ -111,7 +108,7 @@
{/if}
<button type="button" class="button is-text is-disabled" aria-label="next page">
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
<span class="icon-cheveron-right" aria-hidden="true"></span>
</button>
</nav>
{/if}
@@ -15,7 +15,7 @@
<div class="progress-bar-top-line u-flex u-gap-8 u-main-space-between">
<h3 class="body-text-1 u-flex u-cross-baseline u-gap-4">
{#if icon}
<span class={`icon-${icon}`} aria-hidden="true" />
<span class={`icon-${icon}`} aria-hidden="true"></span>
{/if}
<span class="text">{name}</span>
</h3>
@@ -30,7 +30,8 @@
class="progress-bar-container"
class:is-warning={status === 'warning'}
class:is-danger={status === 'error'}
style:--graph-size={progress + '%'} />
style:--graph-size={progress + '%'}>
</div>
<div class="u-flex u-gap-8 u-main-space-between u-cross-baseline">
<span class="progress-bar-text-used">{used}{unit}</span>
<span class="progress-bar-text-max">{max}{unit}</span>
@@ -34,7 +34,7 @@
</Tooltip>
{/each}
{#if remainder > 0}
<div class="progressbar__content" style:width={`${(remainder / maxSize) * 100}%`} />
<div class="progressbar__content" style:width={`${(remainder / maxSize) * 100}%`}></div>
{/if}
</section>
+1 -1
View File
@@ -19,7 +19,7 @@
class:is-complete={status === 'completed' || status === 'ready'}
class:is-processing={status === 'processing' || status === 'building'}>
{#if status}
<span class="status-icon" style={statusIconStyle} />
<span class="status-icon" style={statusIconStyle}></span>
{/if}
<span class="text" data-private><slot /></span>
</div>
+2 -2
View File
@@ -23,10 +23,10 @@
<div class="steps-item-wrapper">
{#if completed}
<div class="bullet is-done">
<span class="icon-check" aria-hidden="true" />
<span class="icon-check" aria-hidden="true"></span>
</div>
{:else}
<div class="bullet" class:is-current={current} />
<div class="bullet" class:is-current={current}></div>
{/if}
<div class="steps-item-content">
<span class="text">{step.text}</span>
+2 -2
View File
@@ -106,7 +106,7 @@
aria-hidden="true"
class="{isSupportOnline()
? 'icon-check-circle u-color-text-success'
: 'icon-x-circle'} u-padding-block-end-1" />
: 'icon-x-circle'} u-padding-block-end-1"></span>
{supportTimings}
</div>
@@ -123,7 +123,7 @@
source: 'support_menu'
});
}}>
<span class={`icon-${option.icon}`} />
<span class={`icon-${option.icon}`}></span>
<span>{option.cta}</span>
</Button>
{/if}
+1 -1
View File
@@ -6,6 +6,6 @@
<li class="tile">
<a class="card" {href}>
<h2 class="tiles-title">{title}</h2>
<span class="icon-right-open" aria-hidden="true" />
<span class="icon-right-open" aria-hidden="true"></span>
</a>
</li>
+1 -1
View File
@@ -118,7 +118,7 @@
<span
class="loader is-small"
style:--p-loader-base-full-color="transparent"
aria-hidden="true" />
aria-hidden="true"></span>
{/if}
<slot isSubmitting={$isSubmitting} />
<slot slot="end" name="end" />
+1 -1
View File
@@ -16,7 +16,7 @@
class:icon-exclamation-circle={type === 'error'}
class:icon-check-circle={type === 'success'}
class:icon-exclamation={type === 'warning'}
aria-hidden="true" />
aria-hidden="true"></span>
{/if}
<span class="text u-line-height-1-5">
<slot />
+1 -1
View File
@@ -67,7 +67,7 @@
<span
class="icon-info"
aria-hidden="true"
style="font-size: var(--icon-size-small)" />
style="font-size: var(--icon-size-small)"></span>
</button>
<p slot="tooltip">{tooltip}</p>
</Tooltip>
+7 -7
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { Drop, Trim } from '$lib/components';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
import { SvelteComponent, onMount } from 'svelte';
import { type Component, onMount } from 'svelte';
import { Helper, Label } from '.';
import { Tooltip } from '@appwrite.io/pink-svelte';
@@ -14,7 +14,7 @@
export let optionalText: string = null;
export let tooltip: string = null;
export let error: string = null;
export let popover: typeof SvelteComponent<unknown> = null;
export let popover: Component = null;
export let popoverProps: Record<string, unknown> = {};
let input: HTMLInputElement;
@@ -137,7 +137,7 @@
<span
class="icon-info"
aria-hidden="true"
style="font-size: var(--icon-size-small)" />
style="font-size: var(--icon-size-small)"></span>
</button>
<svelte:fragment slot="list">
<div
@@ -165,7 +165,7 @@
on:dragleave|preventDefault={() => (hovering = false)}>
<div class="upload-file-box">
<div class="upload-file-box-image">
<span class="icon-upload" aria-hidden="true" />
<span class="icon-upload" aria-hidden="true"></span>
</div>
<div class="u-min-width-0 u-text-center">
<h5 class="upload-file-box-title heading-level-7 u-inline">
@@ -177,7 +177,7 @@
<button
class="u-inline u-margin-inline-start-4"
aria-label="variables info">
<span class="icon-info" aria-hidden="true" />
<span class="icon-info" aria-hidden="true"></span>
</button>
<p slot="tooltip">Only {allowedFileExtensions.join(', ')} accepted.</p>
</Tooltip>
@@ -205,7 +205,7 @@
{@const extension = file.name.split('.').pop()}
{@const fileSize = humanFileSize(file.size)}
<li class="u-flex u-cross-center u-min-width-0">
<span class="icon-document" aria-hidden="true" />
<span class="icon-document" aria-hidden="true"></span>
<span class="upload-file-box-name u-trim u-min-width-0">
<Trim>{fileName}</Trim>
</span>
@@ -222,7 +222,7 @@
class="button is-text is-only-icon u-margin-inline-start-auto"
aria-label="remove file"
style="--button-size:1.5rem;">
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</li>
{/each}
@@ -33,7 +33,7 @@
<span
class="icon-info"
aria-hidden="true"
style="font-size: var(--icon-size-small)" />
style="font-size: var(--icon-size-small)"></span>
</button>
<svelte:fragment slot="list">
<div
@@ -52,7 +52,7 @@
style:--box-border-radius="var(--border-radius-xsmall)">
<div class="upload-file-box">
<div class="upload-file-box-image">
<span class="icon-upload" aria-hidden="true" />
<span class="icon-upload" aria-hidden="true"></span>
</div>
<div class="u-min-width-0 u-text-center">
<h5 class="upload-file-box-title heading-level-7 u-inline">
@@ -75,7 +75,7 @@
{@const fileSize = humanFileSize(value.sizeOriginal)}
<ul class="upload-file-box-list u-min-width-0">
<li class="u-flex u-cross-center u-min-width-0">
<span class="icon-document" aria-hidden="true" />
<span class="icon-document" aria-hidden="true"></span>
<span class="upload-file-box-name u-min-width-0">
<Trim alternativeTrim>{value.name}</Trim>
</span>
@@ -89,7 +89,7 @@
class="button is-text is-only-icon u-margin-inline-start-auto"
aria-label="remove file"
style="--button-size:1.5rem;">
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</li>
</ul>
+1 -1
View File
@@ -32,7 +32,7 @@
{#if tooltip}
<Tooltip placement="top">
<span class="icon-info" aria-hidden="true" style="font-size: var(--icon-size-small)" />
<span class="icon-info" aria-hidden="true" style="font-size: var(--icon-size-small)"></span>
<div slot="tooltip">{tooltip}</div>
</Tooltip>
{/if}
+1 -1
View File
@@ -5,7 +5,7 @@
<span class="text-counter" class:active={count > 0}>
<span class="text-counter-count">{count}</span>
<span class="text-counter-separator" />
<span class="text-counter-separator"></span>
<span class="text-counter-max">{max}</span>
</span>
-1
View File
@@ -11,7 +11,6 @@ export function isHTMLInputElement(el: unknown): el is HTMLInputElement {
return el instanceof HTMLInputElement;
}
// eslint-disable-next-line @typescript-eslint/ban-types
export type Prettify<T> = T & {};
const columnTypes = [
+1 -1
View File
@@ -44,7 +44,7 @@
{/if}
{:else}
<div class="avatar is-size-small">
<span class="icon-anonymous" aria-hidden="true" />
<span class="icon-anonymous" aria-hidden="true"></span>
</div>
<span class="text u-trim">{log.userName ?? 'Anonymous'}</span>
{/if}
+1 -1
View File
@@ -34,7 +34,7 @@
{disabled}
href={buttonHref}>
{#if showIcon}
<span class={`icon-${icon}`} aria-hidden="true" />
<span class={`icon-${icon}`} aria-hidden="true"></span>
{/if}
<span class="text">{buttonText}</span>
</Button>
+2 -2
View File
@@ -121,11 +121,11 @@
<DropList bind:show={showDropdown} width="16">
{#if hasProjectLimitation}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />{total}/{limit} created
<span class="icon-info"></span>{total}/{limit} created
</Pill>
{:else if $organization?.billingPlan !== BillingPlan.SCALE}
<Pill button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-info" />Limits applied
<span class="icon-info"></span>Limits applied
</Pill>
{/if}
<svelte:fragment slot="list">
+1 -1
View File
@@ -49,7 +49,7 @@
class:icon-check-circle={type === 'success'}
class:icon-exclamation={type === 'warning'}
class:icon-exclamation-circle={type === 'error'}
class:icon-info={type === 'info' || type === 'default'} />
class:icon-info={type === 'info' || type === 'default'}></span>
<div class="alert-content">
{#if title || $$slots.title}
+453
View File
@@ -0,0 +1,453 @@
<script lang="ts">
import { hoursToDays, timeFromNow, toLocaleDateTime } from '$lib/helpers/date';
import { log } from '$lib/stores/logs';
import { Alert, Card, Code, Copy, Id, SvgIcon, Tab, Tabs } from '../components';
import { calculateTime } from '$lib/helpers/timeConversion';
import { beforeNavigate } from '$app/navigation';
import { Pill } from '$lib/elements';
import { isCloud } from '$lib/system';
import { getServiceLimit, tierToPlan, upgradeURL } from '$lib/stores/billing';
import { organization } from '$lib/stores/organization';
import { Button } from '$lib/elements/forms';
import { BillingPlan } from '$lib/constants';
import { Table, Tooltip, Typography } from '@appwrite.io/pink-svelte';
let selectedRequest = 'parameters';
let selectedResponse = 'logs';
const limit = getServiceLimit('logs');
const tier = tierToPlan($organization?.billingPlan)?.name;
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
event.preventDefault();
$log.show = false;
}
}
function parseUrl(url: string) {
if (!url) return;
const queryString = url.includes('?') ? url.split('?')[1] : '';
const queries: Record<string, string>[] = [];
for (const param of queryString.split('&')) {
let [key, ...valueArr] = param.split('=');
const value = valueArr.join('=');
if (key) {
queries.push({ key, value: value ?? '' });
}
}
return queries;
}
function unescapeNewLines(logs: string) {
return logs.replace(/\\n/g, '\n');
}
beforeNavigate((n) => {
if (!$log.show) return;
if (n.type === 'popstate') {
n.cancel();
}
$log.show = false;
});
$: parameters = parseUrl(execution?.requestPath);
$: execution = $log.data;
$: func = $log.func;
$: if (execution?.errors) {
selectedResponse = 'errors';
}
$: host = execution?.requestHeaders?.find((header) => header.name === 'host')?.value;
</script>
<svelte:window on:keydown={handleKeydown} />
{#if execution}
<section class="cover-frame" data-private>
<header class="cover-frame-header u-flex u-gap-16 u-main-space-between u-cross-center">
<div class="u-flex u-gap-8 u-cross-center">
<h1 class="body-text-1 u-bold">Function ID:</h1>
<Id value={func.$id}>{func.$id}</Id>
</div>
<button
on:click={() => ($log.show = false)}
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="close popup">
<span class="icon-x" aria-hidden="true"></span>
</button>
</header>
<div class="cover-frame-content u-flex u-flex-vertical">
<div class="grid-1-2">
<div class="grid-1-2-col-1">
<div class="u-flex u-gap-16">
<div class="avatar is-size-large">
<SvgIcon
size={56}
type="color"
name={func.runtime.split('-')[0]}
iconSize="large" />
</div>
<div class="u-grid-equal-row-size u-gap-4 u-line-height-1">
<h2 class="body-text-2 u-bold">Execution ID:</h2>
<Id value={execution.$id}>{execution.$id}</Id>
</div>
</div>
</div>
<div class="grid-1-2-col-2 u-flex u-main-space-between">
<ul class="u-grid-equal-row-size u-gap-4 u-line-height-1">
<li class="text">
<b>Duration: </b>
<time>
{calculateTime(execution.duration)}
</time>
</li>
<li class="text">
<b>Created at:</b>
<time>
{toLocaleDateTime(execution.$createdAt)}
</time>
</li>
{#if host}
<li class="text">
<b>Host:</b>
<span>
{host}
</span>
</li>
{/if}
</ul>
<div class="status u-margin-inline-start-auto">
<Tooltip
maxWidth="180px"
disabled={!execution?.scheduledAt || execution.status !== 'scheduled'}>
<div>
<Pill
warning={execution.status === 'waiting' ||
execution.status === 'building'}
danger={execution.status === 'failed'}
info={execution.status === 'completed' ||
execution.status === 'ready'}>
{#if execution.status === 'scheduled'}
<span class="icon-clock" aria-hidden="true"></span>
{timeFromNow(execution.scheduledAt)}
{:else}
{execution.status}
{/if}
</Pill>
</div>
<span slot="tooltip"
>{`Scheduled to execute on ${toLocaleDateTime(execution.scheduledAt)}`}</span>
</Tooltip>
</div>
</div>
</div>
<div class="u-stretch u-margin-block-start-32 u-overflow-hidden">
<section class="code-panel">
<header
class="code-panel-header code-panel-compact-header u-main-space-between u-width-full-line">
<div class="u-flex">
<div class="u-flex u-gap-16">
<h4 class="text u-bold">Method:</h4>
<span class="u-text-color-gray">{execution.requestMethod}</span>
</div>
<div class="u-flex u-gap-16">
<h4 class="text u-bold">Path:</h4>
<Copy value={execution.requestPath}>
<div
class="interactive-text-output is-textarea"
style:min-inline-size="0">
<span class="text u-line-height-1-5 u-break-all">
{execution.requestPath}
</span>
<div class="u-flex u-cross-child-start u-gap-8">
<button
class="interactive-text-output-button"
aria-label="copy text">
<span class="icon-duplicate" aria-hidden="true"
></span>
</button>
</div>
</div>
</Copy>
</div>
</div>
<div class="u-flex u-gap-24">
<div class="u-flex u-gap-16">
<h4 class="text u-bold">Triggered by:</h4>
<span class="u-text-color-gray">{execution.trigger}</span>
</div>
<div class="u-flex u-gap-16">
<h4 class="text u-bold">Status Code:</h4>
<span class="u-text-color-gray">
{execution.responseStatusCode}
</span>
</div>
</div>
</header>
<div class="code-panel-content grid-1-2">
<div
class="grid-1-2-col-1 u-flex u-flex-vertical u-gap-16 mobile-only-inline-20-padding">
<Typography.Title size="s">Request</Typography.Title>
<div class="u-sep-block-end">
<Tabs>
<Tab
selected={selectedRequest === 'parameters'}
on:click={() => (selectedRequest = 'parameters')}>
Parameters
</Tab>
<Tab
selected={selectedRequest === 'headers'}
on:click={() => (selectedRequest = 'headers')}>
Headers
</Tab>
<Tab
selected={selectedRequest === 'body'}
on:click={() => (selectedRequest = 'body')}>
Body
</Tab>
</Tabs>
</div>
{#if selectedRequest === 'parameters'}
{#if parameters?.length}
<Table.Root columns={2} let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Name</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each parameters as param}
<Table.Row.Base {root}>
<Table.Cell {root}>
{param.key}
</Table.Cell>
<Table.Cell {root}>
{param.value}
</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
{/if}
<p class="text u-text-center u-padding-24">
{parameters?.length
? 'Not all parameters data is'
: 'Parameters data is not'} captured by Appwrite for your user's
security and privacy. To display parameters data in the Logs tab,
use
<b>context.log()</b>.
<a
href="https://appwrite.io/docs/products/functions/development#logging"
target="_blank"
rel="noopener noreferrer"
class="link">Learn more</a
>.
</p>
{:else if selectedRequest === 'headers'}
{#if execution.requestHeaders.length}
<Table.Root columns={2} let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Name</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each execution.requestHeaders as header}
<Table.Row.Base {root}>
<Table.Cell {root}>
{header.name}
</Table.Cell>
<Table.Cell {root}>
{header.value}
</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
{/if}
<p class="text u-text-center u-padding-16">
{execution.requestHeaders?.length
? 'Not all header data is'
: 'Header data is not'}
captured by Appwrite for your user's security and privacy. To display
header data in the Logs tab, use
<b>context.log()</b>.
<a
href="https://appwrite.io/docs/products/functions/development#logging"
target="_blank"
rel="noopener noreferrer"
class="link">Learn more</a
>.
</p>
{:else if selectedRequest === 'body'}
<p class="text u-text-center u-padding-16">
Body data is not captured by Appwrite for your user's security
and privacy. To display body data in the Logs tab, use
<b>context.log()</b>.
<a
href="https://appwrite.io/docs/products/functions/development#logging"
target="_blank"
rel="noopener noreferrer"
class="link">Learn more</a
>.
</p>
{/if}
</div>
<div class="u-sep-block-end is-only-mobile u-padding-block-start-16"></div>
<div
class="grid-1-2-col-2 u-flex u-flex-vertical u-gap-16 u-min-width-0 mobile-only-inline-20-padding mobile-only-block-start-20-padding">
<Typography.Title size="s">Request</Typography.Title>
<div class="u-sep-block-end">
<Tabs>
<Tab
selected={selectedResponse === 'logs'}
on:click={() => (selectedResponse = 'logs')}>
Logs
</Tab>
<Tab
selected={selectedResponse === 'errors'}
on:click={() => (selectedResponse = 'errors')}>
Errors
</Tab>
<Tab
selected={selectedResponse === 'headers'}
on:click={() => (selectedResponse = 'headers')}>
Headers
</Tab>
<Tab
selected={selectedResponse === 'body'}
on:click={() => (selectedResponse = 'body')}>
Body
</Tab>
</Tabs>
</div>
{#if selectedResponse === 'logs'}
{#if execution?.logs}
{#if isCloud && limit !== 0 && limit < Infinity}
<Alert>
Logs are retained in rolling {hoursToDays(limit)} intervals
with the {tier} plan.
{#if $organization.billingPlan === BillingPlan.FREE}
<Button href={$upgradeURL}>Upgrade</Button> to increase
your log retention for a longer period.
{/if}
</Alert>
{/if}
<Code
allowScroll
withCopy
noMargin
code={unescapeNewLines(execution.logs)}
language="sh"
class="limited-code-height" />
{:else}
<Card isDashed>
<p class="text u-text-center">No response was recorded.</p>
</Card>
{/if}
{:else if selectedResponse === 'errors'}
{#if execution?.errors}
<Code
allowScroll
withCopy
noMargin
code={unescapeNewLines(execution.errors)}
language="sh"
class="limited-code-height" />
{:else}
<Card isDashed>
<p class="text u-text-center">No response was recorded.</p>
</Card>
{/if}
{:else if selectedResponse === 'headers'}
{#if execution.responseHeaders.length}
<Table.Root columns={2} let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Name</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each execution.responseHeaders as header}
<Table.Row.Base {root}>
<Table.Cell {root}>
{header.name}
</Table.Cell>
<Table.Cell {root}>
{header.value}
</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
{/if}
<p class="text u-text-center u-padding-16">
{execution.responseHeaders?.length
? 'Not all header data is'
: 'Header data is not'}
captured by Appwrite for your user's security and privacy. To display
header data in the Logs tab, use
<b>context.log()</b>.
<a
href="https://appwrite.io/docs/products/functions/development#logging"
target="_blank"
rel="noopener noreferrer"
class="link">Learn more</a
>.
</p>
{:else if selectedResponse === 'body'}
<p class="text u-text-center u-padding-16">
Body data is not captured by Appwrite for your user's security
and privacy. To display body data in the Logs tab, use
<b>context.log()</b>.
<a
href="https://appwrite.io/docs/products/functions/development#logging"
target="_blank"
rel="noopener noreferrer"
class="link">Learn more</a
>.
</p>
{/if}
</div>
</div>
</section>
</div>
</div>
</section>
{/if}
<style>
:global(.limited-code-height) {
overflow: auto;
max-height: 50vh;
}
.code-panel-compact-header .u-flex {
gap: 1.5rem;
}
@media (max-width: 768px) {
.code-panel-compact-header {
row-gap: 1rem;
flex-direction: column;
}
.code-panel-content {
padding: unset;
padding-block: 1.5rem;
}
.mobile-only-inline-20-padding {
padding-inline: 1.5rem;
}
.mobile-only-block-start-20-padding {
padding-block-start: 1.5rem;
}
.code-panel-content.grid-1-2 {
display: unset;
row-gap: unset;
}
}
</style>
+1 -1
View File
@@ -101,7 +101,7 @@
</script>
{#if width}
<div class="progress-bar" class:progress-bar-hiding={completed} style={barStyle} />
<div class="progress-bar" class:progress-bar-hiding={completed} style={barStyle}></div>
{/if}
<style>
+2 -2
View File
@@ -55,7 +55,7 @@
? ''
: `url(${$app.themeInUse === 'dark' ? imgDark : imgLight})`}>
{#if variation !== 'default'}
<div class="side-bg-container" />
<div class="side-bg-container"></div>
{/if}
<div
class="logo u-flex u-gap-16"
@@ -79,7 +79,7 @@
</div>
{#if variation === 'default'}
<div class="u-flex u-stretch" />
<div class="u-flex u-stretch"></div>
<div class="tag-line is-not-mobile">
<p>Build like a team of hundreds<span class="underscore">_</span></p>
+1 -1
View File
@@ -36,7 +36,7 @@
class="button is-text is-only-icon"
style:--button-size="1.5rem"
aria-label="close popup">
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</div>
</slot>
+1 -1
View File
@@ -3,7 +3,7 @@
<slot />
</div>
{#if $$slots.aside}
<div class="wizard-secondary-content-sep" />
<div class="wizard-secondary-content-sep"></div>
<div class="wizard-secondary-content-2">
<slot name="aside" />
</div>
+6 -6
View File
@@ -3,7 +3,7 @@
number,
{
label: string;
component: typeof SvelteComponent<unknown>;
component: Component;
optional?: boolean;
disabled?: boolean;
actions?: {
@@ -21,7 +21,7 @@
import { Button, Form } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { wizard } from '$lib/stores/wizard';
import { createEventDispatcher, type SvelteComponent } from 'svelte';
import { createEventDispatcher, type Component } from 'svelte';
import WizardExitModal from './wizardExitModal.svelte';
import { Layout } from '@appwrite.io/pink-svelte';
@@ -158,9 +158,9 @@
<svelte:window on:keydown={handleKeydown} />
<section class="wizard">
<div class="wizard-header-strip" />
<div class="wizard-start-bg" />
<div class="wizard-end-bg" />
<div class="wizard-header-strip"></div>
<div class="wizard-start-bg"></div>
<div class="wizard-end-bg"></div>
<header class="wizard-header">
<div class="body-text-1 u-bold">{title}</div>
@@ -171,7 +171,7 @@
style="--button-size:1.5rem;"
aria-label="close wizard"
on:click={handleExit}>
<span class="icon-x" aria-hidden="true" />
<span class="icon-x" aria-hidden="true"></span>
</button>
</header>
@@ -28,7 +28,7 @@
<Table.Cell column="action" {root}>
<Button text>
<Copy value={target}>
<span class="icon-duplicate" aria-hidden="true" />
<span class="icon-duplicate" aria-hidden="true"></span>
</Copy>
</Button>
</Table.Cell>
+2 -2
View File
@@ -64,11 +64,11 @@
<CnameTable />
{:else if domain.status === 'unverified'}
<div class="u-flex u-gap-8 u-cross-center">
<span class="icon-exclamation-circle u-color-text-danger" aria-hidden="true" />
<span class="icon-exclamation-circle u-color-text-danger" aria-hidden="true"></span>
<p class="u-stretch">Generation failed</p>
<Button secondary on:click={retry} disabled={retrying}>
{#if retrying}
<div class="loader u-text-color-gray" />
<div class="loader u-text-color-gray"></div>
{:else}
Retry
{/if}
+5 -4
View File
@@ -27,7 +27,7 @@
<Retry domain={domainAsProxyRule()} on:error={onRetryError} showTitle={false} />
{:else}
<div class="u-flex u-gap-8 u-cross-center">
<span class="icon-check u-color-text-success" aria-hidden="true" />
<span class="icon-check u-color-text-success" aria-hidden="true"></span>
<p class="u-stretch">Domain verified</p>
</div>
{/if}
@@ -36,13 +36,14 @@
{#if $domain.status === 'verifying'}
<div
class="loader"
style="color: hsl(var(--color-neutral-50)); inline-size: 1.25rem; block-size: 1.25rem" />
style="color: hsl(var(--color-neutral-50)); inline-size: 1.25rem; block-size: 1.25rem">
</div>
<p class="u-stretch">Generating certificate</p>
{:else if $domain.status === 'verified'}
<span class="icon-check u-color-text-success" aria-hidden="true" />
<span class="icon-check u-color-text-success" aria-hidden="true"></span>
<p class="u-stretch">Certificate generated</p>
{:else}
<span class="icon-clock u-text-color-gray" aria-hidden="true" />
<span class="icon-clock u-text-color-gray" aria-hidden="true"></span>
<p class="u-stretch">
Certificate generation will begin after domain verification
</p>
+2 -2
View File
@@ -1,7 +1,7 @@
import { browser } from '$app/environment';
import { VARS } from '$lib/system';
import { get, writable } from 'svelte/store';
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
import FeedbackGeneral from '$lib/components/feedback/feedbackGeneral.svelte';
import FeedbackNps from '$lib/components/feedback/feedbackNPS.svelte';
import { Submit, trackEvent } from '$lib/actions/analytics';
@@ -23,7 +23,7 @@ export type FeedbackData = {
export type FeedbackOption = {
type: Feedback['type'];
desc?: string;
component: typeof SvelteComponent<unknown>;
component: Component;
};
export const feedbackOptions: FeedbackOption[] = [
+2 -2
View File
@@ -1,10 +1,10 @@
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
import { writable } from 'svelte/store';
export type HeaderAlert = {
id: string;
show: boolean;
component: typeof SvelteComponent<unknown>;
component: Component;
importance: number;
};
+5 -5
View File
@@ -1,5 +1,5 @@
import { writable } from 'svelte/store';
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
export type Tab = {
href: string;
@@ -14,12 +14,12 @@ export type Breadcrumb = {
export type View = 'list' | 'grid';
export type updateLayoutArguments = {
header?: typeof SvelteComponent<unknown>;
breadcrumb?: typeof SvelteComponent<unknown>;
header?: Component;
breadcrumb?: Component;
};
export const header = writable<typeof SvelteComponent<unknown>>();
export const breadcrumb = writable<typeof SvelteComponent<unknown>>();
export const header = writable<Component>();
export const breadcrumb = writable<Component>();
export function updateLayout(args: updateLayoutArguments) {
header.set(args.header ?? null);
+2 -2
View File
@@ -1,4 +1,4 @@
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
import Apple from '$routes/(console)/project-[project]/auth/(providers)/appleOAuth.svelte';
import Auth0 from '$routes/(console)/project-[project]/auth/(providers)/auth0OAuth.svelte';
import Authentik from '$routes/(console)/project-[project]/auth/(providers)/authentikOAuth.svelte';
@@ -13,7 +13,7 @@ export type Provider = {
name: string;
icon: string;
docs?: string;
component: typeof SvelteComponent<unknown>;
component: Component;
};
export const oAuthProviders: Record<string, Provider> = {
+1 -1
View File
@@ -4,5 +4,5 @@ import { derived } from 'svelte/store';
export const specificationsList = derived(
page,
async ($page) => (await $page.data.specificationsList) as Models.SpecificationList
($page) => $page.data.specificationsList as Models.SpecificationList
);
+5 -5
View File
@@ -1,13 +1,13 @@
import { trackEvent } from '$lib/actions/analytics';
import type { WizardStepsType } from '$lib/layout/wizardWithSteps.svelte';
import type { SvelteComponent } from 'svelte';
import type { Component } from 'svelte';
import { writable } from 'svelte/store';
export type WizardStore = {
show: boolean;
media?: string;
component?: typeof SvelteComponent<unknown>;
cover?: typeof SvelteComponent<unknown>;
component?: Component;
cover?: Component;
interceptor?: () => Promise<void>;
finalAction?: () => Promise<void>;
nextDisabled: boolean;
@@ -34,7 +34,7 @@ function createWizardStore() {
subscribe,
set,
start: (
component: typeof SvelteComponent<unknown>,
component: Component,
media: string = null,
step: number = 1,
props: Record<string, unknown> = {}
@@ -79,7 +79,7 @@ function createWizardStore() {
return n;
}),
showCover: (component: typeof SvelteComponent<unknown>) =>
showCover: (component: Component) =>
update((n) => {
n.cover = component;
return n;
@@ -141,7 +141,7 @@
<EyebrowHeading class="eyebrow" tag="h3" size={3}>Good to know</EyebrowHeading>
<div class="u-flex u-gap-16">
<div class="circled">
<i class="icon-cog" />
<i class="icon-cog"></i>
</div>
<div>
<p class="u-bold">Project settings are not imported</p>
@@ -150,7 +150,7 @@
</div>
<div class="u-flex u-gap-16">
<div class="circled">
<i class="icon-trending-up" />
<i class="icon-trending-up"></i>
</div>
<div>
<p class="u-bold">Keep your organization plan's limits in mind</p>
@@ -162,7 +162,7 @@
{#if $provider.provider === 'firebase'}
<div class="u-flex u-gap-16">
<div class="circled">
<i class="icon-exclamation u-color-text-warning" />
<i class="icon-exclamation u-color-text-warning"></i>
</div>
<div>
<p class="u-bold">Possible charges by Firebase</p>
@@ -175,7 +175,7 @@
{:else}
<div class="u-flex u-gap-16">
<div class="circled">
<i class="icon-currency-dollar" />
<i class="icon-currency-dollar"></i>
</div>
<div>
<p class="u-bold">Transfer is free of charge</p>
@@ -249,11 +249,11 @@
{#if report?.user !== undefined}
<span class="inline-tag">{report.user}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<span>Import all users</span>
{#if resources?.includes('team')}
@@ -269,11 +269,11 @@
{#if report?.team !== undefined}
<span class="inline-tag">{report.team}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<span>Import all teams and the team memberships of your users</span>
</li>
</ul>
@@ -293,11 +293,11 @@
{#if report?.database !== undefined}
<span class="inline-tag">{report.database}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<span>Import all databases, including collections, indexes and attributes</span>
{#if resources?.includes('document')}
@@ -313,11 +313,11 @@
{#if report?.document !== undefined}
<span class="inline-tag">{report.document}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<span>Import all of your documents</span>
</li>
</ul>
@@ -337,11 +337,11 @@
{#if report?.function !== undefined}
<span class="inline-tag">{report.function}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<span>Import all functions and their active deployment</span>
<ul>
{#if resources?.includes('environment-variable')}
@@ -353,7 +353,7 @@
<div class="u-flex u-gap-4">
<span class="u-bold">Include environment variables</span>
</div>
<div />
<div></div>
<span>Import all environment variables</span>
</li>
{/if}
@@ -366,7 +366,7 @@
<div class="u-flex u-gap-4">
<span class="u-bold">Include inactive deployments</span>
</div>
<div />
<div></div>
<span>Import all deployments that are not currently active</span>
</li>
{/if}
@@ -386,11 +386,11 @@
{#if report?.size !== undefined}
<span class="inline-tag">{`${report.size.toFixed(2)}MB`}</span>
{:else if !error}
<span class="loader is-small u-margin-inline-start-4" />
<span class="loader is-small u-margin-inline-start-4"></span>
{/if}
{/if}
</div>
<div />
<div></div>
<p>
Import all buckets
@@ -70,7 +70,7 @@
<div class="avatar is-size-small">
<span
class={`icon-${provider.icon}`}
style="font-size: var(--icon-size-medium)!important" />
style="font-size: var(--icon-size-medium)!important"></span>
</div>
{provider.name}
</Layout.Stack>
@@ -96,7 +96,7 @@
{/if}
</svelte:fragment>
{#await avatarList}
<span class="avatar is-color-empty" />
<span class="avatar is-color-empty"></span>
{:then avatars}
<AvatarGroup {avatars} />
{/await}
@@ -117,7 +117,7 @@
<span
class="icon-globe-alt"
style="--p-text-size: 1.25rem"
aria-hidden="true" />
aria-hidden="true"></span>
{/if}
</div>
<Trim>
@@ -127,7 +127,7 @@
{session.osVersion}
</Trim>
{:else}
<span class="avatar is-color-empty" />
<span class="avatar is-color-empty"></span>
<p class="text u-trim">Unknown</p>
{/if}
<div class="is-only-desktop">
@@ -157,7 +157,7 @@
<EyebrowHeading tag="h3" size={3} class="u-normal">Methods</EyebrowHeading>
<Layout.Stack direction="row">
<div class="avatar is-size-x-small">
<span class="icon-device-mobile" aria-hidden="true" />
<span class="icon-device-mobile" aria-hidden="true"></span>
</div>
<Layout.Stack gap="xxxs">
<Layout.Stack gap="s">
@@ -191,7 +191,7 @@
<Layout.Stack>
<Layout.Stack direction="row">
<div class="avatar is-size-x-small">
<span class="icon-mail" aria-hidden="true" />
<span class="icon-mail" aria-hidden="true"></span>
</div>
<Layout.Stack gap="xxxs">
<Layout.Stack gap="s" direction="row">
@@ -211,7 +211,7 @@
<Layout.Stack>
<Layout.Stack direction="row">
<div class="avatar is-size-x-small">
<span class="icon-mail" aria-hidden="true" />
<span class="icon-mail" aria-hidden="true"></span>
</div>
<Layout.Stack gap="xxxs">
<Layout.Stack gap="s" direction="row">
@@ -239,7 +239,7 @@
<Layout.Stack>
<Layout.Stack direction="row">
<div class="avatar is-size-x-small">
<span class="icon-send" aria-hidden="true" />
<span class="icon-send" aria-hidden="true"></span>
</div>
<Layout.Stack gap="xxxs">
<Layout.Stack gap="s" direction="row">
@@ -265,7 +265,7 @@
<Layout.Stack>
<Layout.Stack direction="row">
<div class="avatar is-size-x-small">
<span class="icon-lock-open" aria-hidden="true" />
<span class="icon-lock-open" aria-hidden="true"></span>
</div>
<Layout.Stack gap="xxxs">
<Layout.Stack gap="s" direction="row">
@@ -337,7 +337,8 @@
}}
disabled={$isSubmitting}>
{#if $isSubmitting}
<span class="loader is-small is-transparent u-line-height-1-5" aria-hidden="true" />
<span class="loader is-small is-transparent u-line-height-1-5" aria-hidden="true"
></span>
{/if}
{#if selectedOrgId === newOrgId}
Create organization
@@ -76,24 +76,26 @@
<Typography.Title size="l">Welcome to Appwrite</Typography.Title>
</div>
<div class="grid" class:remove-shadow={removeShadow}>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 1; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 2; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 3; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 4; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 5; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 6; " />
<div class="border-right is-not-mobile" style="grid-row: 1 / 6; grid-column-start: 7; " />
<div class="border-right is-not-mobile" style="grid-row: 1 / 6; grid-column-start: 8; " />
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 1; "></div>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 2; "></div>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 3; "></div>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 4; "></div>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 5; "></div>
<div class="border-right" style="grid-row: 1 / 6; grid-column-start: 6; "></div>
<div class="border-right is-not-mobile" style="grid-row: 1 / 6; grid-column-start: 7; ">
</div>
<div class="border-right is-not-mobile" style="grid-row: 1 / 6; grid-column-start: 8; ">
</div>
<div class="border-bottom" style="grid-row-start: 1;" />
<div class="border-bottom" style="grid-row-start: 2;" />
<div class="border-bottom" style="grid-row-start: 3;" />
<div class="border-bottom" style="grid-row-start: 4;" />
<div class="border-bottom" style="grid-row-start: 1;"></div>
<div class="border-bottom" style="grid-row-start: 2;"></div>
<div class="border-bottom" style="grid-row-start: 3;"></div>
<div class="border-bottom" style="grid-row-start: 4;"></div>
<div class="vertical-fade-top" style="grid-row-start: 1; " />
<div class="vertical-fade-bottom" style="grid-row-start: 5; " />
<div class="horizontal-fade-left" style="grid-row: 1 / 6; grid-column-start: 1;" />
<div class="horizontal-fade-right" style="grid-row: 1 / 6; " />
<div class="vertical-fade-top" style="grid-row-start: 1; "></div>
<div class="vertical-fade-bottom" style="grid-row-start: 5; "></div>
<div class="horizontal-fade-left" style="grid-row: 1 / 6; grid-column-start: 1;"></div>
<div class="horizontal-fade-right" style="grid-row: 1 / 6; "></div>
<div class="icon icon1" style:--delay={`${initialDelay}s`}>
<div class="icon-container">
@@ -186,7 +186,7 @@
</svelte:fragment>
{#if allServiceDisabled(project)}
<p>
<span class="icon-pause" aria-hidden="true" /> All services are disabled.
<span class="icon-pause" aria-hidden="true"></span> All services are disabled.
</p>
{/if}
@@ -40,7 +40,7 @@
on:click={downloadPdf}
href="{base}/legal/dpa.pdf"
event="download_dpa">
<span class="icon-download" aria-hidden="true" />
<span class="icon-download" aria-hidden="true"></span>
<span class="text">Download</span>
</Button>
</Box>
@@ -95,12 +95,13 @@
</span>
{:else}
<div class="avatar is-size-small">
<span class="icon-minus-sm" aria-hidden="true" />
<span class="icon-minus-sm" aria-hidden="true"
></span>
</div>
{/if}
{:else}
<div class="avatar is-size-small">
<span class="icon-anonymous" aria-hidden="true" />
<span class="icon-anonymous" aria-hidden="true"></span>
</div>
<span class="text u-trim">{user.name}</span>
{/if}

Some files were not shown because too many files have changed in this diff Show More