Merge branch 'main' into 'spreadsheet'.

This commit is contained in:
Darshan
2025-07-29 19:52:37 +05:30
36 changed files with 474 additions and 305 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
build-args: |
"PUBLIC_CONSOLE_MODE=cloud"
"PUBLIC_CONSOLE_FEATURE_FLAGS="
"PUBLIC_CONSOLE_FEATURE_FLAGS=sites"
"PUBLIC_APPWRITE_MULTI_REGION=true"
"PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}"
"PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY }}"
+5 -5
View File
@@ -48,8 +48,8 @@
"tippy.js": "^6.3.7"
},
"devDependencies": {
"@eslint/compat": "^1.2.7",
"@eslint/js": "^9.24.0",
"@eslint/compat": "^1.3.1",
"@eslint/js": "^9.31.0",
"@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.86.5",
"@playwright/test": "^1.51.1",
@@ -58,20 +58,20 @@
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/svelte": "^5.2.4",
"@testing-library/svelte": "^5.2.8",
"@testing-library/user-event": "^14.6.1",
"@types/deep-equal": "^1.0.4",
"@types/prismjs": "^1.26.5",
"@types/remarkable": "^2.0.8",
"@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0",
"@vitest/ui": "^3.0.9",
"@vitest/ui": "^3.2.4",
"color": "^5.0.0",
"eslint": "^9.31.0",
"eslint-config-prettier": "^10.1.0",
"eslint-plugin-svelte": "^3.3.3",
"globals": "^16.0.0",
"jsdom": "^26.0.0",
"jsdom": "^26.1.0",
"kleur": "^4.1.5",
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
+69 -98
View File
@@ -85,11 +85,11 @@ importers:
version: 6.3.7
devDependencies:
'@eslint/compat':
specifier: ^1.2.7
version: 1.2.7(eslint@9.31.0)
specifier: ^1.3.1
version: 1.3.1(eslint@9.31.0)
'@eslint/js':
specifier: ^9.24.0
version: 9.24.0
specifier: ^9.31.0
version: 9.31.0
'@melt-ui/pp':
specifier: ^0.3.2
version: 0.3.2(@melt-ui/svelte@0.86.5(svelte@5.25.3))(svelte@5.25.3)
@@ -115,8 +115,8 @@ importers:
specifier: ^6.6.3
version: 6.6.3
'@testing-library/svelte':
specifier: ^5.2.4
version: 5.2.7(svelte@5.25.3)(vite@6.2.3(@types/node@22.13.14)(sass@1.86.0))(vitest@3.0.9)
specifier: ^5.2.8
version: 5.2.8(svelte@5.25.3)(vite@6.2.3(@types/node@22.13.14)(sass@1.86.0))(vitest@3.0.9)
'@testing-library/user-event':
specifier: ^14.6.1
version: 14.6.1(@testing-library/dom@10.4.0)
@@ -136,8 +136,8 @@ importers:
specifier: ^8.28.0
version: 8.28.0(eslint@9.31.0)(typescript@5.8.2)
'@vitest/ui':
specifier: ^3.0.9
version: 3.0.9(vitest@3.0.9)
specifier: ^3.2.4
version: 3.2.4(vitest@3.0.9)
color:
specifier: ^5.0.0
version: 5.0.0
@@ -154,8 +154,8 @@ importers:
specifier: ^16.0.0
version: 16.0.0
jsdom:
specifier: ^26.0.0
version: 26.0.0
specifier: ^26.1.0
version: 26.1.0
kleur:
specifier: ^4.1.5
version: 4.1.5
@@ -197,7 +197,7 @@ importers:
version: 6.2.3(@types/node@22.13.14)(sass@1.86.0)
vitest:
specifier: ^3.0.0
version: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.9)(jsdom@26.0.0)(sass@1.86.0)
version: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.86.0)
packages:
@@ -548,11 +548,11 @@ packages:
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/compat@1.2.7':
resolution: {integrity: sha512-xvv7hJE32yhegJ8xNAnb62ggiAwTYHBpUCWhRxEj/ksvgDJuSXfoDkBcRYaYNFiJ+jH0IE3K16hd+xXzhBgNbg==}
'@eslint/compat@1.3.1':
resolution: {integrity: sha512-k8MHony59I5EPic6EQTCNOuPoVBnoYXkP+20xvwFjN7t0qI3ImyvyBgg+hIVPwC8JaxVjjUZld+cLfBLFDLucg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^9.10.0
eslint: ^8.40 || 9
peerDependenciesMeta:
eslint:
optional: true
@@ -573,10 +573,6 @@ packages:
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.24.0':
resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.31.0':
resolution: {integrity: sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1288,8 +1284,8 @@ packages:
resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
'@testing-library/svelte@5.2.7':
resolution: {integrity: sha512-aGhUaFmEXEVost4QOsbHUUbHLwi7ZZRRxAHFDO2Cmr0BZD3/3+XvaYEPq70Rdw0NRNjdqZHdARBEcrCOkPuAqw==}
'@testing-library/svelte@5.2.8':
resolution: {integrity: sha512-ucQOtGsJhtawOEtUmbR4rRh53e6RbM1KUluJIXRmh6D4UzxR847iIqqjRtg9mHNFmGQ8Vkam9yVcR5d1mhIHKA==}
engines: {node: '>= 10'}
peerDependencies:
svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0
@@ -1484,6 +1480,9 @@ packages:
'@vitest/pretty-format@3.0.9':
resolution: {integrity: sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==}
'@vitest/pretty-format@3.2.4':
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
'@vitest/runner@3.0.9':
resolution: {integrity: sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==}
@@ -1493,14 +1492,17 @@ packages:
'@vitest/spy@3.0.9':
resolution: {integrity: sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==}
'@vitest/ui@3.0.9':
resolution: {integrity: sha512-FpZD4aIv/qNpwkV3XbLV6xldWFHMgoNWAJEgg5GmpObmAOLAErpYjew9dDwXdYdKOS3iZRKdwI+P3JOJcYeUBg==}
'@vitest/ui@3.2.4':
resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==}
peerDependencies:
vitest: 3.0.9
vitest: 3.2.4
'@vitest/utils@3.0.9':
resolution: {integrity: sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==}
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
'@vue/compiler-core@3.5.13':
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
@@ -1631,9 +1633,6 @@ packages:
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
engines: {node: '>=4'}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
autolinker@3.16.2:
resolution: {integrity: sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==}
@@ -1756,10 +1755,6 @@ packages:
resolution: {integrity: sha512-16BlyiuyLq3MLxpRWyOTiWsO3ii/eLQLJUQXBSNcxMBBSnyt1ee9YUdaozQp03ifwm5woztEZGDbk9RGVuCsdw==}
engines: {node: '>=18'}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
@@ -1976,10 +1971,6 @@ packages:
delaunator@5.0.1:
resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@@ -2043,10 +2034,6 @@ packages:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.25.1:
resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==}
engines: {node: '>=18'}
@@ -2189,6 +2176,14 @@ packages:
picomatch:
optional: true
fdir@6.4.6:
resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
fflate@0.8.2:
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
@@ -2218,10 +2213,6 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
form-data@4.0.2:
resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
engines: {node: '>= 6'}
forwarded-parse@2.1.2:
resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==}
@@ -2491,8 +2482,8 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
jsdom@26.0.0:
resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==}
jsdom@26.1.0:
resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^3.0.0
@@ -2560,6 +2551,9 @@ packages:
loupe@3.1.3:
resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
loupe@3.2.0:
resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
@@ -2621,14 +2615,6 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
@@ -3262,8 +3248,8 @@ packages:
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
tinyglobby@0.2.12:
resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
tinypool@1.0.2:
@@ -3914,7 +3900,7 @@ snapshots:
'@eslint-community/regexpp@4.12.1': {}
'@eslint/compat@1.2.7(eslint@9.31.0)':
'@eslint/compat@1.3.1(eslint@9.31.0)':
optionalDependencies:
eslint: 9.31.0
@@ -3946,8 +3932,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@eslint/js@9.24.0': {}
'@eslint/js@9.31.0': {}
'@eslint/object-schema@2.1.6': {}
@@ -4773,13 +4757,13 @@ snapshots:
lodash: 4.17.21
redent: 3.0.0
'@testing-library/svelte@5.2.7(svelte@5.25.3)(vite@6.2.3(@types/node@22.13.14)(sass@1.86.0))(vitest@3.0.9)':
'@testing-library/svelte@5.2.8(svelte@5.25.3)(vite@6.2.3(@types/node@22.13.14)(sass@1.86.0))(vitest@3.0.9)':
dependencies:
'@testing-library/dom': 10.4.0
svelte: 5.25.3
optionalDependencies:
vite: 6.2.3(@types/node@22.13.14)(sass@1.86.0)
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.9)(jsdom@26.0.0)(sass@1.86.0)
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.86.0)
'@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)':
dependencies:
@@ -5023,6 +5007,10 @@ snapshots:
dependencies:
tinyrainbow: 2.0.0
'@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
'@vitest/runner@3.0.9':
dependencies:
'@vitest/utils': 3.0.9
@@ -5038,16 +5026,16 @@ snapshots:
dependencies:
tinyspy: 3.0.2
'@vitest/ui@3.0.9(vitest@3.0.9)':
'@vitest/ui@3.2.4(vitest@3.0.9)':
dependencies:
'@vitest/utils': 3.0.9
'@vitest/utils': 3.2.4
fflate: 0.8.2
flatted: 3.3.3
pathe: 2.0.3
sirv: 3.0.1
tinyglobby: 0.2.12
tinyglobby: 0.2.14
tinyrainbow: 2.0.0
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.9)(jsdom@26.0.0)(sass@1.86.0)
vitest: 3.0.9(@types/node@22.13.14)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.86.0)
'@vitest/utils@3.0.9':
dependencies:
@@ -5055,6 +5043,12 @@ snapshots:
loupe: 3.1.3
tinyrainbow: 2.0.0
'@vitest/utils@3.2.4':
dependencies:
'@vitest/pretty-format': 3.2.4
loupe: 3.2.0
tinyrainbow: 2.0.0
'@vue/compiler-core@3.5.13':
dependencies:
'@babel/parser': 7.27.0
@@ -5206,8 +5200,6 @@ snapshots:
dependencies:
tslib: 2.8.1
asynckit@0.4.0: {}
autolinker@3.16.2:
dependencies:
tslib: 2.8.1
@@ -5340,10 +5332,6 @@ snapshots:
color-convert: 3.1.0
color-string: 2.0.1
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
comma-separated-tokens@2.0.3: {}
commander@7.2.0: {}
@@ -5588,8 +5576,6 @@ snapshots:
dependencies:
robust-predicates: 3.0.2
delayed-stream@1.0.0: {}
dequal@2.0.3: {}
detect-libc@1.0.3:
@@ -5648,13 +5634,6 @@ snapshots:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild@0.25.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.1
@@ -5836,6 +5815,10 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
fdir@6.4.6(picomatch@4.0.2):
optionalDependencies:
picomatch: 4.0.2
fflate@0.8.2: {}
file-entry-cache@8.0.0:
@@ -5866,13 +5849,6 @@ snapshots:
dependencies:
is-callable: 1.2.7
form-data@4.0.2:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
mime-types: 2.1.35
forwarded-parse@2.1.2: {}
framesync@6.1.2:
@@ -6140,12 +6116,11 @@ snapshots:
dependencies:
argparse: 2.0.1
jsdom@26.0.0:
jsdom@26.1.0:
dependencies:
cssstyle: 4.3.0
data-urls: 5.0.0
decimal.js: 10.5.0
form-data: 4.0.2
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
@@ -6211,6 +6186,8 @@ snapshots:
loupe@3.1.3: {}
loupe@3.2.0: {}
lru-cache@10.4.3: {}
lru-cache@5.1.1:
@@ -6279,12 +6256,6 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
min-indent@1.0.1: {}
minimatch@3.1.2:
@@ -6905,9 +6876,9 @@ snapshots:
tinyexec@0.3.2: {}
tinyglobby@0.2.12:
tinyglobby@0.2.14:
dependencies:
fdir: 6.4.3(picomatch@4.0.2)
fdir: 6.4.6(picomatch@4.0.2)
picomatch: 4.0.2
tinypool@1.0.2: {}
@@ -7071,7 +7042,7 @@ snapshots:
optionalDependencies:
vite: 6.2.3(@types/node@22.13.14)(sass@1.86.0)
vitest@3.0.9(@types/node@22.13.14)(@vitest/ui@3.0.9)(jsdom@26.0.0)(sass@1.86.0):
vitest@3.0.9(@types/node@22.13.14)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.86.0):
dependencies:
'@vitest/expect': 3.0.9
'@vitest/mocker': 3.0.9(vite@6.2.3(@types/node@22.13.14)(sass@1.86.0))
@@ -7095,8 +7066,8 @@ snapshots:
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.13.14
'@vitest/ui': 3.0.9(vitest@3.0.9)
jsdom: 26.0.0
'@vitest/ui': 3.2.4(vitest@3.0.9)
jsdom: 26.1.0
transitivePeerDependencies:
- jiti
- less
+9 -4
View File
@@ -103,6 +103,9 @@
isLoadingProjects = true;
// null on non-org/project path like `onboarding`.
loadedProjects = (await projects) ?? loadedProjects;
for (const project of loadedProjects.projects) {
project.region ??= 'default';
}
isLoadingProjects = false;
const createProjectItem = {
@@ -112,10 +115,12 @@
};
if (loadedProjects.total > 1 && selectedOrg) {
const projectLinks = loadedProjects.projects.slice(0, 4).map((project) => ({
name: project.name,
href: `${base}/project-${project.region}-${project.$id}/overview/platforms`
}));
const projectLinks = loadedProjects.projects.slice(0, 4).map((project) => {
return {
name: project.name,
href: `${base}/project-${project.region}-${project.$id}/overview/platforms`
};
});
if (loadedProjects.projects.length > 4) {
projectLinks.push({
+4 -4
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Alert } from '$lib/components';
import { Alert } from '@appwrite.io/pink-svelte';
import { onMount } from 'svelte';
import Form from '$lib/elements/forms/form.svelte';
import { Click, trackEvent } from '$lib/actions/analytics';
@@ -112,14 +112,14 @@
<div class="modal-content">
<div class="modal-content-spacer u-flex-vertical u-gap-24 u-width-full-line">
{#if error}
<Alert
<Alert.Inline
status="warning"
dismissible
type="warning"
on:dismiss={() => {
error = null;
}}>
{error}
</Alert>
</Alert.Inline>
{/if}
<slot />
</div>
+54 -52
View File
@@ -8,41 +8,58 @@
InputSelectCheckbox,
InputDateTime
} from '$lib/elements/forms';
import { createEventDispatcher, onMount } from 'svelte';
import { operators, addFilter, queries, type TagValue } from './store';
import { onMount, createEventDispatcher } from 'svelte';
import { operators, addFilter, queries, tags } from './store';
import type { Column } from '$lib/helpers/types';
import type { Writable } from 'svelte/store';
import { TagList } from '.';
import { Icon, Layout } from '@appwrite.io/pink-svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
// 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<Column[]>;
export let columnId: string | null = null;
export let arrayValues: string[] = [];
export let operatorKey: string | null = null;
export let singleCondition = false;
let {
value = $bindable(null),
columns,
columnId = $bindable(null),
arrayValues = $bindable([]),
operatorKey = $bindable(null),
singleCondition = false
}: {
// We cast to any to not cause type errors in the input components
/* eslint @typescript-eslint/no-explicit-any: 'off' */
value?: any;
columns: Writable<Column[]>;
columnId?: string | null;
arrayValues?: string[];
operatorKey?: string | null;
singleCondition?: boolean;
} = $props();
$: column = $columns.find((c) => c.id === columnId) as Column;
$: operatorsForColumn = Object.entries(operators)
.filter(([, v]) => v.types.includes(column?.type))
.map(([k]) => ({
label: k,
value: k
let columnsArray = $derived($columns);
let column = $derived(columnsArray.find((c) => c.id === columnId));
let operatorsForColumn = $derived.by(() => {
if (!column?.type) return [];
return Object.entries(operators)
.filter(([, v]) => v.types.includes(column.type))
.map(([k]) => ({ label: k, value: k }));
});
let operator = $derived(operatorKey ? operators[operatorKey] : null);
let isDisabled = $derived(!operator);
let appliedTags = $derived($tags);
let columnOptions = $derived.by(() =>
columnsArray.filter((c) => c.filter !== false).map((c) => ({ label: c.title, value: c.id }))
);
let enumOptions = $derived.by(() => {
if (!column?.elements) return [];
return column.elements.map((e) => ({ label: e?.label ?? e, value: e?.value ?? e }));
});
let enumOptionsWithChecked = $derived.by(() => {
if (!column?.elements) return [];
return column.elements.map((e) => ({
label: e?.label ?? e,
value: e?.value ?? e,
checked: arrayValues.includes(e?.value ?? e)
}));
$: operator = operatorKey ? operators[operatorKey] : null;
$: {
columnId;
operatorKey = null;
}
$: isDisabled = !operator;
let localTags: TagValue[] = [];
});
onMount(() => {
value = column?.array ? [] : null;
@@ -52,22 +69,19 @@
}
});
const dispatch = createEventDispatcher<{ clear: void; apply: { applied: number } }>();
function addFilterAndReset() {
addFilter($columns, columnId, operatorKey, value, arrayValues);
addFilter(columnsArray, columnId, operatorKey, value, arrayValues);
columnId = null;
operatorKey = null;
value = null;
arrayValues = [];
dispatch('apply', { applied: appliedTags.length });
if (singleCondition) {
queries.apply();
}
}
const dispatch = createEventDispatcher<{
clear: void;
apply: { applied: number };
}>();
dispatch('apply', { applied: localTags.length });
</script>
<div>
@@ -75,12 +89,7 @@
<Layout.Stack gap="s" direction="row" alignItems="flex-start">
<InputSelect
id="column"
options={$columns
.filter((c) => c.filter !== false)
.map((c) => ({
label: c.title,
value: c.id
}))}
options={columnOptions}
placeholder="Select column"
bind:value={columnId} />
<InputSelect
@@ -97,11 +106,7 @@
name="value"
bind:tags={arrayValues}
placeholder="Select value"
options={column?.elements?.map((e) => ({
label: e?.label ?? e,
value: e?.value ?? e,
checked: arrayValues.includes(e?.value ?? e)
}))}>
options={enumOptionsWithChecked}>
</InputSelectCheckbox>
{:else}
<InputTags
@@ -117,10 +122,7 @@
id="value"
bind:value
placeholder="Select value"
options={column?.elements?.map((e) => ({
label: e?.label ?? e,
value: e?.value ?? e
}))} />
options={enumOptions} />
{:else if column.type === 'integer' || column.type === 'double'}
<InputNumber id="value" bind:value placeholder="Enter value" />
{:else if column.type === 'boolean'}
@@ -131,7 +133,7 @@
options={[
{ label: 'True', value: true },
{ label: 'False', value: false }
].filter(Boolean)}
]}
bind:value />
{:else if column.type === 'datetime'}
{#key value}
@@ -151,10 +153,10 @@
{/if}
</form>
{#if !singleCondition}
{#if !singleCondition && appliedTags.length > 0}
<ul class="u-flex u-flex-wrap u-cross-center u-gap-8 u-margin-block-start-16 tags">
<TagList
tags={localTags}
tags={appliedTags}
on:remove={(e) => {
queries.removeFilter(e.detail);
queries.apply();
@@ -16,17 +16,17 @@
let show = false;
async function loadBranches() {
const repo = await sdk
.forProject(page.params.region, page.params.project)
.vcs.getRepository(installationId, repositoryId);
branch = repo.defaultBranch ?? 'main';
const { branches } = await sdk
.forProject(page.params.region, page.params.project)
.vcs.listRepositoryBranches(installationId, repositoryId);
const sorted = sortBranches(branches);
branch = sorted[0]?.name ?? null;
if (!branch) {
branch = 'main';
}
return sorted;
return sortBranches(branches);
}
</script>
+7 -6
View File
@@ -1,7 +1,8 @@
<script lang="ts">
import { Alert, DropList } from '$lib/components';
import { DropList } from '$lib/components';
import { BillingPlan } from '$lib/constants';
import { Link, Pill } from '$lib/elements';
import { Alert } from '@appwrite.io/pink-svelte';
import {
checkForProjectLimitation,
checkForUsageFees,
@@ -22,7 +23,7 @@
export let title: string;
export let serviceId = title.toLocaleLowerCase() as PlanServices;
export let total: number = null;
export let alertType: 'info' | 'success' | 'warning' | 'error' | 'default' = 'warning';
export let alertType: 'info' | 'success' | 'warning' | 'error' = 'warning';
export let showAlert = true;
export let buttonText: string = null;
@@ -95,16 +96,16 @@
{#if services.length}
<slot name="alert" {limit} {tier} {title} {upgradeMethod} {hasUsageFees} {services}>
{#if $organization?.billingPlan !== BillingPlan.FREE && hasUsageFees}
<Alert type="info" isStandalone>
<Alert.Inline status="info">
<span class="text">
You've reached the {services} limit for the {tier} plan.
<Link on:mousedown={() => ($showUsageRatesModal = true)}
>Excess usage fees will apply</Link
>.
</span>
</Alert>
</Alert.Inline>
{:else}
<Alert type={alertType} isStandalone>
<Alert.Inline status={alertType}>
<span class="text">
You've reached the {services} limit for the {tier} plan. <Link
href={$upgradeURL}
@@ -112,7 +113,7 @@
eventData={{ from: 'event', source: 'inline_alert' }}>Upgrade</Link> your
organization for additional resources.
</span>
</Alert>
</Alert.Inline>
{/if}
</slot>
{/if}
+3
View File
@@ -37,6 +37,9 @@ export const load: LayoutLoad = async ({ depends, parent }) => {
Query.equal('teamId', currentOrgId),
Query.limit(1000) // Get all projects for organization
]);
for (const project of projects.projects) {
project.region ??= 'default';
}
} catch (e) {
// Handle error silently - projects might not be accessible
projects = {};
@@ -1,5 +1,5 @@
<script lang="ts">
import { Alert } from '$lib/components';
import { Alert } from '@appwrite.io/pink-svelte';
import type { EstimationDeleteOrganization } from '$lib/sdk/billing';
import InvoicesTable from './invoicesTable.svelte';
export let estimation: EstimationDeleteOrganization;
@@ -7,10 +7,10 @@
{#if estimation}
{#if estimation.unpaidInvoices?.length > 0}
<Alert type="warning">
<Alert.Inline status="warning">
This organization has unresolved invoices that must be settled before it can be deleted.
Please review and resolve these invoices to proceed.
</Alert>
</Alert.Inline>
<InvoicesTable invoices={estimation.unpaidInvoices} showActions={false} />
{/if}
@@ -16,6 +16,7 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => {
depends(Dependencies.PROJECT);
const project = await sdk.forConsole.projects.get(params.project);
project.region ??= 'default';
// fast path without a network call!
let organization = (organizations as OrganizationList)?.teams?.find(
@@ -44,6 +44,12 @@
<Id value={'{{user}}'}>{'{{user}}'}</Id>
<Id value={'{{project}}'}>{'{{project}}'}</Id>
<Id value={'{{otp}}'}>{'{{otp}}'}</Id>
<!-- START: for client info -->
<Id value={'{{agentClient}}'}>{'{{agentClient}}'}</Id>
<Id value={'{{agentDevice}}'}>{'{{agentDevice}}'}</Id>
<Id value={'{{agentOs}}'}>{'{{agentOs}}'}</Id>
<!-- END: for client info -->
</EmailTemplate>
</Layout.Stack>
</Card.Base>
@@ -45,6 +45,12 @@
<Id value={'{{user}}'}>{'{{user}}'}</Id>
<Id value={'{{project}}'}>{'{{project}}'}</Id>
<Id value={'{{redirect}}'}>{'{{redirect}}'}</Id>
<!-- START: for client info -->
<Id value={'{{agentClient}}'}>{'{{agentClient}}'}</Id>
<Id value={'{{agentDevice}}'}>{'{{agentDevice}}'}</Id>
<Id value={'{{agentOs}}'}>{'{{agentOs}}'}</Id>
<!-- END: for client info -->
</EmailTemplate>
</Layout.Stack>
</Card.Base>
@@ -0,0 +1,56 @@
<script lang="ts">
import { loadEmailTemplate } from './+page.svelte';
import EmailTemplate from './emailTemplate.svelte';
import LocaleOptions from './localeOptions.svelte';
import { baseEmailTemplate, emailTemplate } from './store';
import { page } from '$app/state';
import { addNotification } from '$lib/stores/notifications';
import { Id } from '$lib/components';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Layout, Card } from '@appwrite.io/pink-svelte';
export let loading = false;
let locale = 'en';
let isUpdating = false;
const projectId = page.params.project;
async function onLocaleChange() {
const timeout = setTimeout(() => {
isUpdating = true;
}, 1000);
try {
const template = await loadEmailTemplate(projectId, 'otpSession', locale);
emailTemplate.set(template);
$baseEmailTemplate = { ...$emailTemplate };
trackEvent(Submit.EmailChangeLocale, { locale, type: 'otpSession' });
} catch (error) {
trackError(error, Submit.EmailChangeLocale);
addNotification({
type: 'error',
message: error.message
});
} finally {
clearTimeout(timeout);
isUpdating = false;
}
}
</script>
<Card.Base variant="secondary" padding="s">
<Layout.Stack>
<LocaleOptions on:change={onLocaleChange} bind:value={locale} />
<EmailTemplate {loading} {isUpdating}>
<Id value={'{{user}}'}>{'{{user}}'}</Id>
<Id value={'{{project}}'}>{'{{project}}'}</Id>
<Id value={'{{otp}}'}>{'{{otp}}'}</Id>
<!-- START: for client info -->
<Id value={'{{agentClient}}'}>{'{{agentClient}}'}</Id>
<Id value={'{{agentDevice}}'}>{'{{agentDevice}}'}</Id>
<Id value={'{{agentOs}}'}>{'{{agentOs}}'}</Id>
<!-- END: for client info -->
</EmailTemplate>
</Layout.Stack>
</Card.Base>
@@ -119,7 +119,7 @@
>here</a
>.
</p>
<Layout.Stack direction="row">
<Layout.Stack direction="row" wrap="wrap">
<slot />
</Layout.Stack>
{/if}
@@ -5,8 +5,9 @@ import type { Models } from '@appwrite.io/console';
// component imports
import Email2FaTemplate from './email2FATemplate.svelte';
import EmailInviteTemplate from './emailInviteTemplate.svelte';
import EmailRecoveryTemplate from './emailRecoveryTemplate.svelte';
import EmailMagicUrlTemplate from './emailMagicUrlTemplate.svelte';
import EmailRecoveryTemplate from './emailRecoveryTemplate.svelte';
import EmailOtpSessionTemplate from './emailOtpSessionTemplate.svelte';
import EmailVerificationTemplate from './emailVerificationTemplate.svelte';
import EmailSessionAlertTemplate from './emailSessionAlertTemplate.svelte';
@@ -62,7 +63,7 @@ export const templates = [
key: 'otpSession',
title: 'OTP session',
description: 'Send an email to users that sign in with a email OTP.',
component: EmailMagicUrlTemplate
component: EmailOtpSessionTemplate
},
{
key: 'recovery',
@@ -1,5 +1,5 @@
<script lang="ts">
import { CardGrid, BoxAvatar, Alert } from '$lib/components';
import { CardGrid, BoxAvatar } from '$lib/components';
import { Container } from '$lib/layout';
import { Button } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
@@ -14,6 +14,7 @@
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { collection } from '../../store';
import { page } from '$app/stores';
import { Alert } from '@appwrite.io/pink-svelte';
let showDelete = false;
let permissions = $doc?.$permissions;
@@ -85,27 +86,23 @@
<svelte:fragment slot="aside">
{#if $collection.documentSecurity}
{#if showPermissionAlert}
<Alert type="info" dismissible on:dismiss={() => (showPermissionAlert = false)}>
<svelte:fragment slot="title">Document security is enabled</svelte:fragment>
<p class="text">
Users will be able to access this document if they have been granted <b
>either document or collection permissions.
</b>
</p>
</Alert>
<Alert.Inline
status="info"
title="Document security is enabled"
dismissible
on:dismiss={() => (showPermissionAlert = false)}>
Users will be able to access this document if they have been granted <b
>either document or collection permissions.</b>
</Alert.Inline>
{/if}
{#if permissions}
<Permissions bind:permissions />
{/if}
{:else}
<Alert type="info">
<svelte:fragment slot="title">Document security is disabled</svelte:fragment>
<p class="text">
If you want to assign document permissions. Go to Collection settings and
enable document security. Otherwise, only collection permissions will be
used.
</p>
</Alert>
<Alert.Inline status="info" title="Document security is disabled">
If you want to assign document permissions. Go to Collection settings and enable
document security. Otherwise, only collection permissions will be used.
</Alert.Inline>
{/if}
</svelte:fragment>
@@ -51,7 +51,10 @@
.vcs.listRepositoryBranches($installation.$id, selectedRepository);
const sorted = sortBranches(branchList.branches);
branch = sorted[0]?.name ?? null;
branch = sorted.find((b) => b.name === $func.providerBranch)
? $func.providerBranch
: (sorted[0]?.name ?? null);
if (!branch) {
branch = 'main';
@@ -24,7 +24,10 @@
return realtime
.forProject(page.params.region, page.params.project)
.subscribe<Models.Deployment>('console', (message) => {
if (previousStatus === message.payload.status) {
if (
message.payload.status !== 'ready' &&
previousStatus === message.payload.status
) {
return;
}
previousStatus = message.payload.status;
@@ -12,7 +12,15 @@
import DeploymentCard from './(components)/deploymentCard.svelte';
import RedeployModal from './(modals)/redeployModal.svelte';
import { canWriteFunctions } from '$lib/stores/roles';
import { ActionMenu, Alert, Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte';
import {
ActionMenu,
Alert,
Card,
Empty,
Icon,
Layout,
Tooltip
} from '@appwrite.io/pink-svelte';
import { Click, trackEvent } from '$lib/actions/analytics';
import {
IconDotsHorizontal,
@@ -99,16 +107,27 @@
<svelte:fragment slot="menu" let:toggle>
<ActionMenu.Root>
{#if $canWriteFunctions}
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
on:click={() => {
selectedDeployment = activeDeployment;
showRedeploy = true;
trackEvent(Click.FunctionsRedeployClick);
toggle();
}}>
Redeploy
</ActionMenu.Item.Button>
<Tooltip
disabled={activeDeployment.sourceSize !== 0}
placement={'bottom'}>
<div>
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
disabled={activeDeployment.sourceSize === 0}
on:click={() => {
selectedDeployment = activeDeployment;
showRedeploy = true;
trackEvent(
Click.FunctionsRedeployClick
);
toggle();
}}
style="width: 100%">
Redeploy
</ActionMenu.Item.Button>
</div>
<div slot="tooltip">Source is empty</div>
</Tooltip>
{/if}
<DownloadActionMenuItem
deployment={activeDeployment}
@@ -19,6 +19,7 @@
Layout,
Logs,
Spinner,
Tooltip,
Typography
} from '@appwrite.io/pink-svelte';
import { capitalize } from '$lib/helpers/string';
@@ -98,15 +99,24 @@
<svelte:fragment slot="menu" let:toggle>
<ActionMenu.Root>
{#if $canWriteFunctions}
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
on:click={() => {
showRedeploy = true;
trackEvent(Click.FunctionsRedeployClick);
toggle();
}}>
Redeploy
</ActionMenu.Item.Button>
<Tooltip
disabled={data.deployment.sourceSize !== 0}
placement={'bottom'}>
<div>
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
disabled={data.deployment.sourceSize === 0}
on:click={() => {
showRedeploy = true;
trackEvent(Click.FunctionsRedeployClick);
toggle();
}}
style="width: 100%">
Redeploy
</ActionMenu.Item.Button>
</div>
<div slot="tooltip">Source is empty</div>
</Tooltip>
{/if}
{#if !!data.deployment?.sourceSize || !!data.deployment?.sourceSize}
<DownloadActionMenuItem deployment={data.deployment} {toggle} />
@@ -13,7 +13,7 @@
import { sdk } from '$lib/stores/sdk';
import { Dependencies } from '$lib/constants';
import { invalidate } from '$app/navigation';
import { Alert } from '$lib/components';
import { Alert } from '@appwrite.io/pink-svelte';
import { Button } from '$lib/elements/forms';
import { Click, trackEvent } from '$lib/actions/analytics';
import UpdateRepository from './updateRepository.svelte';
@@ -22,6 +22,7 @@
import { isCloud } from '$lib/system';
import UpdateVariables from '$routes/(console)/project-[region]-[project]/updateVariables.svelte';
import { page } from '$app/state';
import { Link } from '$lib/elements';
export let data;
let showAlert = true;
@@ -55,35 +56,33 @@
<Container>
{#if data.function.version === 'v2' && showAlert}
<Alert
type="warning"
dismissible
class="u-margin-block-start-24"
on:dismiss={() => (showAlert = false)}>
<svelte:fragment slot="title">Your function is outdated</svelte:fragment>
Update your function version to make use of new features including build commands and HTTP
data in your executions. To update, follow the steps outlined in our
<a
href="https://appwrite.io/docs/products/functions/development"
target="_blank"
rel="noopener noreferrer"
class="link">documentation</a
>.
<svelte:fragment slot="buttons">
<Button
on:click={() =>
trackEvent(Click.WebsiteOpenClick, {
from: 'button',
source: 'function_keys_card',
destination: 'docs'
})}
href="https://appwrite.io/docs/products/functions/development"
external
text>
Learn more
</Button>
</svelte:fragment>
</Alert>
<div>
<Alert.Inline
status="warning"
dismissible
title="Your function is outdated"
on:dismiss={() => (showAlert = false)}>
Update your function version to make use of new features including build commands
and HTTP data in your executions. To update, follow the steps outlined in our
<Link href="https://appwrite.io/docs/products/functions/development" external
>documentation</Link
>.
<svelte:fragment slot="actions">
<Button
on:click={() =>
trackEvent(Click.WebsiteOpenClick, {
from: 'button',
source: 'function_keys_card',
destination: 'docs'
})}
href="https://appwrite.io/docs/products/functions/development"
external
text>
Learn more
</Button>
</svelte:fragment>
</Alert.Inline>
</div>
{/if}
<ExecuteFunction />
<UpdateName />
@@ -20,7 +20,8 @@
FloatingActionBar,
Icon,
Status,
Table
Table,
Tooltip
} from '@appwrite.io/pink-svelte';
import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics';
import {
@@ -149,18 +150,23 @@
<svelte:fragment slot="menu" let:toggle>
<ActionMenu.Root>
{#if deployment.sourceSize !== 0}
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
on:click={() => {
selectedDeployment = deployment;
showRedeploy = true;
toggle();
trackEvent(Click.FunctionsRedeployClick);
}}>
Redeploy
</ActionMenu.Item.Button>
{/if}
<Tooltip disabled={deployment.sourceSize !== 0} placement={'bottom'}>
<div>
<ActionMenu.Item.Button
trailingIcon={IconRefresh}
disabled={deployment.sourceSize === 0}
on:click={() => {
selectedDeployment = deployment;
showRedeploy = true;
toggle();
trackEvent(Click.FunctionsRedeployClick);
}}
style="width: 100%">
Redeploy
</ActionMenu.Item.Button>
</div>
<div slot="tooltip">Source is empty</div>
</Tooltip>
{#if deployment.status === 'ready' && deployment.$id !== $func.deploymentId}
<ActionMenu.Item.Button
trailingIcon={IconLightningBolt}
@@ -14,7 +14,7 @@
IconTrash,
IconXCircle
} from '@appwrite.io/pink-icons-svelte';
import { ActionMenu, Icon } from '@appwrite.io/pink-svelte';
import { ActionMenu, Icon, Tooltip } from '@appwrite.io/pink-svelte';
export let selectedDeployment: Models.Deployment;
export let deployment: Models.Deployment;
@@ -55,17 +55,24 @@
</Button>
<svelte:fragment slot="menu" let:toggle>
<ActionMenu.Root>
{#if !inCard && selectedDeployment?.sourceSize !== 0}
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
on:click={(e) => {
e.preventDefault();
selectedDeployment = deployment;
showRedeploy = true;
toggle();
}}>
Redeploy
</ActionMenu.Item.Button>
{#if !inCard}
<Tooltip disabled={selectedDeployment?.sourceSize !== 0} placement={'bottom'}>
<div>
<ActionMenu.Item.Button
leadingIcon={IconRefresh}
disabled={selectedDeployment?.sourceSize === 0}
on:click={(e) => {
e.preventDefault();
selectedDeployment = deployment;
showRedeploy = true;
toggle();
}}
style="width: 100%">
Redeploy
</ActionMenu.Item.Button>
</div>
<div slot="tooltip">Source is empty</div>
</Tooltip>
{/if}
{#if deployment?.status === 'ready' && deployment?.$id !== activeDeployment}
<ActionMenu.Item.Button
@@ -2,7 +2,7 @@
import { Card } from '$lib/components/index.js';
import { humanFileSize } from '$lib/helpers/sizeConvertion';
import { formatTimeDetailed } from '$lib/helpers/timeConversion';
import type { Models } from '@appwrite.io/console';
import { ImageFormat, type Models } from '@appwrite.io/console';
import { page } from '$app/state';
import {
Badge,
@@ -46,7 +46,23 @@
}
function getFilePreview(fileId: string) {
return sdk.forConsoleIn(page.params.region).storage.getFileView('screenshots', fileId);
return sdk
.forConsoleIn(page.params.region)
.storage.getFilePreview(
'screenshots',
fileId,
1024,
576,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
ImageFormat.Webp
);
}
</script>
@@ -1,6 +1,6 @@
<script lang="ts">
import { Modal } from '$lib/components';
import Alert from '$lib/components/alert.svelte';
import { Alert } from '@appwrite.io/pink-svelte';
import { Button } from '$lib/elements/forms';
import type { Models } from '@appwrite.io/console';
import { IconInfo } from '@appwrite.io/pink-icons-svelte';
@@ -75,9 +75,9 @@
</Layout.Stack>
</Upload.Dropzone>
{#if variables?.length > 0}
<Alert type="info" dismissible>
<Alert.Inline status="info" dismissible>
This action can create and update variables but can not delete them.
</Alert>
</Alert.Inline>
{/if}
</Layout.Stack>
<Selector.Checkbox
@@ -2,7 +2,7 @@
import { base } from '$app/paths';
import { page } from '$app/state';
import { timeFromNow } from '$lib/helpers/date';
import type { Models } from '@appwrite.io/console';
import { ImageFormat, type Models } from '@appwrite.io/console';
import { Card, Icon, Layout, Popover, Tooltip, Typography } from '@appwrite.io/pink-svelte';
import { generateSiteDeploymentDesc } from './store';
import { SvgIcon } from '$lib/components';
@@ -33,7 +33,23 @@
}
function getFilePreview(fileId: string) {
return sdk.forConsoleIn(page.params.region).storage.getFileView('screenshots', fileId);
return sdk
.forConsoleIn(page.params.region)
.storage.getFilePreview(
'screenshots',
fileId,
1024,
576,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
ImageFormat.Webp
);
}
</script>
@@ -14,7 +14,7 @@
onMount(() => {
let previousStatus: string = null;
return sdk.forConsole.client.subscribe<Models.Deployment>('console', (message) => {
if (previousStatus === message.payload.status) {
if (message.payload.status !== 'ready' && previousStatus === message.payload.status) {
return;
}
previousStatus = message.payload.status;
@@ -57,7 +57,10 @@
.vcs.listRepositoryBranches($installation.$id, selectedRepository);
const sorted = sortBranches(branchList.branches);
branch = sorted[0]?.name ?? null;
branch = sorted.find((b) => b.name === site.providerBranch)
? site.providerBranch
: (sorted[0]?.name ?? null);
if (!branch) {
branch = 'main';
@@ -12,7 +12,7 @@
import CancelDeploymentModal from '../cancelDeploymentModal.svelte';
import RedeployModal from '../../../redeployModal.svelte';
import ActivateDeploymentModal from '../../../activateDeploymentModal.svelte';
import { Accordion } from '@appwrite.io/pink-svelte';
import { Accordion, Tooltip } from '@appwrite.io/pink-svelte';
import { capitalize } from '$lib/helpers/string';
import LogsTimer from '../../../(components)/logsTimer.svelte';
import { invalidate } from '$app/navigation';
@@ -56,7 +56,17 @@
</Button>
{/if}
<Button secondary on:click={() => (showRedeploy = true)}>Redeploy</Button>
<Tooltip disabled={deployment?.sourceSize !== 0} placement={'bottom'}>
<div>
<Button
secondary
disabled={deployment?.sourceSize === 0}
on:click={() => (showRedeploy = true)}>
Redeploy
</Button>
</div>
<div slot="tooltip">Source is empty</div>
</Tooltip>
<DeploymentActionMenu
inCard
{deployment}
@@ -60,7 +60,10 @@
{#key data.site.providerRepositoryId}
<UpdateRepository site={data.site} installations={data.installations} />
{/key}
<UpdateBuildSettings site={data.site} frameworks={data.frameworks.frameworks} />
<UpdateBuildSettings
site={data.site}
frameworks={data.frameworks.frameworks}
specs={data.specificationsList} />
<UpdateRuntimeSettings site={data.site} frameworks={data.frameworks.frameworks} />
<UpdateVariables
{sdkCreateVariable}
@@ -33,6 +33,11 @@ export const load = async ({ params, depends, parent }) => {
}
});
const enabledSpecs = specificationsList?.specifications?.filter((s) => s.enabled) ?? [];
if (!enabledSpecs.some((s) => s.slug === site.specification)) {
site.specification = enabledSpecs[0]?.slug;
}
return {
site,
frameworks,
@@ -17,10 +17,12 @@
let {
site,
frameworks
frameworks,
specs
}: {
site: Models.Site;
frameworks: Models.Framework[];
specs: Models.SpecificationList;
} = $props();
let frameworkKey = $state(site.framework);
@@ -88,12 +90,33 @@
}
});
$effect(() => {
if (selectedFramework) {
if (!selectedFramework.adapters.some((a) => a.key === adapter)) {
adapter = selectedFramework.adapters[0].key as Adapter;
site.adapter = adapter;
}
if (specs && specs.specifications?.length) {
if (!specs.specifications.some((s) => s.slug === site.specification)) {
site.specification = specs.specifications[0].slug;
}
}
}
});
async function update() {
let adptr = selectedFramework.adapters.find((a) => a.key === adapter);
if (!adptr?.key && selectedFramework.adapters?.length) {
adapter = selectedFramework.adapters[0].key as Adapter;
adptr = selectedFramework.adapters[0];
site.adapter = adapter;
}
// only allow enabled specsification for it
const enabledSpecs = specs?.specifications?.filter((s) => s.enabled) ?? [];
let specToSend = enabledSpecs.some((s) => s.slug === site.specification)
? site.specification
: enabledSpecs[0]?.slug;
site.specification = specToSend;
try {
await sdk
.forProject(page.params.region, page.params.project)
@@ -115,7 +138,7 @@
site.providerBranch || undefined,
site.providerSilentMode || undefined,
site.providerRootDirectory || undefined,
site?.specification || undefined
specToSend || undefined
);
await invalidate(Dependencies.SITE);
addNotification({
@@ -19,8 +19,6 @@
let specification = site.specification;
let originalSpecification = site.specification;
$: originalSpecification = site.specification;
async function updateLogging() {
try {
await sdk
@@ -1,6 +1,7 @@
<script lang="ts">
import { Click, Submit, trackEvent } from '$lib/actions/analytics';
import { Alert, CardGrid } from '$lib/components';
import { CardGrid } from '$lib/components';
import { Alert } from '@appwrite.io/pink-svelte';
import { BillingPlan } from '$lib/constants';
import { Button, Form, InputNumber, InputSelect } from '$lib/elements/forms';
import { humanFileSize, sizeToBytes } from '$lib/helpers/sizeConvertion';
@@ -45,16 +46,14 @@
<svelte:fragment slot="aside">
{#if isCloud}
{@const size = humanFileSize(sizeToBytes(service, 'MB', 1000))}
<Alert type="info">
<p class="text">
The {currentPlan.name} plan has a maximum upload file size limit of {Math.floor(
parseInt(size.value)
)}{size.unit}.
{#if $organization?.billingPlan === BillingPlan.FREE}
Upgrade to allow files of a larger size.
{/if}
</p>
<svelte:fragment slot="action">
<Alert.Inline status="info">
The {currentPlan.name} plan has a maximum upload file size limit of {Math.floor(
parseInt(size.value)
)}{size.unit}.
{#if $organization?.billingPlan === BillingPlan.FREE}
Upgrade to allow files of a larger size.
{/if}
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE}
<div class="alert-buttons u-flex">
<Button
@@ -68,7 +67,7 @@
</div>
{/if}
</svelte:fragment>
</Alert>
</Alert.Inline>
{/if}
<InputNumber
required