mirror of
https://github.com/appwrite/console.git
synced 2026-04-07 19:17:46 +00:00
Merge branch 'main' into notification-modals.
This commit is contained in:
+3
-1
@@ -153,4 +153,6 @@ dist
|
||||
|
||||
# Sentry Config File
|
||||
.sentryclirc
|
||||
.idea
|
||||
|
||||
# IDE specifics
|
||||
.idea
|
||||
Generated
+5
-4
@@ -6,7 +6,7 @@
|
||||
"": {
|
||||
"name": "@appwrite/console",
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.1.0",
|
||||
"@appwrite.io/console": "^1.2.0",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
@@ -149,9 +149,10 @@
|
||||
"integrity": "sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg=="
|
||||
},
|
||||
"node_modules/@appwrite.io/console": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-1.1.0.tgz",
|
||||
"integrity": "sha512-jWg+NW9RJxh2pnE/14xwpXBcChiSLYBnG3Jkr5RnMJ1mH7BYmbAuLTyxFn3UFy5llB7jVq8pHNYGqA93ZoEMsQ=="
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-1.2.0.tgz",
|
||||
"integrity": "sha512-VglATKgjuhr9jYihz500VbqghOY/695aDwhXtx3beLMzvjjFK+eN+5BOgcNMTj01COl3kBu4wrvbXpDmVemStA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@appwrite.io/pink": {
|
||||
"version": "0.25.0",
|
||||
|
||||
+16
-21
@@ -19,16 +19,16 @@
|
||||
"e2e:ui": "playwright test tests/e2e --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@appwrite.io/console": "1.1.0",
|
||||
"@appwrite.io/console": "^1.2.0",
|
||||
"@appwrite.io/pink": "0.25.0",
|
||||
"@appwrite.io/pink-icons": "0.25.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/sveltekit": "^8.26.0",
|
||||
"@sentry/sveltekit": "^8.31.0",
|
||||
"@stripe/stripe-js": "^3.5.0",
|
||||
"ai": "^2.2.37",
|
||||
"analytics": "^0.8.14",
|
||||
"cron-parser": "^4.9.0",
|
||||
"dayjs": "^1.11.12",
|
||||
"dayjs": "^1.11.13",
|
||||
"deep-equal": "^2.2.3",
|
||||
"echarts": "^5.5.1",
|
||||
"envfile": "^7.1.0",
|
||||
@@ -42,12 +42,12 @@
|
||||
"devDependencies": {
|
||||
"@melt-ui/pp": "^0.3.2",
|
||||
"@melt-ui/svelte": "^0.83.0",
|
||||
"@playwright/test": "^1.46.0",
|
||||
"@sveltejs/adapter-static": "^3.0.4",
|
||||
"@sveltejs/kit": "^2.5.22",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.1",
|
||||
"@playwright/test": "^1.47.2",
|
||||
"@sveltejs/adapter-static": "^3.0.5",
|
||||
"@sveltejs/kit": "^2.5.28",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.4.8",
|
||||
"@testing-library/jest-dom": "^6.5.0",
|
||||
"@testing-library/svelte": "^5.2.1",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/deep-equal": "^1.0.4",
|
||||
@@ -55,29 +55,24 @@
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vitest/ui": "^1.6.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.43.0",
|
||||
"eslint-plugin-svelte": "^2.44.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"kleur": "^4.1.5",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.6",
|
||||
"sass": "^1.77.8",
|
||||
"svelte": "^4.2.18",
|
||||
"svelte-check": "^3.8.5",
|
||||
"sass": "^1.79.3",
|
||||
"svelte": "^4.2.19",
|
||||
"svelte-check": "^3.8.6",
|
||||
"svelte-jester": "^2.3.2",
|
||||
"svelte-preprocess": "^6.0.2",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^5.4.0",
|
||||
"tslib": "^2.7.0",
|
||||
"typescript": "^5.6.2",
|
||||
"vite": "^5.4.7",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"rollup": "^4.22.4"
|
||||
}
|
||||
},
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@9.7.0+sha512.dc09430156b427f5ecfc79888899e1c39d2d690f004be70e05230b72cb173d96839587545d09429b55ac3c429c801b4dc3c0e002f653830a420fa2dd4e3cf9cf"
|
||||
}
|
||||
|
||||
Generated
+508
-503
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@
|
||||
export let tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
||||
export let size: Size;
|
||||
export let trimmed = true;
|
||||
export let trimmedSecondLine = false;
|
||||
export let id: string = null;
|
||||
let classes = '';
|
||||
export { classes as class };
|
||||
@@ -15,6 +16,7 @@
|
||||
this={tag}
|
||||
class={`heading-level-${size} u-min-width-0 ${classes}`}
|
||||
class:u-trim-1={trimmed}
|
||||
class:u-trim-2={trimmedSecondLine}
|
||||
{style}
|
||||
{id}>
|
||||
<slot />
|
||||
|
||||
@@ -56,7 +56,7 @@ export { default as PaginationWithLimit } from './paginationWithLimit.svelte';
|
||||
export { default as ClickableList } from './clickableList.svelte';
|
||||
export { default as ClickableListItem } from './clickableListItem.svelte';
|
||||
export { default as Id } from './id.svelte';
|
||||
export { default as ProgressBar } from './progressBar.svelte';
|
||||
export * from './progressbar';
|
||||
export { default as ProgressBarBig } from './progressBarBig.svelte';
|
||||
export { default as CreditCardInfo } from './creditCardInfo.svelte';
|
||||
export { default as CreditCardBrandImage } from './creditCardBrandImage.svelte';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script context="module" lang="ts">
|
||||
let inputDigitFields: InputDigits;
|
||||
|
||||
export async function verify(challenge: Models.MfaChallenge, code: string) {
|
||||
try {
|
||||
if (challenge == null) {
|
||||
@@ -10,6 +12,7 @@
|
||||
await invalidate(Dependencies.ACCOUNT);
|
||||
trackEvent(Submit.AccountCreate);
|
||||
} catch (error) {
|
||||
inputDigitFields?.clearInputsAndRefocus();
|
||||
trackError(error, Submit.AccountCreate);
|
||||
throw error;
|
||||
}
|
||||
@@ -81,7 +84,12 @@
|
||||
{:else if challengeType == AuthenticationFactor.Phone}
|
||||
<p>A 6-digit verification code was sent to your phone, enter it below.</p>
|
||||
{/if}
|
||||
<InputDigits bind:value={code} required autofocus {autoSubmit} />
|
||||
<InputDigits
|
||||
bind:value={code}
|
||||
required
|
||||
autofocus
|
||||
{autoSubmit}
|
||||
bind:this={inputDigitFields} />
|
||||
{/if}
|
||||
{#if showVerifyButton}
|
||||
<FormItem>
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
<script lang="ts">
|
||||
export let currentValue: string;
|
||||
export let currentUnit: string;
|
||||
export let maxValue: string;
|
||||
export let maxUnit: string;
|
||||
import { ProgressBar, type ProgressbarData } from '$lib/components/progressbar';
|
||||
|
||||
export let currentValue: string | undefined = undefined;
|
||||
export let currentUnit: string | undefined = undefined;
|
||||
export let maxValue: string | undefined = undefined;
|
||||
export let maxUnit: string | undefined = undefined;
|
||||
export let progressValue: number;
|
||||
export let progressMax: number;
|
||||
export let showBar = true;
|
||||
export let minimum = 0;
|
||||
export let maximum = 100;
|
||||
export let progressBarData: Array<ProgressbarData> = [];
|
||||
|
||||
$: progress = Math.round((progressValue / progressMax) * 100);
|
||||
</script>
|
||||
|
||||
<section class="progress-bar">
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
<span class="heading-level-4">{currentValue}</span>
|
||||
<span class="body-text-1 u-bold">{currentUnit}</span>
|
||||
{#if currentValue !== undefined && currentUnit !== undefined && progress !== undefined && maxValue !== undefined && maxUnit !== undefined}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
<span class="heading-level-4">{currentValue}</span>
|
||||
<span class="body-text-1 u-bold">{currentUnit}</span>
|
||||
</p>
|
||||
<p class="heading-level-4">{progress}%</p>
|
||||
</div>
|
||||
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit}
|
||||
</p>
|
||||
<p class="heading-level-4">{progress}%</p>
|
||||
</div>
|
||||
<p class="body-text-2">
|
||||
{maxValue}
|
||||
{maxUnit}
|
||||
</p>
|
||||
</div>
|
||||
{#if showBar}
|
||||
<div
|
||||
class="progress-bar-container u-margin-block-start-16"
|
||||
class:is-warning={progress >= 75 && progress < 100}
|
||||
class:is-danger={progress >= 100}
|
||||
style:--graph-size={Math.max(Math.min(progress, maximum), minimum) + '%'} />
|
||||
{/if}
|
||||
{#if showBar && progressBarData.length > 0}
|
||||
<ProgressBar maxSize={progressMax} data={progressBarData} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<script lang="ts">
|
||||
import { tooltip } from '$lib/actions/tooltip';
|
||||
import type { ProgressbarData, ProgressbarProps } from '$lib/components';
|
||||
|
||||
type $$Props = ProgressbarProps;
|
||||
|
||||
/**
|
||||
* The max value of the progressbar
|
||||
*/
|
||||
export let maxSize: $$Props['maxSize'];
|
||||
|
||||
/**
|
||||
* The data for the progressbar
|
||||
*/
|
||||
export let data: $$Props['data'];
|
||||
|
||||
/**
|
||||
* The remaining value of the progressbar
|
||||
*/
|
||||
$: remainder = data.reduce((sum: number, item: ProgressbarData) => sum - item.size, maxSize);
|
||||
</script>
|
||||
|
||||
<section class="progressbar__container">
|
||||
{#each $$props.data as item}
|
||||
<div
|
||||
class="progressbar__content"
|
||||
style:background-color={item.color}
|
||||
style:width={`${(item.size / maxSize) * 100}%`}
|
||||
use:tooltip={{
|
||||
disabled: !item.tooltip,
|
||||
allowHTML: true,
|
||||
content: `<span class="u-bold">${item.tooltip.title}</span> ${item.tooltip.label}`
|
||||
}}>
|
||||
</div>
|
||||
{/each}
|
||||
{#if remainder > 0}
|
||||
<div class="progressbar__content" style:width={`${(remainder / maxSize) * 100}%`} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
:root {
|
||||
--progressbar-border-radius: 0.25rem;
|
||||
--progressbar-tooltip-label-color: #818186;
|
||||
--progressbar-tooltip-link-color: #6c6c71;
|
||||
}
|
||||
|
||||
:global(.theme-dark) {
|
||||
--progressbar-background-color: var(--neutral-800, #2d2d31);
|
||||
--progressbar-tooltip-background-color: var(--neutral-800, #2d2d31);
|
||||
--progressbar-tooltip-border-color: var(--neutral-80, #424248);
|
||||
}
|
||||
:global(.theme-light) {
|
||||
--progressbar-background-color: var(--neutral-40, #f4f4f7);
|
||||
--progressbar-tooltip-background-color: #ffffff;
|
||||
--progressbar-tooltip-border-color: #ededf0;
|
||||
}
|
||||
|
||||
.progressbar {
|
||||
&__container {
|
||||
height: 0.5rem;
|
||||
background-color: var(--progressbar-background-color);
|
||||
border-radius: var(--progressbar-border-radius);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: 100%;
|
||||
min-width: 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
height: 2.5rem;
|
||||
margin-top: -1.25rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: var(--progressbar-border-radius);
|
||||
border-bottom-left-radius: var(--progressbar-border-radius);
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: var(--progressbar-border-radius);
|
||||
border-bottom-right-radius: var(--progressbar-border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,17 @@
|
||||
export type ProgressbarData = {
|
||||
size: number;
|
||||
color: string;
|
||||
tooltip?: {
|
||||
title: string;
|
||||
label: string;
|
||||
// linkTitle?: string;
|
||||
// linkPath?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type ProgressbarProps = {
|
||||
maxSize: number;
|
||||
data: Array<ProgressbarData>;
|
||||
};
|
||||
|
||||
export { default as ProgressBar } from './ProgressBar.svelte';
|
||||
@@ -38,6 +38,21 @@
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Clears the input fields and moves the focus to the first input.
|
||||
* Usually used when resetting fields on auth fails, etc.
|
||||
*/
|
||||
export function clearInputsAndRefocus() {
|
||||
value = '';
|
||||
autoSubmitted = false;
|
||||
|
||||
if (element) {
|
||||
const inputs = element.querySelectorAll('input');
|
||||
inputs.forEach((input) => (input.value = ''));
|
||||
if (autofocus) inputs[0].focus();
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(() => {
|
||||
const input = element.querySelector('input');
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script>
|
||||
import { settings } from '$lib/components/consent.svelte';
|
||||
import { clickOnEnter } from '$lib/helpers/a11y';
|
||||
import { isCloud } from '$lib/system';
|
||||
import { version } from '$routes/(console)/store';
|
||||
|
||||
|
||||
@@ -178,6 +178,9 @@ export type OrganizationUsage = {
|
||||
bandwidth: Array<Models.Metric>;
|
||||
executions: Array<Models.Metric>;
|
||||
executionsTotal: number;
|
||||
filesStorageTotal: number;
|
||||
buildsStorageTotal: number;
|
||||
deploymentsStorageTotal: number;
|
||||
storageTotal: number;
|
||||
users: Array<Models.Metric>;
|
||||
usersTotal: number;
|
||||
|
||||
@@ -138,6 +138,24 @@ campaigns
|
||||
description:
|
||||
'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan'
|
||||
})
|
||||
.set('NetNinja', {
|
||||
template: 'card',
|
||||
title: 'Claim your $50 Net Ninja credits.',
|
||||
description:
|
||||
'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan'
|
||||
})
|
||||
.set('CodeWithAntonio', {
|
||||
template: 'card',
|
||||
title: 'Claim your $50 Code With Antonio credits.',
|
||||
description:
|
||||
'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan'
|
||||
})
|
||||
.set('Hacktoberfest2024', {
|
||||
template: 'card',
|
||||
title: 'Claim your $60 Hacktobefest credits.',
|
||||
description:
|
||||
'Get $60 in Cloud credits when you upgrade or create an organization with a Pro plan'
|
||||
})
|
||||
.set('VueJS', {
|
||||
template: 'card',
|
||||
title: 'Claim your $50 VueJS credits.',
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
}} />
|
||||
</p>
|
||||
<p class="text u-margin-block-start-4">
|
||||
This could include unauthorized users and search engines.
|
||||
This could include unauthorized users and bots.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
content:
|
||||
'You are limited to 1 free organization per account'
|
||||
}}>
|
||||
<Pill>FREE</Pill>
|
||||
<Pill class="eyebrow-heading-3">FREE</Pill>
|
||||
</div>
|
||||
{/if}
|
||||
{#if organization?.billingTrialStartDate && $daysLeftInTrial > 0 && organization.billingPlan !== BillingPlan.FREE && $plansInfo.get(organization.billingPlan)?.trialDays}
|
||||
@@ -89,7 +89,7 @@
|
||||
organization.billingStartDate
|
||||
)}. ${$daysLeftInTrial} days remaining.`
|
||||
}}>
|
||||
<Pill>TRIAL</Pill>
|
||||
<Pill class="eyebrow-heading-3">TRIAL</Pill>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
{$organization.name}
|
||||
</span>
|
||||
{#if isCloud && $organization?.billingPlan === BillingPlan.FREE}
|
||||
<Pill>FREE</Pill>
|
||||
<Pill class="eyebrow-heading-3">FREE</Pill>
|
||||
{/if}
|
||||
{#if isCloud && $organization?.billingTrialStartDate && $daysLeftInTrial > 0 && $organization.billingPlan !== BillingPlan.FREE && $plansInfo.get($organization.billingPlan)?.trialDays}
|
||||
<div
|
||||
@@ -118,7 +118,7 @@
|
||||
$organization.billingStartDate
|
||||
)}. ${$daysLeftInTrial} days remaining.`
|
||||
}}>
|
||||
<Pill>TRIAL</Pill>
|
||||
<Pill class="eyebrow-heading-3">TRIAL</Pill>
|
||||
</div>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
@@ -282,6 +282,32 @@
|
||||
{@const current = data.organizationUsage.storageTotal}
|
||||
{@const currentHumanized = humanFileSize(current)}
|
||||
{@const max = getServiceLimit('storage', tier)}
|
||||
{@const progressBarStorageDate = [
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.filesStorageTotal, 'GB'),
|
||||
color: '#85DBD8',
|
||||
tooltip: {
|
||||
title: 'File storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.filesStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.deploymentsStorageTotal, 'GB'),
|
||||
color: '#7C67FE',
|
||||
tooltip: {
|
||||
title: 'Deployments storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.deploymentsStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.organizationUsage.buildsStorageTotal, 'GB'),
|
||||
color: '#FE9567',
|
||||
tooltip: {
|
||||
title: 'Builds storage',
|
||||
label: `${Math.round(bytesToSize(data.organizationUsage.buildsStorageTotal, 'GB') * 100) / 100}GB`
|
||||
}
|
||||
}
|
||||
]}
|
||||
<ProgressBarBig
|
||||
currentUnit={currentHumanized.unit}
|
||||
currentValue={currentHumanized.value}
|
||||
@@ -289,7 +315,7 @@
|
||||
maxValue={max.toString()}
|
||||
progressValue={bytesToSize(current, 'GB')}
|
||||
progressMax={max}
|
||||
minimum={1} />
|
||||
progressBarData={progressBarStorageDate} />
|
||||
{#if project?.length > 0}
|
||||
<ProjectBreakdown projects={project} metric="storage" {data} />
|
||||
{/if}
|
||||
|
||||
@@ -19,6 +19,9 @@ export const load: PageLoad = async ({ params, parent }) => {
|
||||
users: null,
|
||||
usersTotal: null,
|
||||
storageTotal: null,
|
||||
filesStorageTotal: null,
|
||||
buildsStorageTotal: null,
|
||||
deploymentsStorageTotal: null,
|
||||
executions: null,
|
||||
executionsTotal: null,
|
||||
projects: null
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@
|
||||
showEdit = true;
|
||||
showDropdown[index] = false;
|
||||
}}>
|
||||
Edit
|
||||
Update
|
||||
</DropListItem>
|
||||
{#if !isRelationship(attribute)}
|
||||
<DropListItem
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
await sdk.forProject.databases.updateBooleanAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.default,
|
||||
data.key !== originalKey ? data.key : undefined
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
await sdk.forProject.databases.updateDatetimeAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.default,
|
||||
data.key !== originalKey ? data.key : undefined
|
||||
|
||||
+10
-6
@@ -52,12 +52,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if (showEdit) {
|
||||
currentAttr ??= { ...selectedAttribute };
|
||||
originalKey = currentAttr.key;
|
||||
error = null;
|
||||
} else {
|
||||
currentAttr = null;
|
||||
$: onShow(showEdit);
|
||||
|
||||
function onShow(show: boolean) {
|
||||
if (show) {
|
||||
currentAttr ??= { ...selectedAttribute };
|
||||
originalKey = currentAttr.key;
|
||||
error = null;
|
||||
} else {
|
||||
currentAttr = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
await sdk.forProject.databases.updateEmailAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.default,
|
||||
data.key !== originalKey ? data.key : undefined
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
await sdk.forProject.databases.updateEnumAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.elements,
|
||||
data.required,
|
||||
data.default,
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
await sdk.forProject.databases.updateFloatAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.min,
|
||||
data.max,
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
await sdk.forProject.databases.updateIntegerAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.min,
|
||||
data.max,
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
await sdk.forProject.databases.updateIpAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.default,
|
||||
data.key !== originalKey ? data.key : undefined
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
await sdk.forProject.databases.updateUrlAttribute(
|
||||
databaseId,
|
||||
collectionId,
|
||||
data.key,
|
||||
originalKey,
|
||||
data.required,
|
||||
data.default,
|
||||
data.key !== originalKey ? data.key : undefined
|
||||
|
||||
+12
-7
@@ -11,6 +11,7 @@
|
||||
|
||||
export let show = false;
|
||||
export let selectedDeployment: Models.Deployment = null;
|
||||
let error: string;
|
||||
|
||||
async function redeploy() {
|
||||
try {
|
||||
@@ -28,17 +29,21 @@
|
||||
invalidate(Dependencies.FUNCTION);
|
||||
invalidate(Dependencies.DEPLOYMENTS);
|
||||
show = false;
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
message: error.message
|
||||
});
|
||||
trackError(error, Submit.FunctionRedeploy);
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
|
||||
trackError(e, Submit.FunctionRedeploy);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal title="Redeploy function" size="big" bind:show onSubmit={redeploy} headerDivider={false}>
|
||||
<Modal
|
||||
title="Redeploy function"
|
||||
size="big"
|
||||
bind:show
|
||||
bind:error
|
||||
onSubmit={redeploy}
|
||||
headerDivider={false}>
|
||||
<p class="text">
|
||||
Are you sure you want to redeploy <b>{$func.name}</b>? Redeploying may affect your
|
||||
production code.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Container } from '$lib/layout';
|
||||
import { CardGrid, Heading, Card } from '$lib/components';
|
||||
import { CardGrid, Heading, Card, ProgressBarBig } from '$lib/components';
|
||||
import {
|
||||
TableBody,
|
||||
TableCell,
|
||||
@@ -13,7 +13,7 @@
|
||||
import { showUsageRatesModal, tierToPlan, upgradeURL } from '$lib/stores/billing';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { bytesToSize, humanFileSize } from '$lib/helpers/sizeConvertion';
|
||||
import { BarChart } from '$lib/charts';
|
||||
import { formatNum } from '$lib/helpers/string';
|
||||
import { total } from '$lib/layout/usage.svelte';
|
||||
@@ -28,7 +28,10 @@
|
||||
$: usersTotal = data.usage.usersTotal;
|
||||
$: executions = data.usage.executions;
|
||||
$: executionsTotal = data.usage.executionsTotal;
|
||||
$: storage = data.usage.filesStorageTotal;
|
||||
$: storage =
|
||||
data.usage.filesStorageTotal +
|
||||
data.usage.deploymentsStorageTotal +
|
||||
data.usage.buildsStorageTotal;
|
||||
|
||||
const tier = data?.currentInvoice?.plan ?? $organization?.billingPlan;
|
||||
const plan = tierToPlan(tier).name;
|
||||
@@ -271,6 +274,32 @@
|
||||
<svelte:fragment slot="aside">
|
||||
{#if storage}
|
||||
{@const humanized = humanFileSize(storage)}
|
||||
{@const progressBarStorageDate = [
|
||||
{
|
||||
size: bytesToSize(data.usage.filesStorageTotal, 'MB'),
|
||||
color: '#85DBD8',
|
||||
tooltip: {
|
||||
title: 'File storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.filesStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.usage.deploymentsStorageTotal, 'MB'),
|
||||
color: '#7C67FE',
|
||||
tooltip: {
|
||||
title: 'Deployments storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.deploymentsStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
},
|
||||
{
|
||||
size: bytesToSize(data.usage.buildsStorageTotal, 'MB'),
|
||||
color: '#FE9567',
|
||||
tooltip: {
|
||||
title: 'Builds storage',
|
||||
label: `${Math.round(bytesToSize(data.usage.buildsStorageTotal, 'MB') * 100) / 100}MB`
|
||||
}
|
||||
}
|
||||
]}
|
||||
<div class="u-flex u-flex-vertical">
|
||||
<div class="u-flex u-main-space-between">
|
||||
<p>
|
||||
@@ -279,33 +308,10 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{#if data.usage.bucketsBreakdown.length > 0}
|
||||
<Table noMargin noStyles>
|
||||
<TableHeader>
|
||||
<TableCellHead width={285}>Bucket</TableCellHead>
|
||||
<TableCellHead>Usage</TableCellHead>
|
||||
<TableCellHead width={140} />
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{#each data.usage.bucketsBreakdown.sort((a, b) => b.value - a.value) as bucket}
|
||||
{@const humanized = humanFileSize(bucket.value)}
|
||||
<TableRow>
|
||||
<TableCell title="Function">
|
||||
{bucket.name ?? bucket.resourceId}
|
||||
</TableCell>
|
||||
<TableCell title="Usage">
|
||||
{humanized.value}{humanized.unit}
|
||||
</TableCell>
|
||||
<TableCellLink
|
||||
href={`${baseRoute}/storage/bucket-${bucket.resourceId}`}
|
||||
title="View bucket">
|
||||
View bucket
|
||||
</TableCellLink>
|
||||
</TableRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{/if}
|
||||
<ProgressBarBig
|
||||
progressValue={bytesToSize(storage, 'MB')}
|
||||
progressMax={bytesToSize(storage, 'MB')}
|
||||
progressBarData={progressBarStorageDate} />
|
||||
{:else}
|
||||
<Card isDashed>
|
||||
<div class="u-flex u-cross-center u-flex-vertical u-main-center u-flex">
|
||||
|
||||
+12
-8
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { CardGrid, BoxAvatar, Heading, Alert, Id } from '$lib/components';
|
||||
import { CardGrid, BoxAvatar, Heading, Alert, CopyInput } from '$lib/components';
|
||||
import { Container } from '$lib/layout';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { file } from './store';
|
||||
@@ -92,18 +92,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="u-flex u-flex-vertical u-gap-16">
|
||||
<Heading tag="h2" size="7">{$file.name}</Heading>
|
||||
<Id value={getView($file.$id)}>File URL</Id>
|
||||
<div class="u-flex u-flex-vertical u-gap-4">
|
||||
<Heading tag="h2" size="7" trimmed={false} trimmedSecondLine={true}
|
||||
>{$file.name}</Heading>
|
||||
<p>{$file.mimeType}</p>
|
||||
</div>
|
||||
</div>
|
||||
<svelte:fragment slot="aside">
|
||||
<div>
|
||||
<p>MIME Type: {$file.mimeType}</p>
|
||||
<p>Size: {calculateSize($file.sizeOriginal)}</p>
|
||||
<p>Created: {toLocaleDate($file.$createdAt)}</p>
|
||||
<p>Last updated: {toLocaleDate($file.$updatedAt)}</p>
|
||||
<p><span class="u-bold">Size:</span> {calculateSize($file.sizeOriginal)}</p>
|
||||
<p><span class="u-bold">Created:</span> {toLocaleDate($file.$createdAt)}</p>
|
||||
<p>
|
||||
<span class="u-bold">Last updated:</span>
|
||||
{toLocaleDate($file.$updatedAt)}
|
||||
</p>
|
||||
</div>
|
||||
<CopyInput label="File URL" showLabel={true} value={getView($file.$id)} />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions">
|
||||
|
||||
@@ -51,17 +51,6 @@
|
||||
await goto(`${base}/apply-credit?campaign=${data.campaign}`);
|
||||
return;
|
||||
}
|
||||
if ($page.url.searchParams) {
|
||||
const redirect = $page.url.searchParams.get('redirect');
|
||||
$page.url.searchParams.delete('redirect');
|
||||
if (redirect) {
|
||||
await goto(`${redirect}${$page.url.search}`);
|
||||
} else {
|
||||
await goto(`${base}${$page.url.search ?? ''}`);
|
||||
}
|
||||
} else {
|
||||
await goto(base);
|
||||
}
|
||||
} catch (error) {
|
||||
disabled = false;
|
||||
addNotification({
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 416 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 384 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 246 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 416 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 384 KiB |
+9
-1
@@ -4,10 +4,18 @@ import { preprocessMeltUI, sequence } from '@melt-ui/pp';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
preprocess: sequence([sveltePreprocess(), preprocessMeltUI()]),
|
||||
preprocess: sequence([
|
||||
sveltePreprocess({
|
||||
scss: {
|
||||
silenceDeprecations: ['legacy-js-api']
|
||||
}
|
||||
}),
|
||||
preprocessMeltUI()
|
||||
]),
|
||||
compilerOptions: {
|
||||
accessors: !!process.env.VITEST
|
||||
},
|
||||
|
||||
kit: {
|
||||
alias: {
|
||||
$routes: './src/routes'
|
||||
|
||||
Reference in New Issue
Block a user