diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ab33a8f37..91c98b81f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -42,6 +42,7 @@ jobs: "PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}" "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY }}" "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + "SENTRY_RELEASE=${{ github.event.release.tag_name }}" publish-cloud-stage: runs-on: ubuntu-latest steps: diff --git a/Dockerfile b/Dockerfile index 9827b2fb1..9c33636a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN npm i -g corepack@latest RUN corepack enable +RUN corepack prepare pnpm@10.0.0 --activate ADD ./package.json /app/package.json ADD ./pnpm-lock.yaml /app/pnpm-lock.yaml @@ -25,12 +26,14 @@ ARG PUBLIC_GROWTH_ENDPOINT ARG PUBLIC_STRIPE_KEY ARG SENTRY_AUTH_TOKEN ARG PUBLIC_PROJECT_PROFILE +ARG SENTRY_RELEASE ENV PUBLIC_APPWRITE_ENDPOINT=$PUBLIC_APPWRITE_ENDPOINT ENV PUBLIC_GROWTH_ENDPOINT=$PUBLIC_GROWTH_ENDPOINT ENV PUBLIC_CONSOLE_MODE=$PUBLIC_CONSOLE_MODE ENV PUBLIC_STRIPE_KEY=$PUBLIC_STRIPE_KEY ENV SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN +ENV SENTRY_RELEASE=$SENTRY_RELEASE ENV PUBLIC_PROJECT_PROFILE=$PUBLIC_PROJECT_PROFILE ENV NODE_OPTIONS=--max_old_space_size=8192 @@ -41,4 +44,4 @@ FROM nginx:1.27-alpine EXPOSE 80 COPY docker/nginx.conf /etc/nginx/conf.d/default.conf -COPY --from=build /app/build /usr/share/nginx/html/console \ No newline at end of file +COPY --from=build /app/build /usr/share/nginx/html/console diff --git a/package.json b/package.json index d7988c84a..2671ca225 100644 --- a/package.json +++ b/package.json @@ -22,20 +22,21 @@ }, "dependencies": { "@appwrite.io/console": "https://pkg.pr.new/appwrite/appwrite/@appwrite.io/console@e2f082e", + "@appwrite.io/pink": "0.25.0", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@207628e", + "@appwrite.io/pink-icons-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-icons-svelte@bd21ff7f", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@16d19d7", + "@appwrite.io/pink-svelte": "https://pkg.pr.new/appwrite/pink/@appwrite.io/pink-svelte@cbf05a1", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", "@stripe/stripe-js": "^3.5.0", "ai": "^2.2.37", "analytics": "^0.8.16", + "@ai-sdk/svelte": "^1.1.22", "cron-parser": "^4.9.0", "dayjs": "^1.11.13", "deep-equal": "^2.2.3", "echarts": "^5.6.0", - "envfile": "^7.1.0", "ignore": "^6.0.2", "monaco-editor": "^0.52.2", "nanoid": "^5.1.5", @@ -50,7 +51,7 @@ }, "devDependencies": { "@eslint/compat": "^1.2.7", - "@eslint/js": "^9.23.0", + "@eslint/js": "^9.24.0", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.5", "@playwright/test": "^1.51.1", @@ -86,7 +87,7 @@ "svelte-sequential-preprocessor": "^2.0.2", "tslib": "^2.8.1", "typescript": "^5.8.2", - "typescript-eslint": "^8.29.1", + "typescript-eslint": "^8.30.1", "vite": "^6.2.3", "vitest": "^3.0.0" }, diff --git a/playwright.config.ts b/playwright.config.ts index bad8f9fca..de119fa1f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -13,7 +13,7 @@ const config: PlaywrightTestConfig = { webServer: { timeout: 120000, env: { - PUBLIC_APPWRITE_ENDPOINT: 'https://console-testing-2.appwrite.org/v1', + PUBLIC_APPWRITE_ENDPOINT: 'https://stage.cloud.appwrite.io/v1', PUBLIC_CONSOLE_MODE: 'cloud', PUBLIC_STRIPE_KEY: 'pk_test_51LT5nsGYD1ySxNCyd7b304wPD8Y1XKKWR6hqo6cu3GIRwgvcVNzoZv4vKt5DfYXL1gRGw4JOqE19afwkJYJq1g3K004eVfpdWn' diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 6b359f6dd..78e7551b7 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -6,6 +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'; function plausible(domain: string): AnalyticsPlugin { if (!browser) return { name: 'analytics-plugin-plausible' }; @@ -64,6 +65,8 @@ export function trackEvent(name: string, data: object = null): void { }; } + data = { ...data, ...getReferrerAndUtmSource() }; + if (ENV.DEV || ENV.PREVIEW) { console.debug(`[Analytics] Event ${name} ${path}`, data); } else { @@ -138,6 +141,8 @@ export function isTrackingAllowed() { } export enum Click { + BackupCopyIdClick = 'click_backup_copy_id', + BackupDeleteClick = 'click_backup_delete', BackupRestoreClick = 'click_backup_restore', BreadcrumbClick = 'click_breadcrumb', ConnectRepositoryClick = 'click_connect_repository', diff --git a/src/lib/charts/legend.svelte b/src/lib/charts/legend.svelte index 2e72c1410..47489efb2 100644 --- a/src/lib/charts/legend.svelte +++ b/src/lib/charts/legend.svelte @@ -8,16 +8,23 @@
{#each legendData as { name, value }, index} - {@const formattedValue = typeof value === 'number' ? formatNumberWithCommas(value) : value} + {@const formattedValue = + typeof value === 'number' + ? numberFormat === 'comma' + ? formatNumberWithCommas(value) + : abbreviateNumber(value, decimalsForAbbreviate) + : value} {name} ({formattedValue}) diff --git a/src/lib/commandCenter/panels/ai.svelte b/src/lib/commandCenter/panels/ai.svelte index 586c523d3..9bda77da8 100644 --- a/src/lib/commandCenter/panels/ai.svelte +++ b/src/lib/commandCenter/panels/ai.svelte @@ -7,7 +7,7 @@ import { AvatarInitials, Code, LoadingDots, SvgIcon } from '$lib/components'; import { user } from '$lib/stores/user'; - import { useCompletion } from 'ai/svelte'; + import { useCompletion } from '@ai-sdk/svelte'; import { subPanels } from '../subPanels'; import { isLanguage, type Language } from '$lib/components/code.svelte'; @@ -20,7 +20,8 @@ headers: { 'x-appwrite-project': 'console' }, - credentials: 'include' + credentials: 'include', + streamProtocol: 'text' }); const examples = [ @@ -179,7 +180,7 @@ {#if $isLoading || answer}
-
{getInitials($user.name)}
+
{getInitials($user.name || $user.email)}

{previousQuestion}

diff --git a/src/lib/components/billing/alerts/newDevUpgradePro.svelte b/src/lib/components/billing/alerts/newDevUpgradePro.svelte index 29296189a..ab48d3798 100644 --- a/src/lib/components/billing/alerts/newDevUpgradePro.svelte +++ b/src/lib/components/billing/alerts/newDevUpgradePro.svelte @@ -2,7 +2,7 @@ import { base } from '$app/paths'; import { page } from '$app/state'; import { Click, trackEvent } from '$lib/actions/analytics'; - import { BillingPlan } from '$lib/constants'; + import { BillingPlan, NEW_DEV_PRO_UPGRADE_COUPON } from '$lib/constants'; import { Button } from '$lib/elements/forms'; import { organization } from '$lib/stores/organization'; import { activeHeaderAlert } from '$routes/(console)/store'; @@ -29,7 +29,7 @@ secondary fullWidthMobile class="u-line-height-1" - href={`${base}/apply-credit?code=appw50&org=${$organization.$id}`} + href={`${base}/apply-credit?code=${NEW_DEV_PRO_UPGRADE_COUPON}&org=${$organization.$id}`} on:click={() => { trackEvent(Click.CreditsRedeemClick, { from: 'button', diff --git a/src/lib/components/billing/alerts/paymentFailed.svelte b/src/lib/components/billing/alerts/paymentFailed.svelte new file mode 100644 index 000000000..9646864a9 --- /dev/null +++ b/src/lib/components/billing/alerts/paymentFailed.svelte @@ -0,0 +1,25 @@ + + +{#if $failedInvoice && $failedInvoice.teamId === $organization.$id && isOnProjects} + + To avoid service disruptions in your projects, please verify your payment details and try + again. + + + + +{/if} diff --git a/src/lib/components/billing/couponInput.svelte b/src/lib/components/billing/couponInput.svelte index 8217b23fc..85e73411c 100644 --- a/src/lib/components/billing/couponInput.svelte +++ b/src/lib/components/billing/couponInput.svelte @@ -3,6 +3,7 @@ import { formatCurrency } from '$lib/helpers/numbers'; import type { Coupon } from '$lib/sdk/billing'; import { sdk } from '$lib/stores/sdk'; + import { Layout } from '@appwrite.io/pink-svelte'; import { createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); @@ -17,7 +18,7 @@ async function addCoupon() { try { - const response = await sdk.forConsole.billing.getCoupon(coupon); + const response = await sdk.forConsole.billing.getCouponAccount(coupon); couponData = response; dispatch('validation', couponData); coupon = null; @@ -36,17 +37,19 @@ } - + + + - + {#if couponData?.status === 'error'}
diff --git a/src/lib/components/billing/discountsApplied.svelte b/src/lib/components/billing/discountsApplied.svelte new file mode 100644 index 000000000..e77bf3ca3 --- /dev/null +++ b/src/lib/components/billing/discountsApplied.svelte @@ -0,0 +1,49 @@ + + +{#if value > 0} + +
+

+ + + {label} + +

+ {#if !fixedCoupon && label.toLowerCase() === 'credits'} + + {/if} +
+ {#if value >= 100} +

Credits applied

+ {:else} + -{formatCurrency(value)} + {/if} +
+{/if} diff --git a/src/lib/components/billing/estimatedTotal.svelte b/src/lib/components/billing/estimatedTotal.svelte new file mode 100644 index 000000000..7e7e84803 --- /dev/null +++ b/src/lib/components/billing/estimatedTotal.svelte @@ -0,0 +1,144 @@ + + +{#if estimation} + + + {#if estimation} + {#each estimation.items ?? [] as item} + {#if item.value > 0} + +

{item.label}

+

{formatCurrency(item.value)}

+
+ {/if} + {/each} + {#each estimation.discounts ?? [] as item} + + {/each} +
+ +

Total due

+

+ {formatCurrency(estimation.grossAmount)} +

+
+ +

+ You'll pay {formatCurrency(estimation.grossAmount)} now. + {#if couponData?.code}Once your credits run out,{:else}Then{/if} you'll be charged + {formatCurrency(estimation.amount)} every 30 days. +

+ {/if} + + + {#if budgetEnabled} +
+ +
+ {/if} +
+
+{/if} diff --git a/src/lib/components/billing/estimatedTotalBox.svelte b/src/lib/components/billing/estimatedTotalBox.svelte index e8adcb489..112d506c1 100644 --- a/src/lib/components/billing/estimatedTotalBox.svelte +++ b/src/lib/components/billing/estimatedTotalBox.svelte @@ -43,7 +43,7 @@ Additional seats ({collaborators?.length}) + >Additional seats ({collaborators?.length ?? 0}) {formatCurrency(extraSeatsCost)} diff --git a/src/lib/components/billing/index.ts b/src/lib/components/billing/index.ts index 266d217d8..1cc70d3d9 100644 --- a/src/lib/components/billing/index.ts +++ b/src/lib/components/billing/index.ts @@ -2,8 +2,9 @@ export { default as PaymentBoxes } from './paymentBoxes.svelte'; export { default as CouponInput } from './couponInput.svelte'; export { default as SelectPaymentMethod } from './selectPaymentMethod.svelte'; export { default as UsageRates } from './usageRates.svelte'; -export { default as EstimatedTotalBox } from './estimatedTotalBox.svelte'; export { default as PlanComparisonBox } from './planComparisonBox.svelte'; export { default as EmptyCardCloud } from './emptyCardCloud.svelte'; export { default as CreditsApplied } from './creditsApplied.svelte'; export { default as PlanSelection } from './planSelection.svelte'; +export { default as EstimatedTotal } from './estimatedTotal.svelte'; +export { default as SelectPlan } from './selectPlan.svelte'; diff --git a/src/lib/components/billing/planExcess.svelte b/src/lib/components/billing/planExcess.svelte index f2f874d5e..02793dc70 100644 --- a/src/lib/components/billing/planExcess.svelte +++ b/src/lib/components/billing/planExcess.svelte @@ -2,19 +2,17 @@ import { calculateExcess, plansInfo, tierToPlan, type Tier } from '$lib/stores/billing'; import { organization } from '$lib/stores/organization'; import { toLocaleDate } from '$lib/helpers/date'; - import { Button } from '$lib/elements/forms'; import { humanFileSize } from '$lib/helpers/sizeConvertion'; import { abbreviateNumber } from '$lib/helpers/numbers'; import { formatNum } from '$lib/helpers/string'; import { onMount } from 'svelte'; - import type { OrganizationUsage } from '$lib/sdk/billing'; + import type { Aggregation } from '$lib/sdk/billing'; import { sdk } from '$lib/stores/sdk'; import { BillingPlan } from '$lib/constants'; import { Alert, Icon, Table, Tooltip } from '@appwrite.io/pink-svelte'; import { IconInfo } from '@appwrite.io/pink-icons-svelte'; export let tier: Tier; - export let members: number; const plan = $plansInfo?.get(tier); let excess: { @@ -24,16 +22,15 @@ executions?: number; members?: number; } = null; - let usage: OrganizationUsage = null; + let aggregation: Aggregation = null; let showExcess = false; onMount(async () => { - usage = await sdk.forConsole.billing.listUsage( + aggregation = await sdk.forConsole.billing.getAggregation( $organization.$id, - $organization.billingCurrentInvoiceDate, - new Date().toISOString() + $organization.billingAggregationId ); - excess = calculateExcess(usage, plan, members); + excess = calculateExcess(aggregation, plan); showExcess = Object.values(excess).some((value) => value > 0); }); @@ -41,22 +38,16 @@ {#if showExcess} - Following payment of your final invoice, your organization will switch to the {tierToPlan( - BillingPlan.FREE - ).name} plan. {#if excess?.members > 0}All team members except the owner will be removed on - that date.{/if} Service disruptions may occur unless resource usage is reduced. - - - - + You will retain access to {tierToPlan($organization.billingPlan).name} plan features until your + billing period ends. After that, + {#if excess?.members > 0} + all team members except the owner will be removed, + {:else} + your organization will be limited to Free plan resources, + {/if} and service disruptions may occur if usage exceeds Free plan limits. @@ -73,7 +64,7 @@ {#if excess?.members} Organization members - {plan.members} members + {plan.addons.seats.limit} members

diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte index afcd3246e..dac287731 100644 --- a/src/lib/components/billing/selectPaymentMethod.svelte +++ b/src/lib/components/billing/selectPaymentMethod.svelte @@ -57,12 +57,13 @@ data: [method.brand] }; })} /> -

+ -
+ + {:else} @@ -79,6 +80,7 @@ Add + {/if} diff --git a/src/lib/components/billing/selectPlan.svelte b/src/lib/components/billing/selectPlan.svelte new file mode 100644 index 000000000..8aae2f0ac --- /dev/null +++ b/src/lib/components/billing/selectPlan.svelte @@ -0,0 +1,51 @@ + + +{#if billingPlan} +
    + {#each $plansInfo.values() as plan} +
  • + + +
    +

    + {plan.name} + {#if $organization?.billingPlan === plan.$id && !isNewOrg} + Current plan + {/if} +

    +

    + {plan.desc} +

    +

    + {formatCurrency(plan?.price ?? 0)} +

    +
    +
    +
    +
  • + {/each} +
+{/if} diff --git a/src/lib/components/billing/usageRates.svelte b/src/lib/components/billing/usageRates.svelte index e835284c2..4635a1d5a 100644 --- a/src/lib/components/billing/usageRates.svelte +++ b/src/lib/components/billing/usageRates.svelte @@ -43,6 +43,13 @@ ]; $: isFree = org.billingPlan === BillingPlan.FREE; + + // equal or above means unlimited! + $: getCorrectSeatsCountValue = (count: number): string | number => { + // php int max is always larger than js + const exceedsSafeLimit = count >= Number.MAX_SAFE_INTEGER; + return exceedsSafeLimit ? 'Unlimited' : count || 0; + }; @@ -75,10 +82,10 @@ {usage.resource} - {plan[usage.id] || 'Unlimited'} + {getCorrectSeatsCountValue(plan.addons.seats.limit)} - {formatCurrency(plan.addons?.member?.price)}/{usage?.unit} + {formatCurrency(plan.addons?.seats?.price)}/{usage?.unit} {:else} diff --git a/src/lib/components/billing/validateCreditModal.svelte b/src/lib/components/billing/validateCreditModal.svelte index ebdf09acb..130532a7b 100644 --- a/src/lib/components/billing/validateCreditModal.svelte +++ b/src/lib/components/billing/validateCreditModal.svelte @@ -19,7 +19,8 @@ async function addCoupon() { try { - const response = await sdk.forConsole.billing.getCoupon(coupon); + // const response = await sdk.forConsole.billing.getCoupon(coupon); + const response = await sdk.forConsole.billing.getCouponAccount(coupon); //TODO: double check that this is the correct method if (response.onlyNewOrgs && !isNewOrg) { show = false; @@ -37,6 +38,14 @@ message: 'Credits applied successfully' }); } + couponData = response; + dispatch('validation', couponData); + coupon = null; + show = false; + addNotification({ + type: 'success', + message: 'Credits applied successfully' + }); } catch (e) { error = e.message; } diff --git a/src/lib/components/boxAvatar.svelte b/src/lib/components/boxAvatar.svelte index c2400d897..7ba70c789 100644 --- a/src/lib/components/boxAvatar.svelte +++ b/src/lib/components/boxAvatar.svelte @@ -4,7 +4,7 @@ - +
diff --git a/src/lib/components/columnSelector.svelte b/src/lib/components/columnSelector.svelte new file mode 100644 index 000000000..37c1640ad --- /dev/null +++ b/src/lib/components/columnSelector.svelte @@ -0,0 +1,89 @@ + + +{#if $columns?.length} + + {@render children(toggle, selectedColumnsNumber)} + + + {#each $columns as column} + {#if !column?.exclude} + (column.hide = !column.hide)} + disabled={allowNoColumns + ? false + : selectedColumnsNumber <= 1 && column.hide !== true}> + + (column.hide = !column.hide)} /> + {column.title} + + + {/if} + {/each} + + + +{/if} diff --git a/src/lib/components/domains/cnameTable.svelte b/src/lib/components/domains/cnameTable.svelte index ca985afc6..9880f5ebf 100644 --- a/src/lib/components/domains/cnameTable.svelte +++ b/src/lib/components/domains/cnameTable.svelte @@ -54,8 +54,7 @@ - {$consoleVariables._APP_DOMAIN_TARGET_CNAME} + text={$consoleVariables._APP_DOMAIN_TARGET_CNAME} /> diff --git a/src/lib/components/domains/nameserverTable.svelte b/src/lib/components/domains/nameserverTable.svelte index be059890f..da5375bce 100644 --- a/src/lib/components/domains/nameserverTable.svelte +++ b/src/lib/components/domains/nameserverTable.svelte @@ -37,8 +37,7 @@ NS - - {nameserver} + {/each} diff --git a/src/lib/components/domains/recordTable.svelte b/src/lib/components/domains/recordTable.svelte index dba63ac6d..f39dea986 100644 --- a/src/lib/components/domains/recordTable.svelte +++ b/src/lib/components/domains/recordTable.svelte @@ -63,8 +63,7 @@ {variant.toUpperCase()} {subdomain || '@'} - - {setTarget()} + diff --git a/src/lib/components/dualTimeView.svelte b/src/lib/components/dualTimeView.svelte index e6ee84fb0..81862b475 100644 --- a/src/lib/components/dualTimeView.svelte +++ b/src/lib/components/dualTimeView.svelte @@ -69,7 +69,7 @@ if (!isMouseOverTooltip) { hideTooltip(); } - }, 50); + }, 150); } $: timeToString = time ? timeDifference(time) : 'Invalid time'; diff --git a/src/lib/components/emptyCardImageCloud.svelte b/src/lib/components/emptyCardImageCloud.svelte index 53f6c2124..2063c3388 100644 --- a/src/lib/components/emptyCardImageCloud.svelte +++ b/src/lib/components/emptyCardImageCloud.svelte @@ -7,13 +7,10 @@ export let noAspectRatio = false; - - + + {#if $$slots?.image} -
+
{/if} diff --git a/src/lib/components/emptySearch.svelte b/src/lib/components/emptySearch.svelte index 220a79f3c..fac974d5e 100644 --- a/src/lib/components/emptySearch.svelte +++ b/src/lib/components/emptySearch.svelte @@ -26,7 +26,7 @@ alignItems="center" wrap="wrap">

Total results: 0

- + {/if} diff --git a/src/lib/components/feedback/feedback.svelte b/src/lib/components/feedback/feedback.svelte index 9fc52afd3..2d1a7623c 100644 --- a/src/lib/components/feedback/feedback.svelte +++ b/src/lib/components/feedback/feedback.svelte @@ -11,6 +11,7 @@ import { addNotification } from '$lib/stores/notifications'; import { page } from '$app/state'; import { Typography } from '@appwrite.io/pink-svelte'; + import { project } from '$routes/(console)/project-[project]/store'; $: $selectedFeedback = feedbackOptions.find((option) => option.type === $feedback.type); @@ -24,8 +25,11 @@ page.url.href, $user.name, $user.email, - $organization.billingPlan, - $feedbackData.value + $organization?.billingPlan, + $feedbackData.value, + $organization?.$id, + $project?.$id, + $user.$id ); addNotification({ type: 'success', diff --git a/src/lib/components/filters/filtersBottomSheet.svelte b/src/lib/components/filters/filtersBottomSheet.svelte new file mode 100644 index 000000000..3d61e8b6b --- /dev/null +++ b/src/lib/components/filters/filtersBottomSheet.svelte @@ -0,0 +1,118 @@ + + + diff --git a/src/lib/components/filters/index.ts b/src/lib/components/filters/index.ts index eb4bd0f3d..5eed4dc72 100644 --- a/src/lib/components/filters/index.ts +++ b/src/lib/components/filters/index.ts @@ -4,3 +4,4 @@ export { default as CustomFilters } from './customFilters.svelte'; export { default as QuickFilters } from './quickFilters.svelte'; export { default as ParsedTagList } from './parsedTagList.svelte'; export { hasPageQueries, queryParamToMap, queries } from '$lib/components/filters/store'; +export { default as FiltersBottomSheet } from './filtersBottomSheet.svelte'; diff --git a/src/lib/components/filters/parsedTagList.svelte b/src/lib/components/filters/parsedTagList.svelte index 4b1faa05d..edbd5161e 100644 --- a/src/lib/components/filters/parsedTagList.svelte +++ b/src/lib/components/filters/parsedTagList.svelte @@ -8,7 +8,7 @@ {#if $parsedTags?.length} - {#each $parsedTags as tag} + {#each $parsedTags as tag (tag.tag)} ; export let analyticsSource: string; + export let openBottomSheet = false; - let openBottomSheet = false; + //TODO: remove this when all header are replace with `ResponsiveContainerHeader` let filterCols = $columns .map((col) => (col.filter !== false ? buildFilterCol(col) : null)) .filter((f) => f?.options); @@ -35,101 +30,6 @@ setFilters(localTags, filterCols, $columns); filterCols = filterCols; }); - - $: subSheets = filterCols.map((col) => { - return { - title: col.title, - top: { - title: col.title, - trailingIcon: IconChevronRight, - items: col.options.map((o) => { - return { - title: capitalize(o.label), - name: capitalize(o.label), - options: col.options, - checked: o.checked, - onClick: () => { - addFilterAndApply( - col.id, - col.title, - col.operator, - o.value, - generateFilterArrayValue(col, o.value), - $columns, - analyticsSource - ); - } - }; - }) - }, - bottom: { - name: 'Back', - items: [ - { - name: 'Back', - leadingIcon: IconChevronLeft, - navigatePrevious: true, - onClick: () => { - // navigate to the previous menu - } - } - ] - } - }; - }); - - $: organizationsBottomSheet = { - top: { - title: 'Filters', - items: filterCols.map((col) => { - return { - name: col.title, - onClick: () => - console.log(subSheets.find((sheet) => sheet?.title === col?.title)), - subMenu: subSheets.find((sheet) => sheet?.title === col?.title), - trailingIcon: IconChevronRight - }; - }) - }, - bottom: { - name: 'Clear All', - items: [ - { - name: 'Clear All', - onClick: () => { - filterCols.forEach((col) => { - addFilterAndApply( - col.id, - col.title, - col.operator, - null, - [], - $columns, - analyticsSource - ); - }); - } - } - ] - } - }; - - function generateFilterArrayValue(col: FilterData, value: string) { - if (!col?.array) return []; - - if (col.options?.find((opt) => opt.value === value)?.checked) { - return col.options - ?.filter((opt) => opt?.checked) - .map((opt) => opt.value) - .filter((item) => item !== value); - } else { - let arrayValue = - col.options?.filter((opt) => opt?.checked)?.map((opt) => opt.value) ?? []; - arrayValue = [...arrayValue, value]; - - return arrayValue; - } - } {#if $isSmallViewport} @@ -161,7 +61,7 @@ {/if} - {#each filterCols as filter} + {#each filterCols as filter (filter.title + filter.id)} {#if filter.options} + {/if} diff --git a/src/lib/components/filters/quickFilters.ts b/src/lib/components/filters/quickFilters.ts index fc09619b0..dce8e823d 100644 --- a/src/lib/components/filters/quickFilters.ts +++ b/src/lib/components/filters/quickFilters.ts @@ -25,7 +25,7 @@ export function buildFilterCol(col: Column, customOperator = null): FilterData { return { value: (element?.value ?? element) as string, label: (element?.label ?? element) as string, - checked: false + checked: undefined }; }) }; diff --git a/src/lib/components/filters/quickfiltersSubMenu.svelte b/src/lib/components/filters/quickfiltersSubMenu.svelte index a3aee392d..b49bef07e 100644 --- a/src/lib/components/filters/quickfiltersSubMenu.svelte +++ b/src/lib/components/filters/quickfiltersSubMenu.svelte @@ -43,7 +43,7 @@