diff --git a/apps/web/src/controllers/AppNoPageAccess.tsx b/apps/web/src/controllers/AppNoPageAccess.tsx index 789095106..38cbfb6c2 100644 --- a/apps/web/src/controllers/AppNoPageAccess.tsx +++ b/apps/web/src/controllers/AppNoPageAccess.tsx @@ -6,32 +6,41 @@ import { BusterLogo } from '@/assets/svg/BusterLogo'; import { Button } from '@/components/ui/buttons'; import { Title } from '@/components/ui/typography'; import { useSupabaseContext } from '@/context/Supabase'; -import { BusterRoutes, createBusterRoute } from '@/routes'; +import { + BusterRoutes, + createBusterRoute, + createPathnameToBusterRoute, + extractPathParamsFromRoute, + getEmbedAssetToRegularAsset +} from '@/routes'; export const AppNoPageAccess: React.FC<{ assetId: string; }> = React.memo(({ assetId }) => { const isAnonymousUser = useSupabaseContext((x) => x.isAnonymousUser); - + const { buttonText, linkUrl } = useMemo(() => { - const isEmbedPage = typeof window !== 'undefined' && window.location.pathname.startsWith('/embed'); - + const isEmbedPage = + typeof window !== 'undefined' && window.location.pathname.startsWith('/embed'); + const shouldShowLogin = isAnonymousUser || isEmbedPage; - + if (shouldShowLogin) { - const currentUrl = typeof window !== 'undefined' - ? `${window.location.pathname}${window.location.search}` - : ''; - + const currentUrl = + typeof window !== 'undefined' ? `${window.location.pathname}${window.location.search}` : ''; + + const linkUrl = getEmbedAssetToRegularAsset(currentUrl); + return { - buttonText: 'Login', - linkUrl: createBusterRoute({ - route: BusterRoutes.AUTH_LOGIN, - next: encodeURIComponent(currentUrl) - }) + buttonText: 'Login to view asset', + linkUrl: + linkUrl || + createBusterRoute({ + route: BusterRoutes.AUTH_LOGIN + }) }; } - + return { buttonText: 'Go home', linkUrl: createBusterRoute({ diff --git a/apps/web/src/routes/busterRoutes/assetPageChecks.test.ts b/apps/web/src/routes/busterRoutes/assetPageChecks.test.ts index 22966d2a7..9de5badb6 100644 --- a/apps/web/src/routes/busterRoutes/assetPageChecks.test.ts +++ b/apps/web/src/routes/busterRoutes/assetPageChecks.test.ts @@ -1,6 +1,6 @@ import { NextRequest } from 'next/server'; import { describe, expect, it, vi } from 'vitest'; -import { getEmbedAssetRedirect } from './assetPageChecks'; +import { getEmbedAssetRedirect, getEmbedAssetToRegularAsset } from './assetPageChecks'; vi.mock('next/server', () => ({ NextRequest: vi.fn().mockImplementation((url) => ({ @@ -66,3 +66,33 @@ describe('getEmbedAssetRedirect', () => { expect(redirect).toBeUndefined(); }); }); + +describe('getEmbedAssetToRegularAsset', () => { + it('should convert embed metric URL to regular metric chart URL', () => { + // Test converting an embed metric URL to the corresponding regular app metric chart URL + const embedMetricUrl = '/embed/metrics/123'; + const result = getEmbedAssetToRegularAsset(embedMetricUrl); + expect(result).toBe('/app/metrics/123/chart'); + }); + + it('should convert embed dashboard URL to regular dashboard URL', () => { + // Test converting an embed dashboard URL to the corresponding regular app dashboard URL + const embedDashboardUrl = '/embed/dashboards/456'; + const result = getEmbedAssetToRegularAsset(embedDashboardUrl); + expect(result).toBe('/app/dashboards/456'); + }); + + it('should return undefined for regular app URLs (non-embed)', () => { + // Test that regular app URLs that are not embed URLs return undefined + const regularAppUrl = '/app/metrics/123/chart'; + const result = getEmbedAssetToRegularAsset(regularAppUrl); + expect(result).toBeUndefined(); + }); + + it('should return undefined for invalid or unknown URLs', () => { + // Test that completely unknown/invalid URLs return undefined + const invalidUrl = '/some/random/unknown/path'; + const result = getEmbedAssetToRegularAsset(invalidUrl); + expect(result).toBeUndefined(); + }); +}); diff --git a/apps/web/src/routes/busterRoutes/assetPageChecks.ts b/apps/web/src/routes/busterRoutes/assetPageChecks.ts index 3e5424315..017ffe2f5 100644 --- a/apps/web/src/routes/busterRoutes/assetPageChecks.ts +++ b/apps/web/src/routes/busterRoutes/assetPageChecks.ts @@ -45,6 +45,12 @@ const assetRedirectRecord: Partial> = { [BusterRoutes.APP_CHAT_ID_DASHBOARD_ID_METRIC_ID_SQL]: BusterRoutes.EMBED_METRIC_ID }; +const embedAssetToRegularAssetRecord: Record = { + [BusterRoutes.EMBED_METRIC_ID]: BusterRoutes.APP_METRIC_ID_CHART, + [BusterRoutes.EMBED_DASHBOARD_ID]: BusterRoutes.APP_DASHBOARD_ID, + [BusterRoutes.EMBED_COLLECTION_ID]: BusterRoutes.APP_COLLECTIONS_ID +}; + const publicPages: BusterRoutes[] = [ BusterRoutes.APP_METRIC_ID_CHART, BusterRoutes.APP_DASHBOARD_ID, @@ -87,3 +93,13 @@ export const getEmbedAssetRedirect = (request: NextRequest): string | undefined return undefined; }; + +export const getEmbedAssetToRegularAsset = (pathnameAndQueryParams: string) => { + const route = createPathnameToBusterRoute(pathnameAndQueryParams); + const matched = embedAssetToRegularAssetRecord[route as BusterEmbedRoutes]; + + if (matched) { + const params = extractPathParamsFromRoute(pathnameAndQueryParams); + return createBusterRoute({ route: matched, ...(params as any) }); + } +}; diff --git a/apps/web/src/routes/busterRoutes/busterEmbedRoutes.ts b/apps/web/src/routes/busterRoutes/busterEmbedRoutes.ts index e307d27d3..a3503001c 100644 --- a/apps/web/src/routes/busterRoutes/busterEmbedRoutes.ts +++ b/apps/web/src/routes/busterRoutes/busterEmbedRoutes.ts @@ -1,6 +1,7 @@ export enum BusterEmbedRoutes { EMBED_METRIC_ID = '/embed/metrics/:metricId', - EMBED_DASHBOARD_ID = '/embed/dashboards/:dashboardId' + EMBED_DASHBOARD_ID = '/embed/dashboards/:dashboardId', + EMBED_COLLECTION_ID = '/embed/collections/:collectionId' } export type BusterEmbedRoutesWithArgs = { @@ -12,4 +13,8 @@ export type BusterEmbedRoutesWithArgs = { route: BusterEmbedRoutes.EMBED_DASHBOARD_ID; dashboardId: string; }; + [BusterEmbedRoutes.EMBED_COLLECTION_ID]: { + route: BusterEmbedRoutes.EMBED_COLLECTION_ID; + collectionId: string; + }; };