mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
Merge branch 'main' of github.com:appwrite/console into feat-org-creation-refactor
This commit is contained in:
@@ -41,6 +41,7 @@ jobs:
|
||||
"PUBLIC_CONSOLE_MODE=cloud"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
"PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY }}"
|
||||
"SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}"
|
||||
publish-cloud-stage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -150,3 +150,6 @@ dist
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
# Sentry Config File
|
||||
.sentryclirc
|
||||
|
||||
@@ -22,11 +22,14 @@ ARG PUBLIC_CONSOLE_MODE
|
||||
ARG PUBLIC_APPWRITE_ENDPOINT
|
||||
ARG PUBLIC_GROWTH_ENDPOINT
|
||||
ARG PUBLIC_STRIPE_KEY
|
||||
ARG SENTRY_AUTH_TOKEN
|
||||
|
||||
ENV PUBLIC_APPWRITE_ENDPOINT=$PUBLIC_APPWRITE_ENDPOINT
|
||||
ENV PUBLIC_GROWTH_ENDPOINT=$PUBLIC_GROWTH_ENDPOINT
|
||||
ENV PUBLIC_CONSOLE_MODE=$PUBLIC_CONSOLE_MODE
|
||||
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
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ services:
|
||||
PUBLIC_APPWRITE_ENDPOINT: ${PUBLIC_APPWRITE_ENDPOINT}
|
||||
PUBLIC_GROWTH_ENDPOINT: ${PUBLIC_GROWTH_ENDPOINT}
|
||||
PUBLIC_STRIPE_KEY: ${PUBLIC_STRIPE_KEY}
|
||||
SENTRY_AUTH_TOKEN: ${SENTRY_AUTH_TOKEN}
|
||||
develop:
|
||||
watch:
|
||||
- action: rebuild
|
||||
|
||||
+2
-1
@@ -19,10 +19,11 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.0.0",
|
||||
"@appwrite.io/console": "1.0.1",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/sveltekit": "^8.26.0",
|
||||
"@stripe/stripe-js": "^3.5.0",
|
||||
"ai": "^2.2.37",
|
||||
"analytics": "^0.8.14",
|
||||
|
||||
Generated
+1056
-5
File diff suppressed because it is too large
Load Diff
+23
-10
@@ -1,14 +1,27 @@
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import { AppwriteException } from '@appwrite.io/console';
|
||||
import type { HandleClientError } from '@sveltejs/kit';
|
||||
import { isCloud, isProd } from '$lib/system';
|
||||
|
||||
export const handleError: HandleClientError = async ({ error, message, status }) => {
|
||||
if (error instanceof AppwriteException) {
|
||||
status = error.code === 0 ? undefined : error.code;
|
||||
message = error.message;
|
||||
Sentry.init({
|
||||
enabled: isCloud && isProd,
|
||||
dsn: 'https://c7ce178bdedd486480317b72f282fd39@o1063647.ingest.us.sentry.io/4504158071422976',
|
||||
tracesSampleRate: 1,
|
||||
replaysSessionSampleRate: 0,
|
||||
replaysOnErrorSampleRate: 1,
|
||||
integrations: [Sentry.replayIntegration()]
|
||||
});
|
||||
|
||||
export const handleError: HandleClientError = Sentry.handleErrorWithSentry(
|
||||
async ({ error, message, status }) => {
|
||||
if (error instanceof AppwriteException) {
|
||||
status = error.code === 0 ? undefined : error.code;
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
return {
|
||||
message,
|
||||
status
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
message,
|
||||
status
|
||||
};
|
||||
};
|
||||
);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { sequence } from '@sveltejs/kit/hooks';
|
||||
import { handleErrorWithSentry, sentryHandle } from '@sentry/sveltekit';
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import { isCloud, isProd } from '$lib/system';
|
||||
|
||||
Sentry.init({
|
||||
enabled: isCloud && isProd,
|
||||
dsn: 'https://c7ce178bdedd486480317b72f282fd39@o1063647.ingest.us.sentry.io/4504158071422976',
|
||||
tracesSampleRate: 1.0
|
||||
});
|
||||
|
||||
export const handle = sequence(sentryHandle());
|
||||
|
||||
export const handleError = handleErrorWithSentry();
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { BillingPlan } from '$lib/constants';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing';
|
||||
import { plansInfo, tierFree, tierPro, type Tier } from '$lib/stores/billing';
|
||||
import { Card, SecondaryTabs, SecondaryTabsItem } from '..';
|
||||
|
||||
let selectedTab: Tier = BillingPlan.FREE;
|
||||
@@ -23,11 +23,11 @@
|
||||
on:click={() => (selectedTab = BillingPlan.PRO)}>
|
||||
{tierPro.name}
|
||||
</SecondaryTabsItem>
|
||||
<SecondaryTabsItem
|
||||
<!-- <SecondaryTabsItem
|
||||
disabled={selectedTab === BillingPlan.SCALE}
|
||||
on:click={() => (selectedTab = BillingPlan.SCALE)}>
|
||||
{tierScale.name}
|
||||
</SecondaryTabsItem>
|
||||
</SecondaryTabsItem> -->
|
||||
</SecondaryTabs>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -45,7 +45,11 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="table-with-scroll {classes}" class:u-margin-block-start-16={!noMargin} data-private>
|
||||
<div
|
||||
class="table-with-scroll {classes}"
|
||||
style:border-radius={noStyles ? '0' : ''}
|
||||
class:u-margin-block-start-16={!noMargin}
|
||||
data-private>
|
||||
<div class="table-wrapper" use:hasOverflow={(v) => (isOverflowing = v)}>
|
||||
<table
|
||||
class="table"
|
||||
|
||||
@@ -79,7 +79,7 @@ const createUploader = () => {
|
||||
(p) => {
|
||||
newFile.$id = p.$id;
|
||||
newFile.progress = p.progress;
|
||||
newFile.completed = p.progress === 100 ? true : false;
|
||||
newFile.completed = p.progress === 100;
|
||||
updateFile(p.$id, newFile);
|
||||
}
|
||||
);
|
||||
@@ -91,6 +91,7 @@ const createUploader = () => {
|
||||
removeFromQueue: (id: string) => {
|
||||
update((n) => {
|
||||
n.files = n.files.filter((f) => f.$id !== id);
|
||||
n.isOpen = n.files.length !== 0;
|
||||
return n;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -23,5 +23,7 @@ export const ENV = {
|
||||
export const MODE = VARS.CONSOLE_MODE === Mode.CLOUD ? Mode.CLOUD : Mode.SELF_HOSTED;
|
||||
export const isCloud = MODE === Mode.CLOUD;
|
||||
export const isSelfHosted = MODE !== Mode.CLOUD;
|
||||
export const isDev = ENV.DEV;
|
||||
export const isProd = ENV.PROD;
|
||||
export const hasStripePublicKey = !!VARS.PUBLIC_STRIPE_KEY;
|
||||
export const GRACE_PERIOD_OVERRIDE = false;
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
{
|
||||
value: BillingPlan.PRO,
|
||||
label: `${tierToPlan(BillingPlan.PRO).name} - ${formatCurrency($plansInfo.get(BillingPlan.PRO).price)}/month + add-ons`
|
||||
},
|
||||
{
|
||||
value: BillingPlan.SCALE,
|
||||
label: `${tierToPlan(BillingPlan.SCALE).name} - ${formatCurrency($plansInfo.get(BillingPlan.SCALE).price)}/month + usage`
|
||||
}
|
||||
// {
|
||||
// value: BillingPlan.SCALE,
|
||||
// label: `${tierToPlan(BillingPlan.SCALE).name} - ${formatCurrency($plansInfo.get(BillingPlan.SCALE).price)}/month + usage`
|
||||
// }
|
||||
]
|
||||
: [];
|
||||
|
||||
|
||||
@@ -149,9 +149,9 @@
|
||||
type: 'success',
|
||||
isHtml: true,
|
||||
message: `
|
||||
<b>${$organization.name}</b> has been changed to ${
|
||||
tierToPlan(billingPlan).name
|
||||
} plan.`
|
||||
<b>${$organization.name}</b> will change to ${
|
||||
tierToPlan(billingPlan).name
|
||||
} plan at the end of the current billing cycle.`
|
||||
});
|
||||
|
||||
trackEvent(Submit.OrganizationDowngrade, {
|
||||
@@ -162,7 +162,7 @@
|
||||
type: 'error',
|
||||
message: e.message
|
||||
});
|
||||
trackError(e, isUpgrade ? Submit.OrganizationUpgrade : Submit.OrganizationDowngrade);
|
||||
trackError(e, Submit.OrganizationDowngrade);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,22 +213,12 @@
|
||||
await invalidate(Dependencies.ORGANIZATION);
|
||||
|
||||
await goto(`${base}/organization-${org.$id}`);
|
||||
if (isUpgrade) {
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: 'Your organization has been upgraded'
|
||||
});
|
||||
} else {
|
||||
addNotification({
|
||||
type: 'success',
|
||||
isHtml: true,
|
||||
message: `
|
||||
<b>${$organization.name}</b> will change to ${
|
||||
tierToPlan(billingPlan).name
|
||||
} plan at the end of the current billing cycle.`
|
||||
});
|
||||
}
|
||||
trackEvent(isUpgrade ? Submit.OrganizationUpgrade : Submit.OrganizationDowngrade, {
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: 'Your organization has been upgraded'
|
||||
});
|
||||
|
||||
trackEvent(Submit.OrganizationUpgrade, {
|
||||
plan: tierToPlan(billingPlan)?.name
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -236,7 +226,7 @@
|
||||
type: 'error',
|
||||
message: e.message
|
||||
});
|
||||
trackError(e, isUpgrade ? Submit.OrganizationUpgrade : Submit.OrganizationDowngrade);
|
||||
trackError(e, Submit.OrganizationUpgrade);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +314,7 @@
|
||||
bind:value={feedbackDowngradeReason} />
|
||||
<InputTextarea
|
||||
id="comment"
|
||||
required
|
||||
label="If you need to elaborate, please do so here"
|
||||
placeholder="Enter feedback"
|
||||
bind:value={feedbackMessage} />
|
||||
|
||||
+88
-83
@@ -44,30 +44,11 @@
|
||||
$: hasValidAttributes = $collection?.attributes?.some((attr) => attr.status === 'available');
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div class="heading-grid u-main-justify-between u-cross-center">
|
||||
<Heading tag="h2" size="5">Documents</Heading>
|
||||
<div class="u-flex u-main-end is-only-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Filters query={data.query} {columns} disabled={!(hasAttributes && hasValidAttributes)} />
|
||||
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<ViewSelector
|
||||
view={data.view}
|
||||
{columns}
|
||||
isCustomCollection
|
||||
hideView
|
||||
allowNoColumns
|
||||
showColsTextMobile />
|
||||
<div class="is-not-mobile">
|
||||
{#key $page.params.collection}
|
||||
<Container>
|
||||
<div class="heading-grid u-main-justify-between u-cross-center">
|
||||
<Heading tag="h2" size="5">Documents</Heading>
|
||||
<div class="u-flex u-main-end is-only-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
@@ -76,76 +57,100 @@
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Filters
|
||||
query={data.query}
|
||||
{columns}
|
||||
disabled={!(hasAttributes && hasValidAttributes)} />
|
||||
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<ViewSelector
|
||||
view={data.view}
|
||||
{columns}
|
||||
isCustomCollection
|
||||
hideView
|
||||
allowNoColumns
|
||||
showColsTextMobile />
|
||||
<div class="is-not-mobile">
|
||||
<Button
|
||||
disabled={!(hasAttributes && hasValidAttributes)}
|
||||
on:click={openWizard}
|
||||
event="create_document">
|
||||
<span class="icon-plus" aria-hidden="true" />
|
||||
<span class="text">Create document</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if hasAttributes && hasValidAttributes}
|
||||
{#if data.documents.total}
|
||||
<Table {data} />
|
||||
{#if hasAttributes && hasValidAttributes}
|
||||
{#if data.documents.total}
|
||||
<Table {data} />
|
||||
|
||||
<PaginationWithLimit
|
||||
name="Documents"
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
total={data.documents.total} />
|
||||
{:else if $hasPageQueries}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<b class="body-text-2 u-bold">Sorry, we couldn't find any documents.</b>
|
||||
<p>There are no documents that match your filters.</p>
|
||||
<PaginationWithLimit
|
||||
name="Documents"
|
||||
limit={data.limit}
|
||||
offset={data.offset}
|
||||
total={data.documents.total} />
|
||||
{:else if $hasPageQueries}
|
||||
<EmptySearch hidePages>
|
||||
<div class="common-section">
|
||||
<div class="u-text-center common-section">
|
||||
<b class="body-text-2 u-bold">Sorry, we couldn't find any documents.</b>
|
||||
<p>There are no documents that match your filters.</p>
|
||||
</div>
|
||||
<div class="u-flex common-section u-main-center">
|
||||
<Button
|
||||
secondary
|
||||
on:click={() => {
|
||||
queries.clearAll();
|
||||
queries.apply();
|
||||
}}>
|
||||
Clear filters
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="u-flex common-section u-main-center">
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty
|
||||
single
|
||||
href="https://appwrite.io/docs/products/databases/documents"
|
||||
target="document"
|
||||
on:click={openWizard} />
|
||||
{/if}
|
||||
{:else}
|
||||
<Empty single target="attribute" on:click={() => (showCreateDropdown = true)}>
|
||||
<div class="u-text-center">
|
||||
<Heading size="7" tag="h2">Create an attribute to get started.</Heading>
|
||||
<p class="body-text-2 u-bold u-margin-block-start-4">
|
||||
Need a hand? Learn more in our documentation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 u-main-center">
|
||||
<Button
|
||||
external
|
||||
href="https://appwrite.io/docs/products/databases/collections#attributes"
|
||||
text
|
||||
event="empty_documentation"
|
||||
ariaLabel={`create {target}`}>Documentation</Button>
|
||||
<CreateAttributeDropdown
|
||||
bind:showCreateDropdown
|
||||
bind:showCreate={showCreateAttribute}
|
||||
bind:selectedOption={selectedAttribute}>
|
||||
<Button
|
||||
secondary
|
||||
event="create_attribute"
|
||||
on:click={() => {
|
||||
queries.clearAll();
|
||||
queries.apply();
|
||||
showCreateDropdown = !showCreateDropdown;
|
||||
}}>
|
||||
Clear filters
|
||||
Create attribute
|
||||
</Button>
|
||||
</div>
|
||||
</CreateAttributeDropdown>
|
||||
</div>
|
||||
</EmptySearch>
|
||||
{:else}
|
||||
<Empty
|
||||
single
|
||||
href="https://appwrite.io/docs/products/databases/documents"
|
||||
target="document"
|
||||
on:click={openWizard} />
|
||||
</Empty>
|
||||
{/if}
|
||||
{:else}
|
||||
<Empty single target="attribute" on:click={() => (showCreateDropdown = true)}>
|
||||
<div class="u-text-center">
|
||||
<Heading size="7" tag="h2">Create an attribute to get started.</Heading>
|
||||
<p class="body-text-2 u-bold u-margin-block-start-4">
|
||||
Need a hand? Learn more in our documentation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="u-flex u-gap-16 u-main-center">
|
||||
<Button
|
||||
external
|
||||
href="https://appwrite.io/docs/products/databases/collections#attributes"
|
||||
text
|
||||
event="empty_documentation"
|
||||
ariaLabel={`create {target}`}>Documentation</Button>
|
||||
<CreateAttributeDropdown
|
||||
bind:showCreateDropdown
|
||||
bind:showCreate={showCreateAttribute}
|
||||
bind:selectedOption={selectedAttribute}>
|
||||
<Button
|
||||
secondary
|
||||
event="create_attribute"
|
||||
on:click={() => {
|
||||
showCreateDropdown = !showCreateDropdown;
|
||||
}}>
|
||||
Create attribute
|
||||
</Button>
|
||||
</CreateAttributeDropdown>
|
||||
</div>
|
||||
</Empty>
|
||||
{/if}
|
||||
</Container>
|
||||
</Container>
|
||||
{/key}
|
||||
|
||||
<CreateAttribute bind:showCreate={showCreateAttribute} bind:selectedOption={selectedAttribute} />
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
},
|
||||
{
|
||||
id: 'size',
|
||||
title: 'Deployment size',
|
||||
title: 'Size',
|
||||
type: 'integer',
|
||||
show: true,
|
||||
width: 140,
|
||||
|
||||
+8
-5
@@ -8,14 +8,17 @@
|
||||
</script>
|
||||
|
||||
<div class="u-flex u-gap-4 u-cross-center">
|
||||
<Trim alternativeTrim>
|
||||
<a href={`http://${domain.rules[0].domain}`} target="_blank">
|
||||
<a
|
||||
href={`http://${domain.rules[0].domain}`}
|
||||
target="_blank"
|
||||
class="u-flex u-gap-4 u-cross-center">
|
||||
<Trim alternativeTrim>
|
||||
<span class="link">
|
||||
{domain.rules[0].domain}
|
||||
</span>
|
||||
</a>
|
||||
</Trim>
|
||||
<span class="icon-external-link" aria-hidden="true" />
|
||||
</Trim>
|
||||
<span class="icon-external-link" aria-hidden="true" />
|
||||
</a>
|
||||
{#if domain.rules.length > 1}
|
||||
<DropList bind:show={showDropdown} scrollable>
|
||||
<Pill button on:click={() => (showDropdown = !showDropdown)}>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { getLimit, getPage, getSearch, pageToOffset } from '$lib/helpers/load';
|
||||
import { Dependencies, PAGE_LIMIT } from '$lib/constants';
|
||||
import type { PageLoad } from './$types';
|
||||
import { isCloud } from '$lib/system';
|
||||
import type { OrganizationUsage } from '$lib/sdk/billing';
|
||||
|
||||
export const load: PageLoad = async ({ params, depends, url, route, parent }) => {
|
||||
const { organization } = await parent();
|
||||
@@ -13,20 +12,20 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) =>
|
||||
const search = getSearch(url);
|
||||
const limit = getLimit(url, route, PAGE_LIMIT);
|
||||
const offset = pageToOffset(page, limit);
|
||||
let organizationUsage: OrganizationUsage = null;
|
||||
if (isCloud && organization?.$id) {
|
||||
organizationUsage = await sdk.forConsole.billing.listUsage(organization.$id);
|
||||
}
|
||||
|
||||
return {
|
||||
offset,
|
||||
limit,
|
||||
search,
|
||||
files: await sdk.forProject.storage.listFiles(
|
||||
const [files, organizationUsage] = await Promise.all([
|
||||
sdk.forProject.storage.listFiles(
|
||||
params.bucket,
|
||||
[Query.limit(limit), Query.offset(offset), Query.orderDesc('')],
|
||||
search
|
||||
),
|
||||
isCloud && organization?.$id ? sdk.forConsole.billing.listUsage(organization.$id) : null
|
||||
]);
|
||||
return {
|
||||
offset,
|
||||
limit,
|
||||
search,
|
||||
files,
|
||||
organizationUsage
|
||||
};
|
||||
};
|
||||
|
||||
+9
-3
@@ -28,17 +28,18 @@
|
||||
});
|
||||
|
||||
async function create() {
|
||||
const fileId = $createFile.id ?? ID.unique();
|
||||
|
||||
try {
|
||||
uploader.uploadFile(
|
||||
const uploadPromise = uploader.uploadFile(
|
||||
bucketId,
|
||||
$createFile.id ?? ID.unique(),
|
||||
fileId,
|
||||
$createFile.files[0],
|
||||
$createFile.permissions
|
||||
);
|
||||
|
||||
createFile.reset();
|
||||
wizard.hide();
|
||||
invalidate(Dependencies.FILES);
|
||||
|
||||
addNotification({
|
||||
type: 'success',
|
||||
@@ -47,7 +48,12 @@
|
||||
trackEvent(Submit.FileCreate, {
|
||||
customId: !!$createFile.id
|
||||
});
|
||||
|
||||
await uploadPromise;
|
||||
invalidate(Dependencies.FILES);
|
||||
} catch (e) {
|
||||
uploader.removeFromQueue(fileId);
|
||||
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: e.message
|
||||
|
||||
+11
-3
@@ -1,16 +1,24 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { sentrySvelteKit } from '@sentry/sveltekit';
|
||||
|
||||
const config = defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
plugins: [
|
||||
sentrySvelteKit({
|
||||
adapter: 'auto',
|
||||
sourceMapsUploadOptions: {
|
||||
org: 'appwrite',
|
||||
project: 'console'
|
||||
}
|
||||
}),
|
||||
sveltekit()
|
||||
],
|
||||
optimizeDeps: {
|
||||
include: ['echarts', 'prismjs']
|
||||
},
|
||||
ssr: {
|
||||
noExternal: [
|
||||
'@analytics/google-analytics',
|
||||
'@sentry/browser',
|
||||
'@sentry-internal/tracing',
|
||||
'analytics',
|
||||
'dayjs',
|
||||
'echarts',
|
||||
|
||||
Reference in New Issue
Block a user