Merge branch 'feat-pink-v2' into 'devkeys-pink2'.

This commit is contained in:
Darshan
2025-03-26 11:32:34 +05:30
38 changed files with 256 additions and 412 deletions
+1 -1
View File
@@ -23,7 +23,7 @@
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5",
"@appwrite.io/pink-legacy": "^1.0.3",
"@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5",
"@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
"@stripe/stripe-js": "^3.5.0",
+12 -12
View File
@@ -21,8 +21,8 @@ importers:
specifier: ^1.0.3
version: 1.0.3
'@appwrite.io/pink-svelte':
specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5
version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
specifier: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84
version: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
@@ -215,14 +215,14 @@ packages:
resolution: {tarball: https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9562}
version: 1.2.1
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@203ff849e6d6a66529bf690af2e97cade99ef488':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@203ff849e6d6a66529bf690af2e97cade99ef488}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab516090e3ae16aef591d8de5f04e1a84fbd':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab516090e3ae16aef591d8de5f04e1a84fbd}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5}
version: 1.0.0-next.7
peerDependencies:
svelte: ^4.0.0
@@ -236,8 +236,8 @@ packages:
'@appwrite.io/pink-legacy@1.0.3':
resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==}
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5}
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84':
resolution: {tarball: https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84}
version: 1.0.0-next.85
peerDependencies:
react-dom: ^18.0.0
@@ -4243,11 +4243,11 @@ snapshots:
'@appwrite.io/console@https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@9562': {}
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5(svelte@4.2.19)':
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@203ff849e6d6a66529bf690af2e97cade99ef488(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab516090e3ae16aef591d8de5f04e1a84fbd(svelte@4.2.19)':
'@appwrite.io/pink-icons-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab5(svelte@4.2.19)':
dependencies:
svelte: 4.2.19
@@ -4260,9 +4260,9 @@ snapshots:
'@appwrite.io/pink-icons': 1.0.0
the-new-css-reset: 1.11.3
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@4a5aab5(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
'@appwrite.io/pink-svelte@https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@203ff84(react-dom@18.3.1(react@18.3.1))(svelte@4.2.19)':
dependencies:
'@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@4a5aab516090e3ae16aef591d8de5f04e1a84fbd(svelte@4.2.19)
'@appwrite.io/pink-icons-svelte': https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@203ff849e6d6a66529bf690af2e97cade99ef488(svelte@4.2.19)
'@floating-ui/dom': 1.6.13
'@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.3(svelte@4.2.19))(svelte@4.2.19)
'@melt-ui/svelte': 0.86.3(svelte@4.2.19)
@@ -69,7 +69,15 @@
});
}}>
<Layout.Stack direction="row" gap="s">
<Selector.Checkbox checked={option.checked} size="s" />
<Selector.Checkbox
checked={option.checked}
on:click={() => {
option.checked = !option.checked;
dispatch('add', {
value: option.checked
});
}}
size="s" />
{capitalize(option.label)}
</Layout.Stack>
</ActionMenu.Item.Button>
+2
View File
@@ -0,0 +1,2 @@
export { default as LogsRequest } from './logsRequest.svelte';
export { default as LogsResponse } from './logsResponse.svelte';
@@ -0,0 +1,26 @@
<script lang="ts">
import { base } from '$app/paths';
import { page } from '$app/stores';
import { Link } from '$lib/elements';
import { Alert } from '@appwrite.io/pink-svelte';
export let product: 'site' | 'function';
</script>
{#if product === 'site'}
<Alert.Inline status="info" title="Your logs are disabled">
To view logs and errors, enable them in your
<Link
href={`${base}/project-${$page.params.project}/sites/site-${$page.params.site}/settings`}>
site settings</Link
>.
</Alert.Inline>
{:else if product === 'function'}
<Alert.Inline status="info" title="Your execution logs are disabled">
To view execution logs and errors, enable them in your
<Link
href={`${base}/project-${$page.params.project}/functions/function-${$page.params.function}/settings`}>
function settings</Link
>.
</Alert.Inline>
{/if}
@@ -14,9 +14,11 @@
Typography
} from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
import LoggingAlert from './loggingAlert.svelte';
export let selectedLog: Models.Execution;
export let product: 'site' | 'function';
export let logging: boolean;
let responseTab: 'logs' | 'errors' | 'headers' | 'body' = 'logs';
onMount(() => {
@@ -37,12 +39,14 @@
on:click={() => (responseTab = 'logs')}>
Logs
</Tabs.Item.Button>
<Tabs.Item.Button
{root}
active={responseTab === 'errors'}
on:click={() => (responseTab = 'errors')}>
Errors
</Tabs.Item.Button>
{#if product !== 'site'}
<Tabs.Item.Button
{root}
active={responseTab === 'errors'}
on:click={() => (responseTab = 'errors')}>
Errors
</Tabs.Item.Button>
{/if}
<Tabs.Item.Button
{root}
active={responseTab === 'headers'}
@@ -52,18 +56,22 @@
size="s"
content={selectedLog?.responseHeaders?.length?.toString()} />
</Tabs.Item.Button>
<Tabs.Item.Button
{root}
active={responseTab === 'body'}
on:click={() => (responseTab = 'body')}>
Body
</Tabs.Item.Button>
{#if product !== 'site'}
<Tabs.Item.Button
{root}
active={responseTab === 'body'}
on:click={() => (responseTab = 'body')}>
Body
</Tabs.Item.Button>
{/if}
</Tabs.Root>
<Divider />
</Layout.Stack>
{#if responseTab === 'logs'}
{#if !logging}
<LoggingAlert {product} />
{/if}
{#if selectedLog.logs}
<Logs logs={selectedLog.logs} />
{:else}
@@ -72,6 +80,9 @@
</Card>
{/if}
{:else if responseTab === 'errors'}
{#if !logging}
<LoggingAlert {product} />
{/if}
{#if selectedLog.errors}
<Logs logs={selectedLog.errors} />
{:else}
@@ -120,8 +131,8 @@
<Logs logs={selectedLog.responseBody} />
{:else}
<Card padding="xs" radius="s">
<Typography.Text
>Body data is not captured by Appwrite for your user's security and privacy. To
<Typography.Text>
Body data is not captured by Appwrite for your user's security and privacy. To
display body data in the Logs tab, use <InlineCode
code="context.log()"
size="s" />. <Link
-1
View File
@@ -30,7 +30,6 @@ export type Column = PinkColumn & {
filter?: boolean;
array?: boolean;
format?: string;
show?: boolean;
exclude?: boolean;
elements?: string[] | { value: string | number; label: string }[];
};
+34 -41
View File
@@ -18,14 +18,12 @@ type TeamPreferences = {
};
type PreferencesStore = {
[key: string]: {
[key: string]: Preferences;
collections?: {
[key: string]: Preferences['columns'];
};
displayNames?: {
[key: string]: TeamPreferences['names'];
};
[key: string]: Preferences;
collections?: {
[key: string]: Preferences['columns'];
};
displayNames?: {
[key: string]: TeamPreferences['names'];
};
} & { hideAiDisclaimer?: boolean };
@@ -51,7 +49,7 @@ function createPreferences() {
get: (route?: Page['route']): Preferences => {
const parsedRoute = route ?? get(page).route;
return (
preferences[sdk.forProject.client.config.project]?.[parsedRoute.id] ?? {
preferences?.[parsedRoute.id] ?? {
limit: null,
view: null,
columns: null
@@ -60,60 +58,58 @@ function createPreferences() {
},
getCustomCollectionColumns: (collectionId: string): Preferences['columns'] => {
return (
preferences[sdk.forProject.client.config.project]?.collections?.[collectionId] ?? []
);
return preferences?.collections?.[collectionId] ?? [];
},
setLimit: (limit: Preferences['limit']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
if (!n?.[path]) {
n ??= {};
n[path] ??= {};
}
n[project][path].limit = limit;
n[path].limit = limit;
return n;
}),
setView: (view: Preferences['view']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
if (!n?.[path]) {
n ??= {};
n[path] ??= {};
}
n[project][path].view = view;
n[path].view = view;
return n;
}),
setColumns: (columns: Preferences['columns']) =>
update((n) => {
const path = get(page).route.id;
const project = sdk.forProject.client.config.project;
if (!n[project]?.[path]) {
n[project] ??= {};
n[project][path] ??= {};
if (!n?.[path]) {
n ??= {};
n[path] ??= {};
}
n[project][path].columns = columns;
n[path].columns = columns;
return n;
}),
setCustomCollectionColumns: (columns: Preferences['columns']) =>
update((n) => {
const current = get(page);
const project = sdk.forProject.client.config.project;
const collection = current.params.collection;
if (!n[project]?.collections?.[collection]) {
n[project] ??= {};
n[project].collections ??= {};
if (!n?.collections?.[collection]) {
n ??= {};
n.collections ??= {};
}
n[project].collections[collection] = columns;
n.collections[collection] = columns;
return n;
}),
@@ -127,22 +123,19 @@ function createPreferences() {
return teamPrefs;
},
getDisplayNames: () => {
const id = get(organization)?.$id;
if (!id) return {};
return preferences?.[id]?.displayNames ?? {};
return preferences?.displayNames ?? {};
},
setDisplayNames: async (collectionId: string, names: TeamPreferences['names']) => {
const id = get(organization).$id;
let teamPrefs: Models.Preferences;
update((n) => {
if (!n[id]?.displayNames) {
n[id] ??= {};
n[id].displayNames ??= {};
if (!n?.displayNames) {
n ??= {};
n.displayNames ??= {};
}
teamPrefs = n[id];
n[id].displayNames[collectionId] = names;
teamPrefs = n;
n.displayNames[collectionId] = names;
return n;
});
@@ -46,7 +46,7 @@
function updateMaxWidth() {
const tableCells = Array.from(document.querySelectorAll('.less-width-truncated'));
const visibleColumnsCount = $columns.filter((col) => col.show).length;
const visibleColumnsCount = $columns.filter((col) => !col.hide).length;
const newMaxWidth = Math.max(50 - (visibleColumnsCount - 1) * 5, 25);
tableCells.forEach((cell) => {
@@ -9,7 +9,7 @@
import { project } from '$routes/(console)/project-[project]/store';
import { base } from '$app/paths';
import { View } from '$lib/helpers/load';
import { Alert, Icon, Layout, Link, Tooltip } from '@appwrite.io/pink-svelte';
import { Icon, Layout, Tooltip } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
import Table from './table.svelte';
import { columns } from './store';
@@ -54,17 +54,6 @@
<ParsedTagList />
</Layout.Stack>
{#if !data.func.logging}
<div class="common-section">
<Alert.Inline status="info" title="Your execution logs are disabled">
To view execution logs and errors, enable them in your
<Link.Anchor
href={`${base}/project-${$project.$id}/functions/function-${data.func.$id}/settings`}>
Function settings</Link.Anchor
>.
</Alert.Inline>
</div>
{/if}
{#if data?.executions?.total}
<Table columns={$columns} logs={data.executions} />
@@ -19,12 +19,12 @@
import { capitalize } from '$lib/helpers/string';
import { Copy } from '$lib/components';
import { logStatusConverter } from './store';
import LogsResponse from './(components)/LogsResponse.svelte';
import LogsRequest from './(components)/LogsRequest.svelte';
import { LogsRequest, LogsResponse } from '$lib/components/logs';
export let open = false;
export let selectedLogId: string;
export let logs: Models.Execution[];
export let logging: boolean;
function nextLog() {
const currentIndex = logs.findIndex((log) => log.$id === selectedLogId);
@@ -160,7 +160,7 @@
<LogsRequest {selectedLog} />
</Accordion>
<Accordion title="Response" open hideDivider>
<LogsResponse {selectedLog} />
<LogsResponse {selectedLog} product="function" {logging} />
</Accordion>
</Layout.Stack>
{/if}
@@ -9,6 +9,7 @@
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
import { logStatusConverter } from './store';
import DualTimeView from '$lib/components/dualTimeView.svelte';
import { func } from '../store';
export let columns: Column[];
export let logs: Models.ExecutionList;
@@ -82,4 +83,4 @@
{/each}
</Table.Root>
<Sheet bind:open={openSheet} bind:selectedLogId logs={logs.executions} />
<Sheet bind:open={openSheet} bind:selectedLogId logs={logs.executions} logging={$func.logging} />
@@ -108,7 +108,7 @@
<UpdateEvents />
<UpdateSchedule />
<UpdateTimeout />
<UpdateLogging />
<UpdateLogging func={data.function} />
<UpdateScopes />
<DangerZone />
</Container>
@@ -1,60 +1,49 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form } from '$lib/elements/forms';
import InputSwitch from '$lib/elements/forms/inputSwitch.svelte';
import { Button, Form, InputSwitch } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { project } from '$routes/(console)/project-[project]/store';
import { onMount } from 'svelte';
import { func } from '../store';
import { isValueOfStringEnum } from '$lib/helpers/types';
import { Runtime } from '@appwrite.io/console';
import { base } from '$app/paths';
import { Runtime, type Models } from '@appwrite.io/console';
import { Typography } from '@appwrite.io/pink-svelte';
import { Link } from '$lib/elements';
const functionId = $page.params.function;
let functionLogging: boolean = null;
export let func: Models.Function;
let logging = func.logging;
onMount(async () => {
functionLogging ??= $func.logging;
});
async function updateLogging() {
async function update() {
try {
if (!isValueOfStringEnum(Runtime, $func.runtime)) {
throw new Error(`Invalid runtime: ${$func.runtime}`);
if (!isValueOfStringEnum(Runtime, func.runtime)) {
throw new Error(`Invalid runtime: ${func.runtime}`);
}
await sdk.forProject.functions.update(
functionId,
$func.name,
$func.runtime,
$func.execute || undefined,
$func.events || undefined,
$func.schedule || undefined,
$func.timeout || undefined,
$func.enabled || undefined,
functionLogging,
$func.entrypoint || undefined,
$func.commands || undefined,
$func.scopes || undefined,
$func.installationId || undefined,
$func.providerRepositoryId || undefined,
$func.providerBranch || undefined,
$func.providerSilentMode || undefined,
$func.providerRootDirectory || undefined
func.$id,
func.name,
func.runtime,
func.execute || undefined,
func.events || undefined,
func.schedule || undefined,
func.timeout || undefined,
func.enabled || undefined,
logging,
func.entrypoint || undefined,
func.commands || undefined,
func.scopes || undefined,
func.installationId || undefined,
func.providerRepositoryId || undefined,
func.providerBranch || undefined,
func.providerSilentMode || undefined,
func.providerRootDirectory || undefined
);
await invalidate(Dependencies.FUNCTION);
addNotification({
type: 'success',
message:
$func.name +
func.name +
' execution logs settings have been ' +
(functionLogging ? 'enabled' : 'disabled')
(logging ? 'enabled' : 'disabled')
});
trackEvent(Submit.FunctionUpdateLogging);
} catch (error) {
@@ -67,20 +56,18 @@
}
</script>
<Form onSubmit={updateLogging}>
<Form onSubmit={update}>
<CardGrid>
<svelte:fragment slot="title">Execution logs</svelte:fragment>
<svelte:fragment slot="aside">
<InputSwitch label="Logs" id="logging" bind:value={functionLogging} />
<InputSwitch label="Logs" id="logging" bind:value={logging} />
<Typography.Text>
When disabled, execution logs and errors will not be shown in the <Link
href={`${base}/project-${$project.$id}/functions/function-${$func.$id}/executions`}>
Executions</Link> tab. We recommend disabling them for better performance in production.
When disabled, executions will exclude logs and errors, and will be slightly faster.
</Typography.Text>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={$func.logging === functionLogging} submit>Update</Button>
<Button disabled={func.logging === logging} submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
@@ -96,7 +96,11 @@
<Table.Root
let:root
columns={[{ id: 'repo' }, { id: 'updated' }, { id: 'actions', width: 20 }]}>
columns={[
{ id: 'repo', width: { min: 150, max: 500 } },
{ id: 'updated', width: { min: 150, max: 500 } },
{ id: 'actions', width: 60 }
]}>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell column="repo" {root}>Repository</Table.Header.Cell>
<Table.Header.Cell column="updated" {root}>Updated</Table.Header.Cell>
@@ -62,6 +62,7 @@
site.name,
site.framework as Framework,
site.enabled,
site.logging || undefined,
site.timeout,
site.installCommand,
site.buildCommand,
@@ -22,7 +22,6 @@
import { Badge, Layout, Logs, Typography } from '@appwrite.io/pink-svelte';
import LogsTimer from './logsTimer.svelte';
export let site: Models.Site;
export let deployment: Models.Deployment;
export let hideTitle = false;
export let hideScrollButtons = false;
@@ -59,7 +59,6 @@
<Fieldset legend="Deploy">
<Logs
bind:deployment={data.deployment}
bind:site={data.site}
hideScrollButtons
height="calc(100dvh - 430px)"
emptyCopy="No logs available yet..." />
@@ -55,6 +55,7 @@
buildRuntime,
undefined,
undefined,
undefined,
installCommand || undefined,
buildCommand || undefined,
outputDirectory || undefined,
@@ -99,6 +99,7 @@
buildRuntime,
undefined,
undefined,
undefined,
installCommand,
buildCommand,
outputDirectory,
@@ -118,6 +118,7 @@
buildRuntime,
undefined,
undefined,
undefined,
framework.installCommand,
framework.buildCommand,
framework.outputDirectory,
@@ -79,6 +79,7 @@
site.name,
site.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -74,12 +74,7 @@
open
badgeType={badgeTypeDeployment(data.deployment.status)}
hideDivider>
<Logs
site={data.site}
deployment={data.deployment}
hideTitle
hideScrollButtons
fullHeight />
<Logs deployment={data.deployment} hideTitle hideScrollButtons fullHeight />
<svelte:fragment slot="end">
<LogsTimer status={data.deployment.status} deployment={data.deployment} />
</svelte:fragment>
@@ -15,27 +15,28 @@
import { writable } from 'svelte/store';
export let data;
const ruleId = $page.url.searchParams.get('rule');
let selectedTab: 'cname' | 'nameserver';
let domainData = data.domain;
let verified = false;
let routeBase = `${base}/project-${$page.params.project}/sites/site-${$page.params.site}/domains`;
let isSubmitting = writable(false);
async function addDomain() {
async function verify() {
const isNewDomain =
data.domainsList.domains.findIndex((rule) => rule.domain === $page.params.domain) ===
-1;
try {
// if (selectedTab === 'cname'){
// domainData = await sdk.forProject.proxy.updateRuleVerification(
// $page.params.domain
// );
// }
if (isNewDomain && isCloud) {
domainData = await sdk.forConsole.domains.create(
if (selectedTab === 'cname') {
const ruleData = await sdk.forProject.proxy.updateRuleVerification(ruleId);
verified = ruleData.status === 'verified';
} else if (isNewDomain && isCloud) {
const domainData = await sdk.forConsole.domains.create(
$organization.$id,
$page.params.domain
);
verified = domainData.nameservers.toLocaleLowerCase() === 'appwrite';
}
addNotification({
@@ -46,8 +47,7 @@
await invalidate(Dependencies.DOMAINS);
await invalidate(Dependencies.SITES_DOMAINS);
} catch (error) {
await invalidate(Dependencies.DOMAINS);
verified = false;
addNotification({
type: 'error',
message: error.message
@@ -56,20 +56,15 @@
}
async function back() {
if ($page.url.searchParams.has('rule')) {
const rule = $page.url.searchParams.get('rule');
await sdk.forProject.proxy.deleteRule(rule);
if (ruleId) {
await sdk.forProject.proxy.deleteRule(ruleId);
}
await goto(`${routeBase}/add-domain?domain=${$page.params.domain}`);
}
$: isVerified = domainData?.nameservers
? domainData?.nameservers.toLocaleLowerCase() === 'appwrite'
: undefined;
</script>
<Wizard title="Add domain" href={routeBase} column columnSize="s">
<Form onSubmit={addDomain} bind:isSubmitting>
<Form onSubmit={verify} bind:isSubmitting>
<Layout.Stack gap="xxl">
<Card.Base radius="s" padding="s">
<Layout.Stack
@@ -88,10 +83,7 @@
</Layout.Stack>
</Card.Base>
<VerificationFieldset
domain={$page.params.domain}
verified={isVerified}
bind:selectedTab>
<VerificationFieldset domain={$page.params.domain} {verified} bind:selectedTab>
<Divider />
<Layout.Stack direction="row" justifyContent="flex-end">
<div>
@@ -38,7 +38,7 @@
{#if selectedTab === 'cname' && isSubDomain}
<CnameTable {domain} {verified} />
{:else if isCloud}
<NameserverTable {domain} />
<NameserverTable {domain} {verified} />
{/if}
<slot />
</Layout.Stack>
@@ -1,124 +0,0 @@
<script lang="ts">
import { Card } from '$lib/components';
import { Link } from '$lib/elements';
import type { Models } from '@appwrite.io/console';
import {
Badge,
Divider,
Input,
Layout,
Table,
Tabs,
Typography
} from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
export let selectedLog: Models.Execution;
let requestTab: 'parameters' | 'headers' = 'parameters';
let parameters = [];
onMount(() => {
try {
// Add dummy base URL to parse relative paths
const url = new URL(selectedLog.requestPath, 'http://dummy.local');
if (url.search) {
parameters = Array.from(url.searchParams.entries()).map(([name, value]) => ({
name,
value: decodeURIComponent(value)
}));
}
} catch (error) {
parameters = [];
}
});
onMount(() => {
if (parameters?.length) {
requestTab = 'parameters';
} else if (selectedLog.requestHeaders?.length) {
requestTab = 'headers';
}
});
</script>
<Layout.Stack>
<Layout.Stack gap="none">
<Tabs.Root variant="secondary" let:root>
<Tabs.Item.Button
{root}
active={requestTab === 'parameters'}
on:click={() => (requestTab = 'parameters')}>
Parameters
<Badge variant="secondary" size="s" content={parameters?.length?.toString()} />
</Tabs.Item.Button>
<Tabs.Item.Button
{root}
active={requestTab === 'headers'}
on:click={() => (requestTab = 'headers')}>
Headers <Badge
variant="secondary"
size="s"
content={selectedLog?.requestHeaders?.length?.toString()} />
</Tabs.Item.Button>
</Tabs.Root>
<Divider />
</Layout.Stack>
{#if requestTab === 'parameters'}
{#if parameters?.length}
<Table.Root columns={2} let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Key</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each parameters as parameter}
<Table.Row.Base {root}>
<Table.Cell {root}>{parameter.name}</Table.Cell>
<Table.Cell {root}>{parameter.value}</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No parameters found.</Typography.Code>
</Card>
{/if}
{:else if requestTab === 'headers'}
{#if selectedLog.requestHeaders?.length}
<Table.Root
columns={[
{
id: 'key',
width: 200
},
{
id: 'value'
}
]}
let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Key</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each selectedLog.requestHeaders as request}
<Table.Row.Base {root}>
<Table.Cell {root}>{request.name}</Table.Cell>
<Table.Cell {root}>{request.value}</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
<Input.Helper state="default">
<span>
Missing headers? Check the <Link variant="muted" href="#" external>docs</Link> to
see the supported data and how to log it.
</span>
</Input.Helper>
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No headers found.</Typography.Code>
</Card>
{/if}
{/if}
</Layout.Stack>
@@ -1,119 +0,0 @@
<script lang="ts">
import { Card } from '$lib/components';
import { Link } from '$lib/elements';
import type { Models } from '@appwrite.io/console';
import {
Badge,
Divider,
Input,
Layout,
Logs,
Table,
Tabs,
Typography
} from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
export let selectedLog: Models.Execution;
let responseTab: 'logs' | 'errors' | 'headers' | 'body' = 'logs';
onMount(() => {
if (selectedLog?.logs) {
responseTab = 'logs';
} else if (selectedLog.requestHeaders?.length) {
responseTab = 'headers';
}
});
</script>
<Layout.Stack>
<Layout.Stack gap="none">
<Tabs.Root variant="secondary" let:root>
<Tabs.Item.Button
{root}
active={responseTab === 'logs'}
on:click={() => (responseTab = 'logs')}>
Logs
</Tabs.Item.Button>
<!-- <Tabs.Item.Button
{root}
active={responseTab === 'errors'}
on:click={() => (responseTab = 'errors')}>
Errors
</Tabs.Item.Button> -->
<Tabs.Item.Button
{root}
active={responseTab === 'headers'}
on:click={() => (responseTab = 'headers')}>
Headers <Badge
variant="secondary"
size="s"
content={selectedLog?.responseHeaders?.length?.toString()} />
</Tabs.Item.Button>
</Tabs.Root>
<Divider />
</Layout.Stack>
{#if responseTab === 'logs'}
{#if selectedLog.logs}
<Logs logs={selectedLog.logs} />
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No logs found.</Typography.Code>
</Card>
{/if}
{:else if responseTab === 'errors'}
{#if selectedLog.errors}
<Logs logs={selectedLog.errors} />
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No errors found.</Typography.Code>
</Card>
{/if}
{:else if responseTab === 'headers'}
{#if selectedLog.responseHeaders?.length}
<Table.Root
columns={[
{
id: 'key',
width: 200
},
{
id: 'value'
}
]}
let:root>
<svelte:fragment slot="header" let:root>
<Table.Header.Cell {root}>Key</Table.Header.Cell>
<Table.Header.Cell {root}>Value</Table.Header.Cell>
</svelte:fragment>
{#each selectedLog.responseHeaders as request}
<Table.Row.Base {root}>
<Table.Cell {root}>{request.name}</Table.Cell>
<Table.Cell {root}>{request.value}</Table.Cell>
</Table.Row.Base>
{/each}
</Table.Root>
<Input.Helper state="default">
<span>
Missing headers? Check the <Link variant="muted" href="#" external>docs</Link> to
see the supported data and how to log it.
</span>
</Input.Helper>
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No headers found.</Typography.Code>
</Card>
{/if}
{:else if responseTab === 'body'}
{#if selectedLog.responseBody}
<Logs logs={selectedLog.responseBody} />
{:else}
<Card padding="xs" radius="s">
<Typography.Code>No parameters found.</Typography.Code>
</Card>
{/if}
{/if}
</Layout.Stack>
@@ -14,10 +14,10 @@
Typography
} from '@appwrite.io/pink-svelte';
import { timeFromNow } from '$lib/helpers/date';
import LogsRequest from './(components)/LogsRequest.svelte';
import LogsResponse from './(components)/LogsResponse.svelte';
import { capitalize } from '$lib/helpers/string';
import { Copy } from '$lib/components';
import { LogsRequest, LogsResponse } from '$lib/components/logs';
import { site } from '../store';
export let open = false;
export let selectedLogId: string;
@@ -127,7 +127,7 @@
<LogsRequest {selectedLog} />
</Accordion>
<Accordion title="Response" open hideDivider>
<LogsResponse {selectedLog} />
<LogsResponse {selectedLog} logging={$site?.logging} product="site" />
</Accordion>
</Layout.Stack>
{/if}
@@ -15,6 +15,7 @@
import { isCloud } from '$lib/system';
import UpdateResourceLimits from './updateResourceLimits.svelte';
import UpdateVariables from '$routes/(console)/project-[project]/updateVariables.svelte';
import UpdateLogging from './updateLogging.svelte';
export let data;
@@ -74,5 +75,6 @@
<UpdateResourceLimits site={data.site} specs={data.specificationsList} />
{/if}
<UpdateTimeout site={data.site} />
<UpdateLogging site={data.site} />
<DangerZone site={data.site} />
</Container>
@@ -22,6 +22,7 @@
site.name,
site.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -40,6 +40,7 @@
site.name,
selectedFramework.key as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
installCommand || undefined,
buildCommand || undefined,
@@ -0,0 +1,68 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { CardGrid } from '$lib/components';
import { Dependencies } from '$lib/constants';
import { Button, Form, InputSwitch } from '$lib/elements/forms';
import { addNotification } from '$lib/stores/notifications';
import { sdk } from '$lib/stores/sdk';
import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console';
import { Typography } from '@appwrite.io/pink-svelte';
export let site: Models.Site;
let logging = site?.logging;
async function update() {
try {
await sdk.forProject.sites.update(
site.$id,
site.name,
site.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
site.outputDirectory || undefined,
(site?.buildRuntime as BuildRuntime) || undefined,
site.adapter as Adapter,
site.fallbackFile || undefined,
site.installationId || undefined,
site.providerRepositoryId || undefined,
site.providerBranch || undefined,
site.providerSilentMode || undefined,
site.providerRootDirectory || undefined
);
await invalidate(Dependencies.SITE);
addNotification({
type: 'success',
message:
site.name + ' logs settings have been ' + (logging ? 'enabled' : 'disabled')
});
trackEvent(Submit.SiteUpdateLogging);
} catch (error) {
addNotification({
type: 'error',
message: error.message
});
trackError(error, Submit.SiteUpdateLogging);
}
}
</script>
<Form onSubmit={update}>
<CardGrid>
<svelte:fragment slot="title">Execution logs</svelte:fragment>
<svelte:fragment slot="aside">
<InputSwitch label="Logs" id="logging" bind:value={logging} />
<Typography.Text>
When disabled, request logs will exclude logs and errors, and site responses will be
slightly faster.
</Typography.Text>
</svelte:fragment>
<svelte:fragment slot="actions">
<Button disabled={site?.logging === logging} submit>Update</Button>
</svelte:fragment>
</CardGrid>
</Form>
@@ -23,6 +23,7 @@
siteName,
site.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -70,6 +70,7 @@
site.name,
site?.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -24,6 +24,7 @@
site.name,
site.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -29,6 +29,7 @@
site.name,
site?.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
site.timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,
@@ -22,6 +22,7 @@
site.name,
site?.framework as Framework,
site.enabled || undefined,
site.logging || undefined,
timeout || undefined,
site.installCommand || undefined,
site.buildCommand || undefined,