11import { NavigationPath , RouteBlocking } from '../types' ;
2-
3- /**
4- * Configuration for generating component-specific routes
5- */
62export interface EmbedRouteConfig {
73 embedComponentType : string ;
84 liveboardId ?: string ;
@@ -11,21 +7,13 @@ export interface EmbedRouteConfig {
117 pageId ?: string ;
128 path ?: string ;
139}
14-
15- /**
16- * Result of route validation and processing
17- */
1810export interface RouteValidationResult {
1911 allowedRoutes : ( NavigationPath | string ) [ ] ;
2012 blockedRoutes : ( NavigationPath | string ) [ ] ;
2113 hasError : boolean ;
2214 errorMessage : string ;
2315}
2416
25- /**
26- * Default routes for each embed component type
27- * AppEmbed and LiveboardEmbed have dynamic routes, so they're empty here
28- */
2917const COMPONENT_DEFAULT_ROUTES : Record < string , string [ ] > = {
3018 AppEmbed : [ ] , // Matches all paths - routes generated dynamically
3119 'bodyless-conversation' : [ '/embed/conv-assist-answer' , '/conv-assist-answer' ] ,
@@ -36,9 +24,6 @@ const COMPONENT_DEFAULT_ROUTES: Record<string, string[]> = {
3624 SearchEmbed : [ '/embed/answer' , '/insights/answer' ] ,
3725} ;
3826
39- /**
40- * Maps page IDs to their corresponding navigation paths
41- */
4227const PAGE_ID_TO_ROUTES : Record < string , NavigationPath [ ] > = {
4328 answers : [ NavigationPath . Answers , NavigationPath . HomeAnswers ] ,
4429 data : [ NavigationPath . DataModelPage ] ,
@@ -50,14 +35,8 @@ const PAGE_ID_TO_ROUTES: Record<string, NavigationPath[]> = {
5035 spotiq : [ NavigationPath . HomeSpotIQAnalysis , NavigationPath . Insights ] ,
5136} ;
5237
53- /**
54- * Routes that must never be blocked for embed functionality to work
55- */
5638const PROTECTED_ROUTES = [ NavigationPath . Login , NavigationPath . EmbedAccessDeniedPage ] ;
5739
58- /**
59- * Generates LiveboardEmbed-specific routes based on configuration
60- */
6140const generateLiveboardRoutes = ( config : EmbedRouteConfig ) : string [ ] => {
6241 const { liveboardId, vizId, activeTabId } = config ;
6342 const routes : string [ ] = [ ] ;
@@ -66,28 +45,22 @@ const generateLiveboardRoutes = (config: EmbedRouteConfig): string[] => {
6645 return routes ;
6746 }
6847
69- // Base liveboard routes
7048 routes . push ( `/embed/viz/${ liveboardId } ` ) ;
7149 routes . push ( `/insights/pinboard/${ liveboardId } ` ) ;
7250 routes . push ( `/embed/insights/viz/${ liveboardId } ` ) ;
7351
74- // Visualization-specific routes
7552 if ( vizId ) {
7653 const vizRoute = activeTabId
7754 ? `/embed/viz/${ liveboardId } /tab/${ activeTabId } /${ vizId } `
7855 : `/embed/viz/${ liveboardId } /${ vizId } ` ;
7956 routes . push ( vizRoute ) ;
8057 } else if ( activeTabId ) {
81- // Tab route without specific visualization
8258 routes . push ( `/embed/viz/${ liveboardId } /tab/${ activeTabId } ` ) ;
8359 }
8460
8561 return routes ;
8662} ;
8763
88- /**
89- * Generates AppEmbed-specific routes based on configuration
90- */
9164const generateAppEmbedRoutes = ( config : EmbedRouteConfig ) : string [ ] => {
9265 const { path, pageId } = config ;
9366 const routes : string [ ] = [ ] ;
@@ -104,24 +77,14 @@ const generateAppEmbedRoutes = (config: EmbedRouteConfig): string[] => {
10477 return routes ;
10578} ;
10679
107- /**
108- * Retrieves navigation routes for a specific page ID
109- */
11080const getRoutesByPageId = ( pageId : string ) : string [ ] => {
11181 return PAGE_ID_TO_ROUTES [ pageId ] || [ ] ;
11282} ;
11383
114- /**
115- * Normalizes a route by removing trailing wildcard
116- */
11784const normalizeRoute = ( route : string ) : string => {
11885 return route . replace ( / \/ \* $ / , '' ) ;
11986} ;
12087
121- /**
122- * Checks if two routes conflict with each other
123- * Routes conflict if one is a prefix of the other or they are identical
124- */
12588const areRoutesConflicting = ( route1 : string , route2 : string ) : boolean => {
12689 const normalized1 = normalizeRoute ( route1 ) ;
12790 const normalized2 = normalizeRoute ( route2 ) ;
@@ -133,9 +96,6 @@ const areRoutesConflicting = (route1: string, route2: string): boolean => {
13396 ) ;
13497} ;
13598
136- /**
137- * Checks if any blocked route conflicts with protected or auto-allowed routes
138- */
13999const hasRouteConflict = (
140100 blockedRoutes : ( NavigationPath | string ) [ ] ,
141101 protectedRoutes : string [ ] ,
@@ -147,16 +107,11 @@ const hasRouteConflict = (
147107 ) ;
148108} ;
149109
150- /**
151- * Filters out null and undefined values from route arrays
152- */
110+
153111const sanitizeRoutes = ( routes : ( NavigationPath | string ) [ ] ) : ( NavigationPath | string ) [ ] => {
154112 return routes . filter ( ( route ) => route !== undefined && route !== null ) ;
155113} ;
156114
157- /**
158- * Generate component-specific allowed routes based on embed configuration
159- */
160115export const generateComponentRoutes = ( config : EmbedRouteConfig ) : string [ ] => {
161116 const { embedComponentType } = config ;
162117
@@ -172,10 +127,6 @@ export const generateComponentRoutes = (config: EmbedRouteConfig): string[] => {
172127 }
173128} ;
174129
175- /**
176- * Validates and processes route blocking configuration
177- * Returns allowed and blocked routes along with any validation errors
178- */
179130export const validateAndProcessRoutes = (
180131 routeBlocking ?: RouteBlocking ,
181132 embedConfig ?: EmbedRouteConfig ,
@@ -187,18 +138,15 @@ export const validateAndProcessRoutes = (
187138 errorMessage : routeBlocking ?. accessDeniedMessage || '' ,
188139 } ;
189140
190- // No route blocking configured
191141 if ( ! routeBlocking ) {
192142 return defaultResult ;
193143 }
194144
195145 const { blockedRoutes, allowedRoutes, accessDeniedMessage = '' } = routeBlocking ;
196146
197- // Validation: Cannot have both blocked and allowed routes
198147 if ( blockedRoutes && allowedRoutes ) {
199148 return {
200- allowedRoutes : [ ] ,
201- blockedRoutes : [ ] ,
149+ ...defaultResult ,
202150 hasError : true ,
203151 errorMessage :
204152 'You cannot have both blockedRoutes and allowedRoutes set at the same time' ,
@@ -207,47 +155,37 @@ export const validateAndProcessRoutes = (
207155
208156 const componentRoutes = generateComponentRoutes ( embedConfig ) ;
209157
210- // Process allowed routes
211158 if ( allowedRoutes ) {
212159 const sanitizedAllowedRoutes = sanitizeRoutes ( allowedRoutes ) ;
213160 return {
161+ ...defaultResult ,
214162 allowedRoutes : [ ...componentRoutes , ...sanitizedAllowedRoutes , ...PROTECTED_ROUTES ] ,
215- blockedRoutes : [ ] ,
216- hasError : false ,
217- errorMessage : accessDeniedMessage ,
218163 } ;
219164 }
220165
221- // Process blocked routes
222166 if ( blockedRoutes ) {
223167 const sanitizedBlockedRoutes = sanitizeRoutes ( blockedRoutes ) ;
224168
225- // Validation: Cannot block protected routes (login, access denied page)
226169 if ( hasRouteConflict ( sanitizedBlockedRoutes , PROTECTED_ROUTES ) ) {
227170 return {
228- allowedRoutes : [ ] ,
229- blockedRoutes : [ ] ,
171+ ...defaultResult ,
230172 hasError : true ,
231173 errorMessage : 'You cannot block the login or embed access denied page' ,
232174 } ;
233175 }
234176
235- // Validation: Cannot block routes required by the embed component
236177 if ( hasRouteConflict ( sanitizedBlockedRoutes , componentRoutes ) ) {
237178 return {
238- allowedRoutes : [ ] ,
239- blockedRoutes : [ ] ,
179+ ...defaultResult ,
240180 hasError : true ,
241181 errorMessage :
242182 'You cannot block a route that is being embedded. The path specified in AppEmbed configuration conflicts with blockedRoutes.' ,
243183 } ;
244184 }
245185
246186 return {
247- allowedRoutes : [ ] ,
187+ ... defaultResult ,
248188 blockedRoutes : sanitizedBlockedRoutes ,
249- hasError : false ,
250- errorMessage : accessDeniedMessage ,
251189 } ;
252190 }
253191
0 commit comments