diff --git a/eslint.config.js b/eslint.config.js index 05ce3e85f..32ef292d0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -32,7 +32,9 @@ export default ts.config( 'svelte/no-at-html-tags': 'off', 'svelte/no-useless-mustaches': 'off', 'svelte/no-reactive-reassign': 'off', - 'svelte/no-reactive-literals': 'off' + 'svelte/no-reactive-literals': 'off', + // TODO: @itznotabug, this requires a big refactor! + 'svelte/no-navigation-without-resolve': 'off' } }, { diff --git a/package.json b/package.json index bf15dfbe5..69a51845e 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,11 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134", + "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1", "@faker-js/faker": "^9.9.0", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", @@ -54,7 +54,7 @@ "@melt-ui/svelte": "^0.86.5", "@playwright/test": "^1.51.1", "@sveltejs/adapter-static": "^3.0.8", - "@sveltejs/kit": "^2.36.2", + "@sveltejs/kit": "^2.42.1", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 088515c16..826d1cce5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,20 +12,20 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.25.3)(zod@3.24.3) '@appwrite.io/console': - specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134 - version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134 + specifier: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562 + version: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -34,7 +34,7 @@ importers: version: 2.11.8 '@sentry/sveltekit': specifier: ^8.38.0 - version: 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + version: 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) '@stripe/stripe-js': specifier: ^3.5.0 version: 3.5.0 @@ -101,10 +101,10 @@ importers: version: 1.51.1 '@sveltejs/adapter-static': specifier: ^3.0.8 - version: 3.0.8(@sveltejs/kit@2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))) + version: 3.0.8(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))) '@sveltejs/kit': - specifier: ^2.36.2 - version: 2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + specifier: ^2.42.1 + version: 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 version: 5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) @@ -260,8 +260,8 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134': - resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562': + resolution: {tarball: https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562} version: 1.10.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': @@ -269,8 +269,8 @@ packages: peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -284,8 +284,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -352,8 +352,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.28.3': - resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + '@babel/parser@7.28.4': + resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} engines: {node: '>=6.0.0'} hasBin: true @@ -373,8 +373,8 @@ packages: resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + '@babel/types@7.28.4': + resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} '@csstools/color-helpers@5.0.2': @@ -1264,8 +1264,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.36.3': - resolution: {integrity: sha512-MVzwZz1GFznEQbL3f0i2v9AIc3lZH01izQj6XfIrthmZAwOzyXJCgXbLRss8vk//HfYsE4w6Tz+ukbf3rScPNQ==} + '@sveltejs/kit@2.42.1': + resolution: {integrity: sha512-SoWdb/OxEKHMlXZ78eNZa4pR1YdOGnUfcFj5NylJv+ZaTrnHK5xapw+7RJP2MiS1D4T+sEH25/tmMtmEl8p6VA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -2607,6 +2607,9 @@ packages: magic-string@0.30.18: resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + magic-string@0.30.7: resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} engines: {node: '>=12'} @@ -3050,8 +3053,8 @@ packages: engines: {node: '>=10'} hasBin: true - seroval-plugins@1.3.2: - resolution: {integrity: sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==} + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 @@ -3700,13 +3703,13 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@6031134': {} + '@appwrite.io/console@https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@7747562': {} '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@d8326d0(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@f2198f1(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3719,7 +3722,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@d8326d0(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@f2198f1(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 @@ -3822,9 +3825,9 @@ snapshots: dependencies: '@babel/types': 7.27.0 - '@babel/parser@7.28.3': + '@babel/parser@7.28.4': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/runtime@7.27.0': dependencies: @@ -3853,7 +3856,7 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@babel/types@7.28.2': + '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 @@ -4671,14 +4674,14 @@ snapshots: magic-string: 0.30.7 svelte: 5.25.3 - '@sentry/sveltekit@8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': + '@sentry/sveltekit@8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': dependencies: '@sentry/core': 8.55.0 '@sentry/node': 8.55.0 '@sentry/opentelemetry': 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0) '@sentry/svelte': 8.55.0(svelte@5.25.3) '@sentry/vite-plugin': 2.22.6 - '@sveltejs/kit': 2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + '@sveltejs/kit': 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) magic-string: 0.30.7 magicast: 0.2.8 sorcery: 1.0.0 @@ -4750,11 +4753,11 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.8(@sveltejs/kit@2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))': + '@sveltejs/adapter-static@3.0.8(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))': dependencies: - '@sveltejs/kit': 2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + '@sveltejs/kit': 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) - '@sveltejs/kit@2.36.3(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': + '@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) @@ -5121,7 +5124,7 @@ snapshots: '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 @@ -5134,13 +5137,13 @@ snapshots: '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 estree-walker: 2.0.2 - magic-string: 0.30.18 + magic-string: 0.30.19 postcss: 8.5.6 source-map-js: 1.2.1 @@ -6282,6 +6285,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.7: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -6703,7 +6710,7 @@ snapshots: semver@7.7.1: {} - seroval-plugins@1.3.2(seroval@1.3.2): + seroval-plugins@1.3.3(seroval@1.3.2): dependencies: seroval: 1.3.2 @@ -6786,7 +6793,7 @@ snapshots: dependencies: csstype: 3.1.3 seroval: 1.3.2 - seroval-plugins: 1.3.2(seroval@1.3.2) + seroval-plugins: 1.3.3(seroval@1.3.2) solid-swr-store@0.10.7(solid-js@1.9.5)(swr-store@0.10.6): dependencies: diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 957b10e6b..1f4722965 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -6,7 +6,7 @@ import { user } from '$lib/stores/user'; import { ENV, MODE, VARS, isCloud } from '$lib/system'; import { AppwriteException } from '@appwrite.io/console'; import { browser } from '$app/environment'; -import { getReferrerAndUtmSource } from '$lib/helpers/utm'; +import { getReferrerAndUtmSource, getTrackedQueryParams } from '$lib/helpers/utm'; function plausible(domain: string): AnalyticsPlugin { if (!browser) return { name: 'analytics-plugin-plausible' }; @@ -65,7 +65,7 @@ export function trackEvent(name: string, data: object = null): void { }; } - data = { ...data, ...getReferrerAndUtmSource() }; + data = { ...data, ...getReferrerAndUtmSource(), ...getTrackedQueryParams() }; if (ENV.DEV || ENV.PREVIEW) { console.debug(`[Analytics] Event ${name} ${path}`, data); @@ -429,5 +429,6 @@ export enum Submit { RecordUpdate = 'submit_dns_record_update', RecordDelete = 'submit_dns_record_delete', SearchClear = 'submit_clear_search', - FrameworkDetect = 'submit_framework_detect' + FrameworkDetect = 'submit_framework_detect', + TestimonialView = 'testimonial_view' } diff --git a/src/lib/actions/timer.ts b/src/lib/actions/timer.ts index 1f6bff7e1..07d589a8b 100644 --- a/src/lib/actions/timer.ts +++ b/src/lib/actions/timer.ts @@ -21,13 +21,16 @@ export const timer: Action = (node, props) => { } function step() { - const diffInSeconds = Math.floor((new Date().getTime() - startDate.getTime()) / 1000); - const minutes = Math.floor(diffInSeconds / 60); + const elapsedSeconds = Math.max( + 0, + Math.floor((new Date().getTime() - startDate.getTime()) / 1000) + ); + const minutes = Math.floor(elapsedSeconds / 60); if (minutes > 0) { - const seconds = diffInSeconds % 60; + const seconds = elapsedSeconds % 60; node.textContent = `${minutes}m ${seconds}s`; } else { - node.textContent = calculateTime(diffInSeconds); + node.textContent = calculateTime(elapsedSeconds); } frame = window.requestAnimationFrame(step); } diff --git a/src/lib/components/account/sendVerificationEmailModal.svelte b/src/lib/components/account/sendVerificationEmailModal.svelte new file mode 100644 index 000000000..bbe676142 --- /dev/null +++ b/src/lib/components/account/sendVerificationEmailModal.svelte @@ -0,0 +1,79 @@ + + + + + + + To continue using Appwrite Cloud, please verify your email address. An email will be + sent to {get(user)?.email} + + + + + + + + diff --git a/src/lib/components/alerts/emailVerificationBanner.svelte b/src/lib/components/alerts/emailVerificationBanner.svelte index 51fc4bbab..9af46d418 100644 --- a/src/lib/components/alerts/emailVerificationBanner.svelte +++ b/src/lib/components/alerts/emailVerificationBanner.svelte @@ -1,55 +1,26 @@ {#if shouldShowEmailBanner} - + To avoid losing access to your projects, make sure - + + {/if} diff --git a/src/lib/components/billing/alerts/newDevUpgradePro.svelte b/src/lib/components/billing/alerts/newDevUpgradePro.svelte index 4631c1721..733736f02 100644 --- a/src/lib/components/billing/alerts/newDevUpgradePro.svelte +++ b/src/lib/components/billing/alerts/newDevUpgradePro.svelte @@ -23,7 +23,7 @@ } -{#if show && $organization?.$id && $organization?.billingPlan === BillingPlan.FREE && !page.url.pathname.includes('/console/account')} +{#if show && $organization?.$id && $organization?.billingPlan === BillingPlan.FREE && !page.url.pathname.includes(base + '/account')} import { BillingPlan } from '$lib/constants'; import { formatNum } from '$lib/helpers/string'; - import { plansInfo, tierFree, tierPro, tierScale, type Tier } from '$lib/stores/billing'; + import { plansInfo, tierToPlan, type Tier } from '$lib/stores/billing'; import { Card, Layout, Tabs, Typography } from '@appwrite.io/pink-svelte'; export let downgrade = false; @@ -9,29 +9,22 @@ let selectedTab: Tier = BillingPlan.FREE; $: plan = $plansInfo.get(selectedTab); + + const allTiers: Tier[] = [BillingPlan.FREE, BillingPlan.PRO, BillingPlan.SCALE]; + $: visibleTiers = allTiers.filter((tier) => tier !== BillingPlan.SCALE); - (selectedTab = BillingPlan.FREE)}> - {tierFree.name} - - (selectedTab = BillingPlan.PRO)}> - {tierPro.name} - - (selectedTab = BillingPlan.SCALE)}> - {tierScale.name} - + {#each visibleTiers as tier} + (selectedTab = tier)}> + {tierToPlan(tier).name} + + {/each} {plan.name} plan diff --git a/src/lib/components/billing/planSelection.svelte b/src/lib/components/billing/planSelection.svelte index dd6716c7f..0e194f9b6 100644 --- a/src/lib/components/billing/planSelection.svelte +++ b/src/lib/components/billing/planSelection.svelte @@ -14,10 +14,13 @@ $: plans = Object.values(page.data.plans.plans) as Plan[]; $: currentPlanInList = plans.some((plan) => plan.$id === $currentPlan?.$id); + + // experiment to remove scale plan temporarily + $: plansWithoutScale = plans.filter((plan) => plan.$id != BillingPlan.SCALE); - {#each plans as plan} + {#each plansWithoutScale as plan} = null; + function closeAllMenus() { + if (orgMenuStates?.open) { + orgMenuStates.open.set(false); + } + + if (projectsMenuStates?.open) { + projectsMenuStates.open.set(false); + } + + projectsBottomSheetOpen = false; + organisationBottomSheetOpen = false; + } + + beforeNavigate(closeAllMenus); + + onDestroy(closeAllMenus); + function createOrg() { trackEvent(Click.OrganizationClickCreate, { source: 'breadcrumbs' }); if (isCloud) { @@ -105,6 +128,8 @@ async function createProjectsBottomSheet( organization: Organization ): Promise { + const isOnProjects = page.route.id.includes('project-[region]-[project]'); + if (!isOnProjects) return null; isLoadingProjects = true; @@ -212,12 +237,10 @@ ? $currentPlan.name : selectedOrg?.tierName; // fallback - $: derivedKey = `${selectedOrg?.$id}-${currentProject?.$id}`; + $: derivedKey = `${selectedOrg?.$id}-${currentProject?.$id}-${ID.unique()}`; $: organizationId = currentProject?.teamId; - $: isOnProjects = page.route.id.includes('project-[region]-[project]'); - $: shouldReloadProjects = isLoadingProjects ? false : currentProject && loadedProjects.projects.length diff --git a/src/lib/components/csvImportBox.svelte b/src/lib/components/csvImportBox.svelte index 8ff2838ab..ec7a2c9a3 100644 --- a/src/lib/components/csvImportBox.svelte +++ b/src/lib/components/csvImportBox.svelte @@ -62,7 +62,7 @@ if (isSuccess) { await invalidate(Dependencies.ROWS); - $spreadsheetRenderKey = hash(Date.now().toString()); + spreadsheetRenderKey.set(hash(Date.now().toString())); } } @@ -90,6 +90,15 @@ } } + if (tableId && tableName === null) { + importItems.update((items) => { + const next = new Map(items); + next.delete(importData.$id); + return next; + }); + return; + } + importItems.update((items) => { const existing = items.get(importData.$id); diff --git a/src/lib/components/domains/dnsRecordsAction.svelte b/src/lib/components/domains/dnsRecordsAction.svelte index a1c7845ae..546407c49 100644 --- a/src/lib/components/domains/dnsRecordsAction.svelte +++ b/src/lib/components/domains/dnsRecordsAction.svelte @@ -32,6 +32,6 @@ {#if dnsData} - DNS Records + DNS records {/if} diff --git a/src/lib/components/filters/content.svelte b/src/lib/components/filters/content.svelte index 85f2960da..a42161f43 100644 --- a/src/lib/components/filters/content.svelte +++ b/src/lib/components/filters/content.svelte @@ -6,10 +6,11 @@ InputText, InputTags, InputSelectCheckbox, - InputDateTime + InputDateTime, + InputPoint } from '$lib/elements/forms'; import { onMount, createEventDispatcher } from 'svelte'; - import { operators, addFilter, queries, tags } from './store'; + import { operators, addFilter, queries, tags, ValidOperators } from './store'; import type { Column } from '$lib/helpers/types'; import type { Writable } from 'svelte/store'; import { TagList } from '.'; @@ -18,6 +19,7 @@ let { value = $bindable(null), + distanceValue = $bindable(null), columns, columnId = $bindable(null), arrayValues = $bindable([]), @@ -27,6 +29,7 @@ // We cast to any to not cause type errors in the input components /* eslint @typescript-eslint/no-explicit-any: 'off' */ value?: any; + distanceValue?: number | null; columns: Writable; columnId?: string | null; arrayValues?: string[]; @@ -61,21 +64,57 @@ })); }); + // Check if the current operator is a distance-based operator + let isDistanceOperator = $derived( + operatorKey && + [ + ValidOperators.DistanceEqual, + ValidOperators.DistanceNotEqual, + ValidOperators.DistanceGreaterThan, + ValidOperators.DistanceLessThan + ].includes(operatorKey as ValidOperators) + ); + onMount(() => { value = column?.array ? [] : null; if (column?.type === 'datetime') { const now = new Date(); value = now.toISOString().slice(0, 16); } + // Initialize spatial data with default values + if (column?.type === 'point') { + value = [0, 0]; + } else if (column?.type === 'linestring') { + value = [ + [0, 0], + [1, 1] + ]; + } else if (column?.type === 'polygon') { + value = [ + [ + [0, 0], + [1, 1], + [2, 2], + [0, 0] + ] + ]; + } }); const dispatch = createEventDispatcher<{ clear: void; apply: { applied: number } }>(); function addFilterAndReset() { - addFilter(columnsArray, columnId, operatorKey, value, arrayValues); + // For distance operators, pass the distance as a separate parameter + if (isDistanceOperator && distanceValue !== null && value !== null) { + addFilter(columnsArray, columnId, operatorKey, value, arrayValues, distanceValue); + } else { + addFilter(columnsArray, columnId, operatorKey, value, arrayValues); + } + columnId = null; operatorKey = null; value = null; + distanceValue = null; arrayValues = []; dispatch('apply', { applied: appliedTags.length }); if (singleCondition) { @@ -143,11 +182,29 @@ {#key value} {/key} + {:else if column.type === 'point' || column.type === 'linestring' || column.type === 'polygon'} + { + if (!value) value = [0, 0]; + value[index] = newValue; + }} /> {:else} {/if} {/if} + + {#if isDistanceOperator} +
+ +
+ {/if} {/if} {#if !singleCondition} {/if} -{#if enabledFactors.length > 1} - or -
- {#if factors.totp} - {#if (challengeType === null || challengeType === AuthenticationFactor.Totp || challengeType === AuthenticationFactor.Recoverycode) && factors.email} - - {:else if (challengeType === AuthenticationFactor.Recoverycode && !factors.email) || challengeType === AuthenticationFactor.Email} + +{#if enabledMainFactors.length > 0} + {@const hasSecondaryOptions = + enabledMainFactors.length > 1 || + (factors.recoveryCode && challengeType !== AuthenticationFactor.Recoverycode) || + (enabledMainFactors.length === 1 && factors.recoveryCode)} + + {#if hasSecondaryOptions} + or +
+ + {#if factors.totp && challengeType !== AuthenticationFactor.Totp} - {/if} -
+ + {#if factors.recoveryCode && challengeType !== AuthenticationFactor.Recoverycode} + + {/if} +
+ {/if} {/if} diff --git a/src/lib/components/sidebar.svelte b/src/lib/components/sidebar.svelte index 325eb8bd5..6a694d6e9 100644 --- a/src/lib/components/sidebar.svelte +++ b/src/lib/components/sidebar.svelte @@ -42,6 +42,7 @@ import type { HTMLAttributes } from 'svelte/elements'; import type { Models } from '@appwrite.io/console'; import { noWidthTransition } from '$lib/stores/sidebar'; + import { base } from '$app/paths'; type $$Props = HTMLAttributes & { state?: 'closed' | 'open' | 'icons'; @@ -138,7 +139,7 @@ { trackEvent('click_menu_get_started'); sideBarIsOpen = false; @@ -162,7 +163,7 @@ { @@ -192,7 +193,7 @@ {#each buildProjectOptions as projectOption} { @@ -223,7 +224,7 @@ {#each deployProjectOptions as projectOption} { @@ -253,7 +254,7 @@
{ trackEvent('click_menu_settings'); sideBarIsOpen = false; @@ -313,7 +314,7 @@
{ trackEvent('click_menu_settings'); diff --git a/src/lib/data/testimonials.ts b/src/lib/data/testimonials.ts new file mode 100644 index 000000000..47b0b8883 --- /dev/null +++ b/src/lib/data/testimonials.ts @@ -0,0 +1,58 @@ +import DevKind from '$lib/images/testimonials/hassan.png'; +import LangX from '$lib/images/testimonials/xue.webp'; +import KCollect from '$lib/images/testimonials/ryan-oconner-testimonial.png'; +import Phil from '$lib/images/testimonials/phil.jpg'; + +export interface Testimonial { + id: string; + logo: string; + headline: string; + blurb: string; + name: string; + title: string; + avatar: string; +} + +export const testimonials: Testimonial[] = [ + { + id: 'hassan-devkind', + logo: DevKind, + headline: 'DevKind reduced development time by 60% and lowered server costs by 40%', + blurb: 'A special thanks to Appwrite for providing robust features and seamless functionality.', + name: 'Hassan Ahmed', + title: 'Engineer at DevKind', + avatar: DevKind + }, + { + id: 'xue-langx', + logo: LangX, + headline: 'LangX handled millions of requests using Appwrite', + blurb: 'With its comprehensive suite of services, Appwrite emerged as an ideal choice for my needs.', + name: 'Xue', + title: 'Founder at LangX', + avatar: LangX + }, + { + id: 'ryan-kcollect', + logo: KCollect, + headline: 'K-Collect reduced infrastructure costs by 700%', + blurb: 'A major impact that Appwrite made was the amount of time and stress saved.', + name: "Ryan O'Connor", + title: 'Founder at K-Collect', + avatar: KCollect + }, + { + id: 'phil-majikkids', + logo: Phil, + headline: 'With Appwrite, Majik Kids built an entire app with one developer.', + blurb: 'Just like a Swiss Army Knife you can choose and use the tools that you need with Appwrite.', + name: 'Phil McCluskey', + title: 'App Manager, Majik Kids', + avatar: Phil + } +]; + +export function getRandomTestimonial(): Testimonial { + const randomIndex = Math.floor(Math.random() * testimonials.length); + return testimonials[randomIndex]; +} diff --git a/src/lib/elements/forms/index.ts b/src/lib/elements/forms/index.ts index 20b970669..8dcb7e5aa 100644 --- a/src/lib/elements/forms/index.ts +++ b/src/lib/elements/forms/index.ts @@ -31,3 +31,6 @@ export { default as InputDigits } from './inputDigits.svelte'; export { default as InputSelectCheckbox } from './inputSelectCheckbox.svelte'; export { default as InputFilePicker } from './inputFilePicker.svelte'; export { default as Seekbar } from './Seekbar.svelte'; +export { default as InputPoint } from './inputPoint.svelte'; +export { default as InputLine } from './inputLine.svelte'; +export { default as InputPolygon } from './inputPolygon.svelte'; diff --git a/src/lib/elements/forms/inputLine.svelte b/src/lib/elements/forms/inputLine.svelte new file mode 100644 index 000000000..3987b3635 --- /dev/null +++ b/src/lib/elements/forms/inputLine.svelte @@ -0,0 +1,61 @@ + + + + + {#each values as value, index} + onDeletePoint(index)} + onChangePoint={(coordIndex, newValue) => + onChangePoint?.(index, coordIndex, newValue)} /> + {/each} + + + {#if values} + + + {@render addLineButton?.()} + + {/if} + diff --git a/src/lib/elements/forms/inputPoint.svelte b/src/lib/elements/forms/inputPoint.svelte new file mode 100644 index 000000000..4c0b4ce40 --- /dev/null +++ b/src/lib/elements/forms/inputPoint.svelte @@ -0,0 +1,54 @@ + + + + + {#if nullable} + {#each nullableSkeletonShape as _, index} + + {/each} + {:else} + {#each values as _, index} + onChangePoint(index, Number.parseFloat(`${e.detail}`))} /> + {/each} + {/if} + {#if deletePoints} + + {/if} + + diff --git a/src/lib/elements/forms/inputPolygon.svelte b/src/lib/elements/forms/inputPolygon.svelte new file mode 100644 index 000000000..c2bcbb4db --- /dev/null +++ b/src/lib/elements/forms/inputPolygon.svelte @@ -0,0 +1,59 @@ + + + + {#each values as value, index} + + onAddPoint(index)} + {nullable} + onDeletePoint={() => onDeletePoint(index)} + onChangePoint={(pointIndex, coordIndex, newValue) => + onChangePoint(index, pointIndex, coordIndex, newValue)} + allowLineDelete={index < 2} + {minDeletableIndex}> + {#snippet addLineButton()} + {#if index === values.length - 1} + + {/if} + {/snippet} + + + {/each} + diff --git a/src/lib/helpers/faker.ts b/src/lib/helpers/faker.ts index 16355677a..56987f879 100644 --- a/src/lib/helpers/faker.ts +++ b/src/lib/helpers/faker.ts @@ -3,6 +3,7 @@ import type { Columns } from '$routes/(console)/project-[region]-[project]/datab import { ID, type Models } from '@appwrite.io/console'; import { sdk } from '$lib/stores/sdk'; import { isWithinSafeRange } from '$lib/helpers/numbers'; +import type { NestedNumberArray } from './types'; export async function generateColumns( project: Models.Project, @@ -42,7 +43,24 @@ export async function generateColumns( size: 1000, required: false }), - client.tablesDB.createBooleanColumn({ databaseId, tableId, key: 'active', required: false }) + client.tablesDB.createBooleanColumn({ + databaseId, + tableId, + key: 'active', + required: false + }), + client.tablesDB.createPointColumn({ + databaseId, + tableId, + key: 'location', + required: false + }), + client.tablesDB.createLineColumn({ + databaseId, + tableId, + key: 'route', + required: false + }) ]); } @@ -66,7 +84,10 @@ export function generateFakeRecords( const id = ID.unique(); ids.push(id); - let row: Record> = { + let row: Record< + string, + string | number | boolean | Array + > = { $id: id }; @@ -78,7 +99,12 @@ export function generateFakeRecords( age: faker.number.int({ min: 18, max: 80 }), city: faker.location.city(), description: faker.lorem.sentence(), - active: faker.datatype.boolean() + active: faker.datatype.boolean(), + location: [faker.location.longitude(), faker.location.latitude()], + route: Array.from({ length: 5 }, () => [ + faker.location.longitude(), + faker.location.latitude() + ]) }; } else { for (const column of filteredColumns) { @@ -116,10 +142,10 @@ function generateStringValue(key: string, maxLength: number): string { function generateValueForColumn( column: Columns -): string | number | boolean | null | Array { +): string | number | boolean | null | Array { if (column.array) { const arraySize = faker.number.int({ min: 1, max: 5 }); - const items: Array = []; + const items: Array = []; for (let i = 0; i < arraySize; i++) { const itemAttribute = { ...column, array: false }; @@ -135,7 +161,9 @@ function generateValueForColumn( return generateSingleValue(column); } -function generateSingleValue(column: Columns): string | number | boolean | null { +function generateSingleValue( + column: Columns +): string | number | boolean | NestedNumberArray | null { switch (column.type) { case 'string': { if ('format' in column && column.format) { @@ -192,6 +220,25 @@ function generateSingleValue(column: Columns): string | number | boolean | null return faker.date.recent({ days: 365 }).toISOString(); } + case 'point': { + return [faker.location.longitude(), faker.location.latitude()]; + } + + case 'linestring': { + return Array.from({ length: 5 }, () => [ + faker.location.longitude(), + faker.location.latitude() + ]); + } + + case 'polygon': { + const points = Array.from({ length: 5 }, () => [ + faker.location.longitude(), + faker.location.latitude() + ]); + points.push(points[0]); // close polygon + return [points]; + } default: { return faker.lorem.word(); } diff --git a/src/lib/helpers/github.ts b/src/lib/helpers/github.ts index 2155642d8..b173d6d22 100644 --- a/src/lib/helpers/github.ts +++ b/src/lib/helpers/github.ts @@ -3,7 +3,9 @@ export function getNestedRootDirectory(repository: string): string | null { return match ? match[1] : null; } -export function getRepositoryInfo(repository: string): { owner: string; name: string } | null { +export function getRepositoryInfo( + repository: string +): { owner: string; name: string; url: string } | null { const match = repository .trim() .match(/(?:^|\/\/|@)github\.com[/:]([^/]+)\/([^/]+?)(?:\.git)?(?:$|[/?#])/i); @@ -13,7 +15,9 @@ export function getRepositoryInfo(repository: string): { owner: string; name: st const owner = decodeURIComponent(match[1]); const name = decodeURIComponent(match[2].replace(/\.git$/i, '')); - return { owner, name }; + const url = `https://github.com/${owner}/${name}`; + + return { owner, name, url }; } export async function getLatestTag(owner: string, name: string): Promise { diff --git a/src/lib/helpers/httpStatus.ts b/src/lib/helpers/httpStatus.ts new file mode 100644 index 000000000..fee77802a --- /dev/null +++ b/src/lib/helpers/httpStatus.ts @@ -0,0 +1,23 @@ +/** + * determines the badge color based on HTTP status code + * + * @param statusCode + * @returns badge color + */ +export function getBadgeTypeFromStatusCode( + statusCode: number +): 'error' | 'warning' | 'success' | undefined { + if (statusCode >= 500) { + return 'error'; + } + + if (statusCode >= 400) { + return 'warning'; + } + + if (statusCode === 0) { + return undefined; + } + + return 'success'; +} diff --git a/src/lib/helpers/types.ts b/src/lib/helpers/types.ts index abb4c133a..df6fba0d9 100644 --- a/src/lib/helpers/types.ts +++ b/src/lib/helpers/types.ts @@ -35,7 +35,10 @@ const columnTypes = [ 'boolean', 'datetime', 'relationship', - 'enum' + 'enum', + 'point', + 'linestring', + 'polygon' ] as const; export type ColumnType = (typeof columnTypes)[number]; export type Column = PinkColumn & { @@ -77,3 +80,5 @@ export type TableRootProp = { addAvailableId: (id: string) => void; removeAvailableId: (id: string) => void; }; + +export type NestedNumberArray = Array; diff --git a/src/lib/helpers/utm.ts b/src/lib/helpers/utm.ts index df2cb2158..d37abd88c 100644 --- a/src/lib/helpers/utm.ts +++ b/src/lib/helpers/utm.ts @@ -1,3 +1,17 @@ +const LINKEDIN_TRACKING_ID = 'li_fat_id'; +const GOOGLE_TRACKING_ID = 'gclid'; +const TWITTER_TRACKING_ID = 'twclid'; +const REDDIT_TRACKING_ID = 'rdt_cid'; + +const TRACKED_QUERY_PARAMS = [ + LINKEDIN_TRACKING_ID, + GOOGLE_TRACKING_ID, + TWITTER_TRACKING_ID, + REDDIT_TRACKING_ID +] as const; + +type TrackedParams = Record<(typeof TRACKED_QUERY_PARAMS)[number], string>; + export function getReferrerAndUtmSource() { if (sessionStorage) { let values = {}; @@ -15,3 +29,26 @@ export function getReferrerAndUtmSource() { } return {}; } + +export function getTrackedQueryParams(): Partial { + if (typeof window === 'undefined' || !window.location) { + return {}; + } + + try { + const urlParams = new URLSearchParams(window.location.search); + const params: Partial = {}; + + for (const paramName of TRACKED_QUERY_PARAMS) { + const value = urlParams.get(paramName); + if (value) { + params[paramName] = value; + } + } + + return params; + } catch (error) { + console.warn('Failed to parse URL search parameters:', error); + return {}; + } +} diff --git a/src/lib/images/promos/spatial-columns-api-dark.png b/src/lib/images/promos/spatial-columns-api-dark.png new file mode 100644 index 000000000..232763d19 Binary files /dev/null and b/src/lib/images/promos/spatial-columns-api-dark.png differ diff --git a/src/lib/images/promos/spatial-columns-api-light.png b/src/lib/images/promos/spatial-columns-api-light.png new file mode 100644 index 000000000..f62f20d4d Binary files /dev/null and b/src/lib/images/promos/spatial-columns-api-light.png differ diff --git a/src/lib/images/promos/tables-api-dark.png b/src/lib/images/promos/tables-api-dark.png deleted file mode 100644 index 7ac69f3fe..000000000 Binary files a/src/lib/images/promos/tables-api-dark.png and /dev/null differ diff --git a/src/lib/images/promos/tables-api-light.png b/src/lib/images/promos/tables-api-light.png deleted file mode 100644 index 0ab288301..000000000 Binary files a/src/lib/images/promos/tables-api-light.png and /dev/null differ diff --git a/src/lib/images/testimonials/hassan.png b/src/lib/images/testimonials/hassan.png new file mode 100644 index 000000000..5c0e3e45b Binary files /dev/null and b/src/lib/images/testimonials/hassan.png differ diff --git a/src/lib/images/testimonials/phil.jpg b/src/lib/images/testimonials/phil.jpg new file mode 100644 index 000000000..b358163e0 Binary files /dev/null and b/src/lib/images/testimonials/phil.jpg differ diff --git a/src/lib/images/testimonials/ryan-oconner-testimonial.png b/src/lib/images/testimonials/ryan-oconner-testimonial.png new file mode 100644 index 000000000..417592184 Binary files /dev/null and b/src/lib/images/testimonials/ryan-oconner-testimonial.png differ diff --git a/src/lib/images/testimonials/xue.webp b/src/lib/images/testimonials/xue.webp new file mode 100644 index 000000000..4f7fe1ce5 Binary files /dev/null and b/src/lib/images/testimonials/xue.webp differ diff --git a/src/lib/layout/shell.svelte b/src/lib/layout/shell.svelte index bfc06264f..5f76c05f2 100644 --- a/src/lib/layout/shell.svelte +++ b/src/lib/layout/shell.svelte @@ -205,7 +205,7 @@ {/if} - {#if !$isNewWizardStatusOpen} + {#if !$isNewWizardStatusOpen && isProjectPage} {#if currentReview?.image} {:else} diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 3564a1c27..d23fa3346 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -620,7 +620,7 @@ export const billingURL = derived( ($page) => `${base}/organization-${$page.data?.organization?.$id}/billing` ); -export const hideBillingHeaderRoutes = ['/console/create-organization', '/console/account']; +export const hideBillingHeaderRoutes = [base + '/create-organization', base + '/account']; export function calculateExcess(addon: AggregationTeam, plan: Plan) { return { diff --git a/src/lib/stores/feedback.ts b/src/lib/stores/feedback.ts index 30dc99687..8b140c0ca 100644 --- a/src/lib/stores/feedback.ts +++ b/src/lib/stores/feedback.ts @@ -144,7 +144,7 @@ function createFeedbackStore() { message, email, customFields, - firstname: name || 'Unknown', + firstname: (name || 'Unknown').slice(0, 40), metaFields: { source: get(feedback).source, orgId, diff --git a/src/lib/stores/preferences.ts b/src/lib/stores/preferences.ts index 36419be28..fdcb89f7e 100644 --- a/src/lib/stores/preferences.ts +++ b/src/lib/stores/preferences.ts @@ -66,6 +66,19 @@ function safePrefsKey(widthPreferences: TeamPreferences['widths'], from: string, } } +function safePrefsKeyForOrder( + orderPreferences: TeamPreferences['order'], + from: string, + to: string +) { + if (orderPreferences.includes(from)) { + const index = orderPreferences.indexOf(from); + if (index !== -1) { + orderPreferences[index] = to; + } + } +} + // rare cases where the value was an array, probably due to PHP backend. function ensureObjectProperty, K extends keyof T>( obj: T | null | undefined, @@ -239,7 +252,9 @@ function createPreferences() { }, getColumnOrder(tableId: string): TeamPreferences['order'] { - return teamPreferences?.columnOrder?.[tableId] ?? []; + const columnOrder = teamPreferences?.columnOrder?.[tableId] ?? []; + safePrefsKeyForOrder(columnOrder, '$uid', '$id'); + return columnOrder; }, async saveColumnOrder(orgId: string, tableId: string, columnIds: TeamPreferences['order']) { @@ -247,6 +262,10 @@ function createPreferences() { teamPreferences.columnOrder[tableId] = columnIds; + for (const tableOrder of Object.values(teamPreferences.columnOrder)) { + safePrefsKeyForOrder(tableOrder, '$id', '$uid'); + } + await sdk.forConsole.teams.updatePrefs({ teamId: orgId, prefs: teamPreferences diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte index 1b0748e12..a8e6e30c7 100644 --- a/src/routes/(console)/+layout.svelte +++ b/src/routes/(console)/+layout.svelte @@ -59,7 +59,6 @@ import type { LayoutData } from './$types'; export let data: LayoutData; - let emailBannerClosed = false; function kebabToSentenceCase(str: string) { return str @@ -83,7 +82,7 @@ keys: ['g', 'p'], group: 'navigation', disabled: - (page.url.pathname.includes('/console/organization-') && + (page.url.pathname.includes(base + '/organization-') && !page.url.pathname.endsWith('/members') && !page.url.pathname.endsWith('/settings')) || !$canSeeProjects, @@ -336,20 +335,18 @@