diff --git a/package-lock.json b/package-lock.json index 73a025a09..cdb6a1ec0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "@appwrite/console", "dependencies": { - "@appwrite.io/console": "^0.6.2", + "@appwrite.io/console": "npm:matej-appwrite-console-16x@0.6.7", "@appwrite.io/pink": "0.23.0", "@appwrite.io/pink-icons": "0.23.0", "@popperjs/core": "^2.11.8", @@ -150,9 +150,10 @@ "integrity": "sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==" }, "node_modules/@appwrite.io/console": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-0.6.2.tgz", - "integrity": "sha512-3qYknuFwhvTN2GnPB8G1w5DgxfVorGtfj4uuEaXbTmMUmjA8fHaW5VkJriuUxCi6/TpxDxqV/hhEkdoXL+5H4w==" + "name": "matej-appwrite-console-16x", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/matej-appwrite-console-16x/-/matej-appwrite-console-16x-0.6.7.tgz", + "integrity": "sha512-orhonLVjV0vzJE/OrI49DRJ75EAkEa+8QzWy30h1N04jNyAcEGFfx4OKmhWg4uG5XRrmWrrDj9nobHKCiBaDCg==" }, "node_modules/@appwrite.io/pink": { "version": "0.23.0", diff --git a/package.json b/package.json index 3ce486181..aa9ceb951 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "e2e:ui": "playwright test tests/e2e --ui" }, "dependencies": { - "@appwrite.io/console": "^0.6.2", + "@appwrite.io/console": "npm:matej-appwrite-console-16x@0.6.7", "@appwrite.io/pink": "0.23.0", "@appwrite.io/pink-icons": "0.23.0", "@popperjs/core": "^2.11.8", diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 744a4e351..156fca4fc 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -194,6 +194,7 @@ export enum Submit { AuthPasswordHistoryUpdate = 'submit_auth_password_history_limit_update', AuthPasswordDictionaryUpdate = 'submit_auth_password_dictionary_update', AuthPersonalDataCheckUpdate = 'submit_auth_personal_data_check_update', + AuthMockNumbersUpdate = 'submit_auth_mock_numbers_update', SessionsLengthUpdate = 'submit_sessions_length_update', SessionsLimitUpdate = 'submit_sessions_limit_update', SessionDelete = 'submit_session_delete', @@ -226,13 +227,16 @@ export enum Submit { FunctionUpdateLogging = 'submit_function_update_logging', FunctionUpdateTimeout = 'submit_function_update_timeout', FunctionUpdateEvents = 'submit_function_update_events', + FunctionUpdateScopes = 'submit_function_key_update_scopes', FunctionConnectRepo = 'submit_function_connect_repo', FunctionDisconnectRepo = 'submit_function_disconnect_repo', FunctionRedeploy = 'submit_function_redeploy', DeploymentCreate = 'submit_deployment_create', DeploymentDelete = 'submit_deployment_delete', DeploymentUpdate = 'submit_deployment_update', + DeploymentCancel = 'submit_deployment_cancel', ExecutionCreate = 'submit_execution_create', + ExecutionDelete = 'submit_execution_delete', VariableCreate = 'submit_variable_create', VariableDelete = 'submit_variable_delete', VariableUpdate = 'submit_variable_update', diff --git a/src/lib/components/billing/creditsApplied.svelte b/src/lib/components/billing/creditsApplied.svelte index 6cf231e57..1010f0f5e 100644 --- a/src/lib/components/billing/creditsApplied.svelte +++ b/src/lib/components/billing/creditsApplied.svelte @@ -42,9 +42,7 @@ {/if} {#if couponData.credits >= 100} -

- Credits applied -

+

Credits applied

{:else} -{formatCurrency(couponData.credits)} {/if} diff --git a/src/lib/components/billing/estimatedTotalBox.svelte b/src/lib/components/billing/estimatedTotalBox.svelte index 52ac4faba..3ff31041c 100644 --- a/src/lib/components/billing/estimatedTotalBox.svelte +++ b/src/lib/components/billing/estimatedTotalBox.svelte @@ -32,9 +32,10 @@
+

{currentPlan.name} plan

{formatCurrency(currentPlan.price)}

diff --git a/src/lib/components/dropList.svelte b/src/lib/components/dropList.svelte index 0c802cffd..effecd4a6 100644 --- a/src/lib/components/dropList.svelte +++ b/src/lib/components/dropList.svelte @@ -36,10 +36,10 @@ }`}> {#if $$slots.list}
+ class="drop-section" + style={noMaxWidthList ? 'max-inline-size: 100%' : ''}>
diff --git a/src/lib/components/filters/content.svelte b/src/lib/components/filters/content.svelte index cb56ca1e5..72634ab94 100644 --- a/src/lib/components/filters/content.svelte +++ b/src/lib/components/filters/content.svelte @@ -6,96 +6,25 @@ InputText, InputTags, FormList, - InputSelectCheckbox + InputSelectCheckbox, + InputDateTime } from '$lib/elements/forms'; - import { Query } from '@appwrite.io/console'; import { createEventDispatcher, onMount } from 'svelte'; - import { tags, type Operator, queries, type TagValue } from './store'; + import { tags, operators, addFilter, queries } from './store'; import type { Column } from '$lib/helpers/types'; import type { Writable } from 'svelte/store'; - import { tooltip } from '$lib/actions/tooltip'; + import { TagList } from '.'; + // We cast to any to not cause type errors in the input components + /* eslint @typescript-eslint/no-explicit-any: 'off' */ + export let value: any = null; export let columns: Writable; export let columnId: string | null = null; - - const dispatch = createEventDispatcher<{ - clear: void; - apply: { applied: number }; - }>(); + export let arrayValues: string[] = []; + export let operatorKey: string | null = null; + export let singleCondition = false; $: column = $columns.find((c) => c.id === columnId) as Column; - let arrayValues: string[] = []; - - dispatch('apply', { applied: $tags.length }); - - const operators: Record = { - 'starts with': { - toQuery: Query.startsWith, - toTag: (attribute, input) => `**${attribute}** starts with **${input}**`, - types: ['string'] - }, - 'ends with': { - toQuery: Query.endsWith, - toTag: (attribute, input) => `**${attribute}** ends with **${input}**`, - types: ['string'] - }, - 'greater than': { - toQuery: (attr, input) => Query.greaterThan(attr, Number(input)), - toTag: (attribute, input) => `**${attribute}** greater than **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'greater than or equal': { - toQuery: (attr, input) => Query.greaterThanEqual(attr, Number(input)), - toTag: (attribute, input) => `**${attribute}** greater than or equal to **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'less than': { - toQuery: Query.lessThan, - toTag: (attribute, input) => `**${attribute}** less than **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'less than or equal': { - toQuery: Query.lessThanEqual, - toTag: (attribute, input) => `**${attribute}** less than or equal to **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - equal: { - toQuery: Query.equal, - toTag: (attribute, input) => `**${attribute}** equal to **${input}**`, - types: ['string', 'integer', 'double', 'boolean'] - }, - 'not equal': { - toQuery: Query.notEqual, - toTag: (attribute, input) => `**${attribute}** not equal to **${input}**`, - types: ['string', 'integer', 'double', 'boolean'] - }, - 'is not null': { - toQuery: Query.isNotNull, - toTag: (attribute) => `**${attribute}** is not null`, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], - hideInput: true - }, - 'is null': { - toQuery: Query.isNull, - toTag: (attribute) => `**${attribute}** is null`, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], - hideInput: true - }, - contains: { - toQuery: Query.contains, - toTag: (attribute, input) => { - if (Array.isArray(input) && input.length > 2) { - return { - value: input, - tag: `**${attribute}** contains **${formatArray(input)}** ` - }; - } else { - return `**${attribute}** contains **${input}**`; - } - }, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'enum'] - } - }; $: operatorsForColumn = Object.entries(operators) .filter(([, v]) => v.types.includes(column?.type)) @@ -104,65 +33,43 @@ value: k })); - let operatorKey: string | null = null; $: operator = operatorKey ? operators[operatorKey] : null; $: { columnId; operatorKey = null; } - // We cast to any to not cause type errors in the input components - /* eslint @typescript-eslint/no-explicit-any: 'off' */ - let value: any = null; + $: isDisabled = !operator; onMount(() => { value = column?.array ? [] : null; + if (column?.type === 'datetime') { + const today = new Date(); + value = today.toISOString(); + } }); - // This Map is keyed by tags, and has a query as the value - function addFilter() { - if (!column || !operator) return; - if (column.array) { - queries.addFilter({ column, operator, value: arrayValues }); - columnId = null; - arrayValues = []; - } else { - queries.addFilter({ column, operator, value: value ?? '' }); - columnId = null; - value = null; + function addFilterAndReset() { + addFilter($columns, columnId, operatorKey, value, arrayValues); + columnId = null; + operatorKey = null; + value = null; + arrayValues = []; + if (singleCondition) { + queries.apply(); } } - function tagFormat(node: HTMLElement) { - node.innerHTML = node.innerHTML.replace(/\*\*(.*?)\*\*/g, '$1'); - } - - function formatArray(array: string[]) { - if (!array?.length) return; - if (array.length > 2) { - return `${array[0]} or ${array.length - 1} others`; - } else { - return array.join(' or '); - } - } - - function isTypeTagValue(obj: any): obj is TagValue { - if (typeof obj === 'string') return false; - return ( - obj && - typeof obj.tag === 'string' && - (typeof obj.value === 'string' || - typeof obj.value === 'number' || - Array.isArray(obj.value)) - ); - } - - $: isDisabled = !operator; + const dispatch = createEventDispatcher<{ + clear: void; + apply: { applied: number }; + }>(); + dispatch('apply', { applied: $tags.length });
-
-
    + +
      ({ - label: value, - value, - checked: arrayValues.includes(value) + options={column?.elements?.map((e) => ({ + label: e?.label ?? e, + value: e?.value ?? e, + checked: arrayValues.includes(e?.value ?? e) }))}> {:else} @@ -210,7 +117,10 @@ id="value" bind:value placeholder="Select value" - options={column?.elements?.map((value) => ({ label: value, value }))} + options={column?.elements?.map((e) => ({ + label: e?.label ?? e, + value: e?.value ?? e + }))} label="Value" showLabel={false} /> {:else if column.type === 'integer' || column.type === 'double'} @@ -225,48 +135,29 @@ { label: 'False', value: false } ].filter(Boolean)} bind:value /> + {:else if column.type === 'datetime'} + {#key value} + + {/key} {:else} {/if}
    {/if} {/if} - + {#if !singleCondition} + + {/if} -
      - {#each $tags as tag (tag)} - {#if isTypeTagValue(tag)} - - {:else} - - {/if} - {/each} -
    + {#if !singleCondition} +
      + +
    + {/if}
diff --git a/src/lib/layout/wizardSecondaryContent.svelte b/src/lib/layout/wizardSecondaryContent.svelte index 6b69d488a..908995692 100644 --- a/src/lib/layout/wizardSecondaryContent.svelte +++ b/src/lib/layout/wizardSecondaryContent.svelte @@ -4,8 +4,6 @@
-
- -
+
diff --git a/src/lib/layout/wizardSecondaryHeader.svelte b/src/lib/layout/wizardSecondaryHeader.svelte index bb74685db..048482de9 100644 --- a/src/lib/layout/wizardSecondaryHeader.svelte +++ b/src/lib/layout/wizardSecondaryHeader.svelte @@ -4,8 +4,18 @@ import { Button } from '$lib/elements/forms'; import { createEventDispatcher } from 'svelte'; - export let confirmExit = false; - export let href = ''; + type $$Props = + | { + confirmExit: boolean; + href?: string; + } + | { + confirmExit?: boolean; + href: string; + }; + + export let confirmExit: $$Props['confirmExit'] = false; + export let href: $$Props['href'] = ''; const dispatch = createEventDispatcher(); diff --git a/src/lib/sdk/functionsSpec.ts b/src/lib/sdk/functionsSpec.ts new file mode 100644 index 000000000..a50679099 --- /dev/null +++ b/src/lib/sdk/functionsSpec.ts @@ -0,0 +1,292 @@ +import { AppwriteException, Runtime, type Client, type Payload } from '@appwrite.io/console'; + +export type Specs = { + cpus: number[]; + memory: number[]; +}; + +/** + * Variable + */ +type Variable = { + /** + * Variable ID. + */ + $id: string; + /** + * Variable creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Variable creation date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Variable key. + */ + key: string; + /** + * Variable value. + */ + value: string; + /** + * Service to which the variable belongs. Possible values are "project", "function" + */ + resourceType: string; + /** + * ID of resource to which the variable belongs. If resourceType is "project", it is empty. If resourceType is "function", it is ID of the function. + */ + resourceId: string; +}; + +export type Func = { + /** + * Function ID. + */ + $id: string; + /** + * Function creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Function update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Execution permissions. + */ + execute: string[]; + /** + * Function name. + */ + name: string; + /** + * Function enabled. + */ + enabled: boolean; + /** + * Is the function deployed with the latest configuration? This is set to false if you've changed an environment variables, entrypoint, commands, or other settings that needs redeploy to be applied. When the value is false, redeploy the function to update it with the latest configuration. + */ + live: boolean; + /** + * Whether executions will be logged. When set to false, executions will not be logged, but will reduce resource used by your Appwrite project. + */ + logging: boolean; + /** + * Function execution runtime. + */ + runtime: string; + /** + * Function's active deployment ID. + */ + deployment: string; + /** + * Function variables. + */ + vars: Variable[]; + /** + * Function trigger events. + */ + events: string[]; + /** + * Function execution schedult in CRON format. + */ + schedule: string; + /** + * Function execution timeout in seconds. + */ + timeout: number; + /** + * The entrypoint file used to execute the deployment. + */ + entrypoint: string; + /** + * The build command used to build the deployment. + */ + commands: string; + /** + * Version of Open Runtimes used for the function. + */ + version: string; + /** + * Function VCS (Version Control System) installation id. + */ + installationId: string; + /** + * VCS (Version Control System) Repository ID + */ + providerRepositoryId: string; + /** + * VCS (Version Control System) branch name + */ + providerBranch: string; + /** + * Path to function in VCS (Version Control System) repository + */ + providerRootDirectory: string; + /** + * Is VCS (Version Control System) connection is in silent mode? When in silence mode, no comments will be posted on the repository pull or merge requests + */ + providerSilentMode: boolean; + /** + * CPU limit + */ + cpus: number; + /** + * Memory limit + */ + memory: number; +}; + +export class SpecsFunctions { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + async getSpecs(): Promise { + const path = '/functions/specs'; + + const uri = new URL(this.client.config.endpoint + path); + return await this.client.call('GET', uri, { + 'content-type': 'application/json' + }); + } + + /** + * Update function + * + * Update function by its unique ID. + * + * @param {string} functionId + * @param {string} name + * @param {Runtime} runtime + * @param {string[]} execute + * @param {string[]} events + * @param {string} schedule + * @param {number} timeout + * @param {boolean} enabled + * @param {boolean} logging + * @param {string} entrypoint + * @param {string} commands + * @param {string} installationId + * @param {string} providerRepositoryId + * @param {string} providerBranch + * @param {boolean} providerSilentMode + * @param {string} providerRootDirectory + * @param {number} cpus + * @param {number} memory + * @throws {AppwriteException} + * @returns {Promise} + */ + async update( + functionId: string, + name: string, + runtime?: Runtime, + execute?: string[], + events?: string[], + schedule?: string, + timeout?: number, + enabled?: boolean, + logging?: boolean, + entrypoint?: string, + commands?: string, + installationId?: string, + providerRepositoryId?: string, + providerBranch?: string, + providerSilentMode?: boolean, + providerRootDirectory?: string, + cpus?: number, + memory?: number + ): Promise { + if (typeof functionId === 'undefined') { + throw new AppwriteException('Missing required parameter: "functionId"'); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/functions/{functionId}'.replace('{functionId}', functionId); + const payload: Payload = {}; + + if (typeof name !== 'undefined') { + payload['name'] = name; + } + + if (typeof runtime !== 'undefined') { + payload['runtime'] = runtime; + } + + if (typeof execute !== 'undefined') { + payload['execute'] = execute; + } + + if (typeof events !== 'undefined') { + payload['events'] = events; + } + + if (typeof schedule !== 'undefined') { + payload['schedule'] = schedule; + } + + if (typeof timeout !== 'undefined') { + payload['timeout'] = timeout; + } + + if (typeof enabled !== 'undefined') { + payload['enabled'] = enabled; + } + + if (typeof logging !== 'undefined') { + payload['logging'] = logging; + } + + if (typeof entrypoint !== 'undefined') { + payload['entrypoint'] = entrypoint; + } + + if (typeof commands !== 'undefined') { + payload['commands'] = commands; + } + + if (typeof installationId !== 'undefined') { + payload['installationId'] = installationId; + } + + if (typeof providerRepositoryId !== 'undefined') { + payload['providerRepositoryId'] = providerRepositoryId; + } + + if (typeof providerBranch !== 'undefined') { + payload['providerBranch'] = providerBranch; + } + + if (typeof providerSilentMode !== 'undefined') { + payload['providerSilentMode'] = providerSilentMode; + } + + if (typeof providerRootDirectory !== 'undefined') { + payload['providerRootDirectory'] = providerRootDirectory; + } + + if (typeof cpus !== 'undefined') { + payload['cpus'] = cpus; + } + + if (typeof memory !== 'undefined') { + payload['memory'] = memory; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + return await this.client.call( + 'put', + uri, + { + 'content-type': 'application/json' + }, + payload + ); + } +} diff --git a/src/lib/stores/campaigns.ts b/src/lib/stores/campaigns.ts index cf381f16d..6ffc9e0f1 100644 --- a/src/lib/stores/campaigns.ts +++ b/src/lib/stores/campaigns.ts @@ -1,40 +1,119 @@ //campaign welcome and startup -type CampaignData = { +export type CampaignData = { title: string; description: string; + template: 'card' | 'review'; + data?: Record; + onlyNewOrgs?: boolean; + footer?: boolean; }; export const campaigns: Map = new Map(); campaigns .set('welcome', { + template: 'card', title: "You've received $VALUE in credits", description: 'Get $VALUE in credits when you upgrade or create an organization with a Pro plan.' }) .set('startup', { + template: 'card', title: 'Welcome to the Startups program!', description: "We're excited to have you on board. Add the coupon code to your Appwrite Pro account to join." }) .set('RenderATL2024', { + template: 'card', title: 'Claim your $100 RenderATL credits', description: 'Get $100 in Cloud credits when you upgrade or create an organization with a Pro plan.' }) .set('dealsfordevs', { + template: 'card', title: 'Claim your $50 Deals For Devs credits', description: 'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan.' }) .set('WelcomeManual', { + template: 'card', title: 'Here is your $VALUE welcome credit!', description: 'Upgrade to Appwrite Pro and add the credits to enjoy the full capabilities of Cloud.' }) .set('InactiveAccounts', { + template: 'card', title: 'Get everything out of Cloud. Claim your $VALUE credits.', description: 'Get $VALUE in Cloud credits when you upgrade or create an organization with a Pro plan.' + }) + .set('StartupsProgram', { + template: 'review', + title: 'Welcome to the Startups program', + description: + "We're excited to have you on board. Add your credit code to your Appwrite Pro account to join.", + onlyNewOrgs: true, + data: { + cta: 'Get everything out of Cloud with Pro', + claimed: 'Your credits will be valid for 12 months.', + unclaimed: 'Apply your code to join the Startups program.', + reviews: [ + { + name: 'David Foster', + img: '1.jpeg', + desc: 'Managing director', + review: 'We really loved working with Appwrite for launching our bootstrapped "Open Mind" App. It was saving us a lot of money in comparison to Firebase since the amount of users grew quite fast and we needed a quick switch.' + } + ] + } + }) + .set('JSMastery', { + template: 'review', + title: 'Claim your JavaScript Mastery $50 credits.', + description: + 'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan', + data: { + reviews: [ + { + name: 'Marius Bloki', + desc: 'CTO // mySHOEFITTER', + img: 'js_mastery_reviewer_1.png', + review: 'Appwrite has been a tremendous asset in implementing our IT infrastructure. Not only is the software an absolute game-changer, but the team is always there when you need them.' + } + ] + } + }) + .set('FusionVC', { + template: 'review', + title: 'Welcome to Appwrite!', + description: + 'Upgrade to Appwrite Pro and add the credits to enjoy the full capabilities of Cloud. Provided to you by Fusion VC.', + footer: true, + data: { + reviews: [ + { + name: 'David Foster', + img: '1.jpeg', + desc: 'Managing director', + review: 'We really loved working with Appwrite for launching our bootstrapped "Open Mind" App. It was saving us a lot of money in comparison to Firebase since the amount of users grew quite fast and we needed a quick switch.' + } + ] + } + }) + .set('carbon', { + template: 'review', + title: 'Build your entire backend within minutes.', + description: + 'Get $50 in Cloud credits when you upgrade or create an organization with a Pro plan.', + data: { + reviews: [ + { + name: 'David Foster', + img: '1.jpeg', + desc: 'Managing director', + review: 'We really loved working with Appwrite for launching our bootstrapped "Open Mind" App. It was saving us a lot of money in comparison to Firebase since the amount of users grew quite fast and we needed a quick switch.' + } + ] + } }); diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index 8434b9e99..ab3f0f0ae 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -24,6 +24,7 @@ import { import { Billing } from '../sdk/billing'; import { Sources } from '$lib/sdk/sources'; import { Account as WebauthnAccount } from '$lib/sdk/account'; +import { SpecsFunctions } from '$lib/sdk/functionsSpec'; const endpoint = VARS.APPWRITE_ENDPOINT ?? `${globalThis?.location?.origin}/v1`; @@ -40,6 +41,7 @@ const sdkForProject = { avatars: new Avatars(clientProject), databases: new Databases(clientProject), functions: new Functions(clientProject), + specsFunctions: new SpecsFunctions(clientProject), health: new Health(clientProject), locale: new Locale(clientProject), messaging: new Messaging(clientProject), diff --git a/src/lib/wizards/functions/connectExisting.svelte b/src/lib/wizards/functions/connectExisting.svelte index 7d097f773..f28cc8555 100644 --- a/src/lib/wizards/functions/connectExisting.svelte +++ b/src/lib/wizards/functions/connectExisting.svelte @@ -31,6 +31,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $installation.$id, $repository.id, $choices.branch, diff --git a/src/lib/wizards/functions/createGit.svelte b/src/lib/wizards/functions/createGit.svelte index cf8a4b748..f6307df41 100644 --- a/src/lib/wizards/functions/createGit.svelte +++ b/src/lib/wizards/functions/createGit.svelte @@ -32,6 +32,7 @@ undefined, $createFunction.entrypoint, $createFunction.commands || undefined, + undefined, $installation.$id, $repository.id, $choices.branch, diff --git a/src/lib/wizards/functions/createTemplate.svelte b/src/lib/wizards/functions/createTemplate.svelte index 7d0d4958f..11580051f 100644 --- a/src/lib/wizards/functions/createTemplate.svelte +++ b/src/lib/wizards/functions/createTemplate.svelte @@ -49,6 +49,7 @@ undefined, runtimeDetail.entrypoint, runtimeDetail.commands || undefined, + undefined, $installation.$id, $repository.id, $choices.branch, diff --git a/src/routes/console/apply-credit/+page.svelte b/src/routes/console/apply-credit/+page.svelte index 4395538f1..d1dd1ce47 100644 --- a/src/routes/console/apply-credit/+page.svelte +++ b/src/routes/console/apply-credit/+page.svelte @@ -67,10 +67,11 @@ let name: string; let coupon: string; let couponData = data?.couponData; + let campaign = campaigns.get(data?.couponData?.campaign ?? data?.campaign); onMount(async () => { await loadPaymentMethods(); - if (!$organizationList?.total) { + if (!$organizationList?.total || campaign?.onlyNewOrgs) { selectedOrgId = newOrgId; } }); @@ -183,7 +184,6 @@ $: isButtonDisabled = checkButtonDisabled(selectedOrgId, name, paymentMethodId) || couponData?.status !== 'active'; - $: campaign = campaigns.get(data?.couponData?.campaign ?? data?.campaign); function checkButtonDisabled(id: string | null, name: string | null, method: string | null) { if (id === newOrgId) { @@ -207,7 +207,7 @@
- {#if $organizationList?.total} + {#if $organizationList?.total && !campaign?.onlyNewOrgs} -
-
-
- promo -

- {#if couponData?.credits} - {campaign.title.replace('VALUE', couponData.credits.toString())} - {:else} - {campaign.title} - {/if} -

+ {#if campaign?.template === 'card'} +
+
+
+ promo +

+ {#if couponData?.credits} + {campaign.title.replace('VALUE', couponData.credits.toString())} + {:else} + {campaign.title} + {/if} +

+
-
+ {/if} {#if selectedOrg?.billingPlan === BillingPlan.PRO}
{:else if selectedOrgId} - +
+ + {#if campaign?.template === 'review' && (campaign?.data?.cta || campaign?.data?.claimed || campaign?.data?.unclaimed)} +
+

{campaign?.data?.cta}

+

+ {#if couponData?.code && couponData?.status === 'active' && campaign?.data?.claimed} + {campaign?.data?.claimed} + {:else if campaign?.data?.unclaimed} + {campaign?.data?.unclaimed} + {/if} +

+
+ {/if} +
+
{/if} diff --git a/src/routes/console/project-[project]/auth/security/+page.svelte b/src/routes/console/project-[project]/auth/security/+page.svelte index f69b91395..0e3ac4f68 100644 --- a/src/routes/console/project-[project]/auth/security/+page.svelte +++ b/src/routes/console/project-[project]/auth/security/+page.svelte @@ -1,5 +1,6 @@ + +
+ + Mock Phone Numbers +

+ Generate fictional numbers to simulate phone verification while testing demo accounts. + A maximum of 10 phone numbers can be generated. +

+ + + {#if numbers?.length > 0} +
    + {#each numbers as number, index} + + + + + + + + {/each} +
+ {#if numbers?.length < 10} + + {/if} + {:else} + { + addPhoneNumber({ + phone: '', + otp: '' + }); + }}>Create a mock phone number + {/if} +
+ + + + +
+
diff --git a/src/routes/console/project-[project]/functions/+layout.ts b/src/routes/console/project-[project]/functions/+layout.ts index 68ecb719d..5be87b9cf 100644 --- a/src/routes/console/project-[project]/functions/+layout.ts +++ b/src/routes/console/project-[project]/functions/+layout.ts @@ -8,15 +8,17 @@ import type { LayoutLoad } from './$types'; export const load: LayoutLoad = async ({ depends }) => { depends(Dependencies.FUNCTION_INSTALLATIONS); - const [runtimesList, installations] = await Promise.all([ + const [runtimesList, installations, specs] = await Promise.all([ sdk.forProject.functions.listRuntimes(), - sdk.forProject.vcs.listInstallations([Query.limit(100)]) + sdk.forProject.vcs.listInstallations([Query.limit(100)]), + sdk.forProject.specsFunctions.getSpecs() ]); return { header: Header, breadcrumbs: Breadcrumbs, runtimesList, - installations + installations, + specs }; }; diff --git a/src/routes/console/project-[project]/functions/+page.svelte b/src/routes/console/project-[project]/functions/+page.svelte index 2a86c9150..7f45d8302 100644 --- a/src/routes/console/project-[project]/functions/+page.svelte +++ b/src/routes/console/project-[project]/functions/+page.svelte @@ -3,10 +3,16 @@ import { page } from '$app/stores'; import { tooltip } from '$lib/actions/tooltip'; import { registerCommands, updateCommandGroupRanks } from '$lib/commandCenter'; - import { CardContainer, Empty, GridItem1, Id, PaginationWithLimit } from '$lib/components'; + import { + CardContainer, + Empty, + GridItem1, + Id, + PaginationWithLimit, + SvgIcon + } from '$lib/components'; import { toLocaleDateTime } from '$lib/helpers/date'; import { Container, ContainerHeader } from '$lib/layout'; - import { app } from '$lib/stores/app'; import { isServiceLimited } from '$lib/stores/billing'; import { marketplace } from '$lib/stores/marketplace.js'; import { organization } from '$lib/stores/organization'; @@ -90,11 +96,7 @@
- technology +
{func.name}
diff --git a/src/routes/console/project-[project]/functions/function-[function]/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/+page.svelte index aa0c3c17b..de49e904b 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/+page.svelte @@ -1,72 +1,119 @@ - {#if $deploymentList?.total} + {#if !data?.deploymentList?.total && !data?.query} + +
+ Create your first deployment to get started. +

+ Learn more about deployments in our Documentation. +

+
+
+ + +
+
+ {:else} {@const activeDeployment = data.activeDeployment} +
Active
- {#if activeDeployment && !$func.live && showAlert} + {#if data?.activeDeployment && !$func.live && showAlert} {/if} {#if activeDeployment} - -
- -
-

Deployment ID

- - - {activeDeployment.$id} - -
-
- - {@const status = activeDeployment.status} - {@const fileSize = humanFileSize(activeDeployment.size)} -
-
-

Build time: {calculateTime(activeDeployment.buildTime)}

-

- Updated: - -

-

Size: {fileSize.value + fileSize.unit}

-

- Source: - -

- {#if $proxyRuleList?.rules?.length} -

- Domains: - -

- {/if} -
-
- - - {activeDeployment.status === 'ready' - ? 'active' - : activeDeployment.status} - - -
-
-
- +
-
-
- {:else if $deploymentList.total} + + {:else if !$deploymentList.total && !data?.query} + +
+ Create your first deployment to get started. +

+ Learn more about deployments in our Documentation. +

+
+
+ + +
+
+ {:else} @@ -180,174 +189,81 @@

- {:else} - -
- - Create your first deployment to get started. - -

- Learn more about deployments in our Documentation. -

-
-
- - -
-
{/if} -
- All +
+ All deployments +
+
+ + + +
+ + {#if $tags?.length} +
+
+ + {/if} +
+
+
+
+ +
+
+
+ + + + + + +
{#if $deploymentList.total} -
- - - Deployment ID - Status - Source - Updated - Build Time - Size - - - - {#each $deploymentList.deployments as deployment, index (deployment.$id)} - {@const status = deployment.status} - - - {deployment.$id} - - - {#if activeDeployment?.$id === deployment?.$id} - active - {:else} - - {status} - - {/if} - - - - - - - - - {#if ['processing', 'building'].includes(deployment.status)} - - {:else} - {calculateTime(deployment.buildTime)} - {/if} - - - - {calculateSize(deployment.size)} - - - - - - - { - selectedDeployment = deployment; - showRedeploy = true; - showDropdown = []; - }}> - Redeploy - - {#if deployment.status === 'ready' && deployment.$id !== $func.deployment} - { - selectedDeployment = deployment; - showActivate = true; - showDropdown = []; - }}> - Activate - - {/if} - - Logs - - { - selectedDeployment = deployment; - showDropdown = []; - showDelete = true; - }}> - Delete - - - - - - {/each} - - -
- {:else} - -
- - You have no deployments. Create one to see it here. - -

- Learn more about deployments in our Documentation. -

+ + {:else if data?.query} + +
+
+ Sorry we couldn't find any deployments +

There are no deployments that match your filters.

+
+
+ +
-
- - -
- +
{/if} - {:else} - -
- Create your first deployment to get started. -

- Learn more about deployments in our Documentation. -

-
-
- - -
-
{/if} {#if selectedDeployment} - - {/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/+page.ts b/src/routes/console/project-[project]/functions/function-[function]/+page.ts index 1d85970ce..02b02627d 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/+page.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/+page.ts @@ -1,8 +1,9 @@ import { Query } from '@appwrite.io/console'; import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; +import { getLimit, getPage, getQuery, pageToOffset } from '$lib/helpers/load'; import { Dependencies, PAGE_LIMIT } from '$lib/constants'; import type { PageLoad } from './$types'; +import { queries, queryParamToMap } from '$lib/components/filters'; export const load: PageLoad = async ({ params, depends, url, route, parent }) => { const data = await parent(); @@ -10,10 +11,14 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => const page = getPage(url); const limit = getLimit(url, route, PAGE_LIMIT); const offset = pageToOffset(page, limit); + const query = getQuery(url); + const parsedQueries = queryParamToMap(query || '[]'); + queries.set(parsedQueries); return { offset, limit, + query, activeDeployment: data.function.deployment ? await sdk.forProject.functions.getDeployment( params.function, @@ -23,7 +28,8 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => deploymentList: await sdk.forProject.functions.listDeployments(params.function, [ Query.limit(limit), Query.offset(offset), - Query.orderDesc('') + Query.orderDesc(''), + ...parsedQueries.values() ]) }; }; diff --git a/src/routes/console/project-[project]/functions/function-[function]/cancel.svelte b/src/routes/console/project-[project]/functions/function-[function]/cancel.svelte new file mode 100644 index 000000000..77f91bca2 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/cancel.svelte @@ -0,0 +1,49 @@ + + + +

Are you sure you want to cancel this deployment?

+ + + + +
diff --git a/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte b/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte index 91507d198..deedf8dee 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/createManual.svelte @@ -1,5 +1,12 @@ @@ -71,13 +83,8 @@ allowedFileExtensions={['gz']} bind:files required={true} /> - - {#if $func.version !== 'v3'} + + {#if $func.version === 'v2'} Build commands now available for functions v3.0 @@ -93,26 +100,35 @@ {:else} - Build settings + Overwrite settings (optional) +

- Overwrite your function configuration for a single deployment or save - commands for future use. + Overwrite your function entrypoint or build commands for a single + deployment or save commands for future use.

+ + + This deployment will be activated after the build is completed. +
{/if} - - This deployment will be activated after the build is completed. - diff --git a/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte index ccaacbe06..50cf9d442 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte @@ -1,27 +1,40 @@ - -
- -
-

Deployment ID

+ + +
+ {#if $deployment.status === 'processing'} + + {/if} - - {$deployment.$id} - -
-
- - {@const status = $deployment.status} - {@const fileSize = humanFileSize($deployment.size)} -
-
-

- Build time: - {#if ['processing', 'building'].includes($deployment.status)} - - {:else} - {calculateTime($deployment.buildTime)} - {/if} -

-

Updated:

-

- Size: - {fileSize.value + fileSize.unit} -

-

- Source: - -

- {#if $proxyRuleList?.rules?.length} -

- Domains: - -

- {/if} -
-
- - {$deployment.status} - -
+ {#if $deployment.status === 'ready'} + + {/if} +
- + - -
-
-
-
-

Build {$func.name}

- {#if $deployment.status === 'building'} - Building... - {:else} - {$deployment.status} - {/if} -
- -
- - - -
-
-
-
{logs}
+
+
+
+
+

Build {$func.name}

+ {#if $deployment.status === 'building'} + Building... + {:else} + {$deployment.status} + {/if}
-
-
- + +
+ + + +
+ +
+
{logs}
+
+
+
+ + {#if !data.activeDeployment} + + Delete deployment +

+ The deployment will be permanently deleted, including all data associated with it. + This action is irreversible. +

+ + +

Last updated: {toLocaleDateTime($func.$updatedAt)}

+
+
+ + + +
+ {/if} + + + + diff --git a/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts b/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts index 41afdcff3..bb5cd33b0 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/deployment-[deployment]/+page.ts @@ -2,10 +2,17 @@ import { sdk } from '$lib/stores/sdk'; import { Dependencies } from '$lib/constants'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ params, depends }) => { +export const load: PageLoad = async ({ params, depends, parent }) => { + const { function: func } = await parent(); depends(Dependencies.DEPLOYMENT); + const deployment = await sdk.forProject.functions.getDeployment( + params.function, + params.deployment + ); + return { - deployment: await sdk.forProject.functions.getDeployment(params.function, params.deployment) + deployment, + activeDeployment: func.deployment === params.deployment }; }; diff --git a/src/routes/console/project-[project]/functions/function-[function]/deploymentCard.svelte b/src/routes/console/project-[project]/functions/function-[function]/deploymentCard.svelte new file mode 100644 index 000000000..693da5950 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/deploymentCard.svelte @@ -0,0 +1,100 @@ + + + +
+ +
+

Deployment ID

+ + + {deployment.$id} + +
+
+ + {@const status = deployment.status} + {@const fileSize = humanFileSize(deployment.size)} +
    +
  • +

    Status

    + + + + +
  • +
  • +

    Build time

    +

    + {calculateTime(deployment.buildTime)} +

    +
  • +
  • +

    Build size

    +

    + {fileSize.value + fileSize.unit} +

    +
  • +
  • +

    Updated

    +

    + +

    +
  • +
+ +
+

Source

+
+ +
+
+ + {#if $proxyRuleList?.rules?.length} +
+

Domains

+ +
+ {/if} +
+ + + + +
+ + diff --git a/src/routes/console/project-[project]/functions/function-[function]/deploymentDomains.svelte b/src/routes/console/project-[project]/functions/function-[function]/deploymentDomains.svelte index 9df7f80cd..68b475340 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/deploymentDomains.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/deploymentDomains.svelte @@ -12,9 +12,10 @@ {domain.rules[0].domain} - +
+ {:else if data?.query} + +
+
+ Sorry we couldn't find any executions +

There are no executions that match your filters.

+
+
+ +
+
+
{:else}
diff --git a/src/routes/console/project-[project]/functions/function-[function]/executions/+page.ts b/src/routes/console/project-[project]/functions/function-[function]/executions/+page.ts index 86ef6c966..2d4d66858 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/executions/+page.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/executions/+page.ts @@ -1,22 +1,29 @@ import { Query } from '@appwrite.io/console'; import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; +import { getLimit, getPage, getQuery, pageToOffset } from '$lib/helpers/load'; import { Dependencies, PAGE_LIMIT } from '$lib/constants'; import type { PageLoad } from './$types'; +import { queries, queryParamToMap } from '$lib/components/filters'; export const load: PageLoad = async ({ params, depends, url, route }) => { depends(Dependencies.EXECUTIONS); const page = getPage(url); const limit = getLimit(url, route, PAGE_LIMIT); const offset = pageToOffset(page, limit); + const query = getQuery(url); + + const parsedQueries = queryParamToMap(query || '[]'); + queries.set(parsedQueries); return { offset, limit, + query, executions: await sdk.forProject.functions.listExecutions(params.function, [ Query.limit(limit), Query.offset(offset), - Query.orderDesc('') + Query.orderDesc(''), + ...parsedQueries.values() ]) }; }; diff --git a/src/routes/console/project-[project]/functions/function-[function]/executions/delete.svelte b/src/routes/console/project-[project]/functions/function-[function]/executions/delete.svelte new file mode 100644 index 000000000..b05f59fb7 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/executions/delete.svelte @@ -0,0 +1,47 @@ + + + +

Are you sure you want to delete this execution?

+ + + + +
diff --git a/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte new file mode 100644 index 000000000..51f6e5b4b --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.svelte @@ -0,0 +1,382 @@ + + + + Execute function - Appwrite + + + + Execute function + +
+ + {#if func?.version === 'v2'} + + + Customizable execution data now available for functions v3.0 + + Update your function version to make use of new features including customizable + HTTP data in your executions. + + + + + + {:else} + + + + +
+

+ Headers + (optional) + +

+ + + {#if headers} + {#each headers as [name, value], index} + + + + + + + + {/each} + {/if} + + +
+ + + +
  • + + {#if isScheduled} + + + + + {/if} + + {isScheduled + ? `Your function will be executed on ${toLocaleDateTime(dateTime?.toString())}` + : 'Your function will be executed immediately'} + +
  • + {/if} +
    + + + +
    +

    Deployment ID

    + + + {func.deployment} + +
    +
      +
    • +

      Status

      +

      + + active + + +

      +
    • +
    • +

      Build time

      +

      + {#if ['processing', 'building'].includes(deployment.status)} + + {:else} + {calculateTime(deployment.buildTime)} + {/if} +

      +
    • +
    • +

      Size

      +

      + {humanFileSize(deployment.size).value + + humanFileSize(deployment.size).unit} +

      +
    • +
    +
    +

    Source

    + + + +
    +
    +

    Domains

    + + + +
    +
    +

    Updated

    + + + +
    +
    +
    +
    + + + + + +
    diff --git a/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.ts b/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.ts new file mode 100644 index 000000000..1d11c6734 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/executions/execute-function/+page.ts @@ -0,0 +1,18 @@ +import { sdk } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params, depends, parent }) => { + const data = await parent(); + depends(Dependencies.DEPLOYMENTS); + + return { + func: data.function, + activeDeployment: data.function.deployment + ? await sdk.forProject.functions.getDeployment( + params.function, + data.function.deployment + ) + : null + }; +}; diff --git a/src/routes/console/project-[project]/functions/function-[function]/executions/table.svelte b/src/routes/console/project-[project]/functions/function-[function]/executions/table.svelte new file mode 100644 index 000000000..b440a8105 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/executions/table.svelte @@ -0,0 +1,152 @@ + + + + + {#each columns as column} + {#if column.show} + {column.title} + {/if} + {/each} + + + + {#each data.executions.executions as execution, index (execution.$id)} + + {#each columns as column} + {#if column.show} + {#if column.id === '$id'} + {#key column.id} + + {execution.$id} + + {/key} + {:else if column.id === 'status'} + + {@const status = execution.status} +
    + + {#if status === 'scheduled'} + +
    +
    + {:else if column.id === '$createdAt'} + + {timeFromNow(execution.$createdAt)} + + {:else if column.id === 'trigger'} + + + {execution.trigger} + + + {:else if column.id === 'requestMethod'} + + {execution.requestMethod} + + {:else if column.id === 'responseStatusCode'} + + {execution.responseStatusCode} + + {:else if column.id === 'requestPath'} + + {execution.requestPath} + + {:else if column.id === 'duration'} + + {calculateTime(execution.duration)} + + {/if} + {/if} + {/each} + + + + + { + showDropdown = []; + showLogs(execution); + }}> + Logs + + { + selectedExecution = execution; + showDropdown = []; + showDelete = true; + }}> + Delete + + + + +
    + {/each} +
    +
    + +{#if selectedExecution} + +{/if} diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte index db5149a6a..dd2e6e69e 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/+page.svelte @@ -1,23 +1,26 @@ @@ -28,9 +30,8 @@ + href={`${base}/console/project-${$project.$id}/functions/function-${$func.$id}/executions/execute-function`}> + Execute now + diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte index 6a8dc10d4..cd43beb40 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/gitConfigurationModal.svelte @@ -64,6 +64,7 @@ $func.logging || undefined, $func.entrypoint, $func.commands || undefined, + $func.scopes || undefined, selectedInstallationId, selectedRepoId, selectedBranch, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte index df247fcc8..132520cf3 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateConfiguration.svelte @@ -130,6 +130,7 @@ $func.logging || undefined, entrypoint, commands, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, selectedBranch, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateEvents.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateEvents.svelte index c2c359bfd..fe63e7726 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateEvents.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateEvents.svelte @@ -46,6 +46,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateLogging.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateLogging.svelte index 2f6e4afb8..59a722f0c 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateLogging.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateLogging.svelte @@ -38,6 +38,7 @@ functionLogging, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte index 8f44fd549..3051debe4 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateName.svelte @@ -36,6 +36,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte index 8af6ef6e3..41a8ecbe3 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updatePermissions.svelte @@ -40,6 +40,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateRuntime.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateRuntime.svelte index a4a2f806c..b88055ddf 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateRuntime.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateRuntime.svelte @@ -10,23 +10,47 @@ import { onMount } from 'svelte'; import { func } from '../store'; import InputSelect from '$lib/elements/forms/inputSelect.svelte'; - import { runtimesList } from '../../store'; + import { runtimesList, specs } from '../../store'; import { isValueOfStringEnum } from '$lib/helpers/types'; import { Runtime } from '@appwrite.io/console'; const functionId = $page.params.function; let runtime: string = null; + let memory: number = null; + let cpus: number = null; let options = []; + let cpuOptions = []; + let memoryOptions = []; onMount(async () => { runtime ??= $func.runtime; + memory ??= $func.memory; + cpus ??= $func.cpus; let runtimes = await $runtimesList; + let allowedSpecs = await $specs; options = runtimes.runtimes.map((runtime) => ({ label: `${runtime.name} - ${runtime.version}`, value: runtime.$id })); + + memoryOptions = allowedSpecs.memory.map((memory) => + memory > 1024 + ? { + label: `${memory / 1024} GB`, + value: memory + } + : { + label: `${memory} MB`, + value: memory + } + ); + + cpuOptions = allowedSpecs.cpus.map((cpu) => ({ + label: cpu === 1 ? `${cpu} CPU Cores` : `${cpu} CPU Core`, + value: cpu + })); }); async function updateRuntime() { @@ -34,7 +58,7 @@ if (!isValueOfStringEnum(Runtime, runtime)) { throw new Error(`Invalid runtime: ${runtime}`); } - await sdk.forProject.functions.update( + await sdk.forProject.specsFunctions.update( functionId, $func.name, runtime, @@ -46,15 +70,18 @@ $func.logging || undefined, $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.providerRootDirectory || undefined, + cpus, + memory ); await invalidate(Dependencies.FUNCTION); addNotification({ - message: 'Runtime has been updated', + message: 'Runtime settings have been updated', type: 'success' }); trackEvent(Submit.FunctionUpdateName); @@ -66,6 +93,9 @@ trackError(error, Submit.FunctionUpdateName); } } + + $: isUpdateButtonEnabled = + runtime !== $func?.runtime || memory !== $func?.memory || cpus !== $func?.cpus;
    @@ -82,11 +112,27 @@ {options} required hideRequired /> + + - + diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte index ecd707039..d59ccecf8 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateSchedule.svelte @@ -36,6 +36,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateScopes.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateScopes.svelte new file mode 100644 index 000000000..4e1d49500 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateScopes.svelte @@ -0,0 +1,92 @@ + + +
    + + Scopes +

    + Select scopes to grant the dynamic key generated temporarily for your function. It is + best practice to allow only necessary permissions. Learn more. +

    + + {#if functionScopes !== null} + + {/if} + + + + + +
    + diff --git a/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte b/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte index c36303279..9c4f07753 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte +++ b/src/routes/console/project-[project]/functions/function-[function]/settings/updateTimeout.svelte @@ -36,6 +36,7 @@ $func.logging || undefined, $func.entrypoint || undefined, $func.commands || undefined, + $func.scopes || undefined, $func.installationId || undefined, $func.providerRepositoryId || undefined, $func.providerBranch || undefined, diff --git a/src/routes/console/project-[project]/functions/function-[function]/store.ts b/src/routes/console/project-[project]/functions/function-[function]/store.ts index 0bc01a1d4..18f03dd31 100644 --- a/src/routes/console/project-[project]/functions/function-[function]/store.ts +++ b/src/routes/console/project-[project]/functions/function-[function]/store.ts @@ -1,8 +1,9 @@ import { page } from '$app/stores'; import { derived, writable, type Writable } from 'svelte/store'; import type { Models } from '@appwrite.io/console'; +import type { Func } from '$lib/sdk/functionsSpec'; -export const func = derived(page, ($page) => $page.data.function as Models.Function); +export const func = derived(page, ($page) => $page.data.function as Func); export const deploymentList = derived( page, ($page) => $page.data.deploymentList as Models.DeploymentList @@ -11,8 +12,8 @@ export const proxyRuleList = derived( page, ($page) => $page.data.proxyRuleList as Models.ProxyRuleList ); -export const execute: Writable = writable(); -export const showFunctionExecute: Writable = writable(false); +export const execute: Writable = writable(); //TODO Remove +export const showFunctionExecute: Writable = writable(false); //TODO Remove export const repositories: Writable<{ search: string; diff --git a/src/routes/console/project-[project]/functions/function-[function]/table.svelte b/src/routes/console/project-[project]/functions/function-[function]/table.svelte new file mode 100644 index 000000000..941c09242 --- /dev/null +++ b/src/routes/console/project-[project]/functions/function-[function]/table.svelte @@ -0,0 +1,192 @@ + + + + + {#each columns as column} + {#if column.show} + {column.title} + {/if} + {/each} + + + + {#each data.deploymentList.deployments as deployment, index (deployment.$id)} + + {#each columns as column} + {#if column.show} + {#if column.id === '$id'} + {#key column.id} + + {deployment.$id} + + {/key} + {:else if column.id === 'status'} + + {@const status = deployment.status} + {#if data?.activeDeployment?.$id === deployment?.$id} + + + {:else} + + {status} + + {/if} + + {:else if column.id === 'type'} + + + + {:else if column.id === '$updatedAt'} + + + + {:else if column.id === 'buildTime'} + + {#if ['processing', 'building'].includes(deployment.status)} + + {:else} + {calculateTime(deployment.buildTime)} + {/if} + + {:else if column.id === 'size'} + + {calculateSize(deployment.size)} + + {/if} + {/if} + {/each} + + + + + { + selectedDeployment = deployment; + showRedeploy = true; + showDropdown = []; + }}> + Redeploy + + {#if deployment.status === 'ready' && deployment.$id !== $func.deployment} + { + selectedDeployment = deployment; + showActivate = true; + showDropdown = []; + }}> + Activate + + {/if} + + Logs + + {#if deployment.status === 'ready'} + (showDropdown[index] = false)}> + Download + + {/if} + {#if deployment.status === 'processing' || deployment.status === 'building'} + { + selectedDeployment = deployment; + showDropdown = []; + showCancel = true; + }}> + Cancel + + {/if} + { + selectedDeployment = deployment; + showDropdown = []; + showDelete = true; + }}> + Delete + + + + + + {/each} + + + +{#if selectedDeployment} + + + + +{/if} diff --git a/src/routes/console/project-[project]/functions/store.ts b/src/routes/console/project-[project]/functions/store.ts index 3acf62136..396c5d584 100644 --- a/src/routes/console/project-[project]/functions/store.ts +++ b/src/routes/console/project-[project]/functions/store.ts @@ -1,12 +1,15 @@ import { page } from '$app/stores'; import { derived } from 'svelte/store'; import type { Models } from '@appwrite.io/console'; +import type { Specs } from '$lib/sdk/functionsSpec'; export const runtimesList = derived( page, async ($page) => (await $page.data.runtimesList) as Models.RuntimeList ); +export const specs = derived(page, async ($page) => (await $page.data.specs) as Specs); + export const baseRuntimesList = derived(runtimesList, async ($runtimesList) => { const baseRuntimes = new Map(); for (const runtime of (await $runtimesList).runtimes) { diff --git a/static/icons/dark/color/go.svg b/static/icons/dark/color/go.svg new file mode 100644 index 000000000..ec7ff2412 --- /dev/null +++ b/static/icons/dark/color/go.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/icons/dark/grayscale/go.svg b/static/icons/dark/grayscale/go.svg new file mode 100644 index 000000000..245dc1c89 --- /dev/null +++ b/static/icons/dark/grayscale/go.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/icons/light/color/go.svg b/static/icons/light/color/go.svg new file mode 100644 index 000000000..ec7ff2412 --- /dev/null +++ b/static/icons/light/color/go.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/icons/light/grayscale/go.svg b/static/icons/light/grayscale/go.svg new file mode 100644 index 000000000..245dc1c89 --- /dev/null +++ b/static/icons/light/grayscale/go.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/static/images/campaigns/FusionVC/footer/dark.png b/static/images/campaigns/FusionVC/footer/dark.png new file mode 100644 index 000000000..6fe0f03b0 Binary files /dev/null and b/static/images/campaigns/FusionVC/footer/dark.png differ diff --git a/static/images/campaigns/FusionVC/footer/light.png b/static/images/campaigns/FusionVC/footer/light.png new file mode 100644 index 000000000..a21263326 Binary files /dev/null and b/static/images/campaigns/FusionVC/footer/light.png differ diff --git a/static/images/campaigns/FusionVC/reviewers/1.jpeg b/static/images/campaigns/FusionVC/reviewers/1.jpeg new file mode 100644 index 000000000..db56c928c Binary files /dev/null and b/static/images/campaigns/FusionVC/reviewers/1.jpeg differ diff --git a/static/images/campaigns/JSMastery/reviewers/js_mastery_reviewer_1.png b/static/images/campaigns/JSMastery/reviewers/js_mastery_reviewer_1.png new file mode 100644 index 000000000..ce5189b59 Binary files /dev/null and b/static/images/campaigns/JSMastery/reviewers/js_mastery_reviewer_1.png differ diff --git a/static/images/campaigns/StartupsProgram/reviewers/1.jpeg b/static/images/campaigns/StartupsProgram/reviewers/1.jpeg new file mode 100644 index 000000000..db56c928c Binary files /dev/null and b/static/images/campaigns/StartupsProgram/reviewers/1.jpeg differ diff --git a/static/images/campaigns/carbon/reviewers/1.jpeg b/static/images/campaigns/carbon/reviewers/1.jpeg new file mode 100644 index 000000000..db56c928c Binary files /dev/null and b/static/images/campaigns/carbon/reviewers/1.jpeg differ