frontend: Configures the application routing
Sets up domain-based routing for different app features. This change introduces a structured approach to managing application routes, making it easier to add, modify, and maintain different sections of the application. It configures routes for authentication, meetings, rooms, recordings, and the console.
This commit is contained in:
parent
ca2d41b05e
commit
082aa8480c
@ -0,0 +1,15 @@
|
||||
import { DomainRouteConfig } from '../../../shared/models/domain-routes.model';
|
||||
import { checkUserNotAuthenticatedGuard } from '../guards/auth.guard';
|
||||
|
||||
/**
|
||||
* Auth domain route configurations
|
||||
*/
|
||||
export const authDomainRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'login',
|
||||
loadComponent: () => import('../pages/login/login.component').then((m) => m.LoginComponent),
|
||||
canActivate: [checkUserNotAuthenticatedGuard]
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -2,6 +2,7 @@ import { Component } from '@angular/core';
|
||||
import { ConsoleNavLink } from '../../../../shared/models/sidenav.model';
|
||||
import { AuthService } from '../../../auth/services/auth.service';
|
||||
import { ConsoleNavComponent } from '../../components/console-nav/console-nav.component';
|
||||
import { consoleChildRoutes } from '../../routes/console.routes';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-console',
|
||||
@ -10,28 +11,25 @@ import { ConsoleNavComponent } from '../../components/console-nav/console-nav.co
|
||||
styleUrl: './console.component.scss'
|
||||
})
|
||||
export class ConsoleComponent {
|
||||
navLinks: ConsoleNavLink[] = [
|
||||
{ label: 'Overview', route: 'overview', icon: 'dashboard' },
|
||||
{ label: 'Rooms', route: 'rooms', icon: 'video_chat', iconClass: 'ov-room-icon' },
|
||||
{ label: 'Recordings', route: 'recordings', icon: 'video_library', iconClass: 'ov-recording-icon' },
|
||||
{
|
||||
label: 'Embedded',
|
||||
route: 'embedded',
|
||||
icon: 'code_blocks',
|
||||
iconClass: 'material-symbols-outlined ov-developer-icon'
|
||||
},
|
||||
{
|
||||
label: 'Users & Permissions',
|
||||
route: 'users-permissions',
|
||||
icon: 'passkey',
|
||||
iconClass: 'ov-users-permissions material-symbols-outlined'
|
||||
},
|
||||
{ label: 'Configuration', route: 'config', icon: 'settings', iconClass: 'ov-settings-icon' }
|
||||
navLinks: ConsoleNavLink[];
|
||||
|
||||
// { label: 'About', route: 'about', icon: 'info' }
|
||||
];
|
||||
|
||||
constructor(private authService: AuthService) {}
|
||||
constructor(private authService: AuthService) {
|
||||
// Build navigation links from console child route configurations
|
||||
this.navLinks = consoleChildRoutes
|
||||
.filter((config) => config.navMetadata) // Only include routes with navigation metadata
|
||||
.map((config) => ({
|
||||
label: config.navMetadata!.label,
|
||||
route: config.navMetadata!.route,
|
||||
icon: config.navMetadata!.icon,
|
||||
iconClass: config.navMetadata?.iconClass
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
// Sort by order if available
|
||||
const orderA = consoleChildRoutes.find((r) => r.navMetadata?.route === a.route)?.navMetadata?.order ?? 999;
|
||||
const orderB = consoleChildRoutes.find((r) => r.navMetadata?.route === b.route)?.navMetadata?.order ?? 999;
|
||||
return orderA - orderB;
|
||||
});
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.authService.logout();
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
import { Route } from '@angular/router';
|
||||
import { DomainRouteConfig } from '../../../shared/models/domain-routes.model';
|
||||
import { checkUserAuthenticatedGuard } from '../../auth/guards/auth.guard';
|
||||
import { recordingsConsoleRoutes } from '../../recordings/routes/recordings.routes';
|
||||
import { roomsConsoleRoutes } from '../../rooms/routes/rooms.routes';
|
||||
|
||||
/**
|
||||
* All console child routes configuration (includes console pages + rooms + recordings)
|
||||
* Used by ConsoleComponent to build navigation links
|
||||
*/
|
||||
export const consoleChildRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'overview',
|
||||
loadComponent: () => import('../pages/overview/overview.component').then((m) => m.OverviewComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Overview',
|
||||
route: 'overview',
|
||||
icon: 'dashboard',
|
||||
order: 1
|
||||
}
|
||||
},
|
||||
...roomsConsoleRoutes,
|
||||
...recordingsConsoleRoutes,
|
||||
{
|
||||
route: {
|
||||
path: 'embedded',
|
||||
loadComponent: () => import('../pages/embedded/embedded.component').then((m) => m.EmbeddedComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Embedded',
|
||||
route: 'embedded',
|
||||
icon: 'code_blocks',
|
||||
iconClass: 'material-symbols-outlined ov-developer-icon',
|
||||
order: 4
|
||||
}
|
||||
},
|
||||
{
|
||||
route: {
|
||||
path: 'users-permissions',
|
||||
loadComponent: () =>
|
||||
import('../pages/users-permissions/users-permissions.component').then((m) => m.UsersPermissionsComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Users & Permissions',
|
||||
route: 'users-permissions',
|
||||
icon: 'passkey',
|
||||
iconClass: 'ov-users-permissions material-symbols-outlined',
|
||||
order: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
route: {
|
||||
path: 'config',
|
||||
loadComponent: () => import('../pages/config/config.component').then((m) => m.ConfigComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Configuration',
|
||||
route: 'config',
|
||||
icon: 'settings',
|
||||
iconClass: 'ov-settings-icon',
|
||||
order: 6
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Console domain routes (error page + authenticated console shell with all child routes)
|
||||
* Used by base-routes.ts
|
||||
*/
|
||||
export const consoleDomainRoutes: Route[] = [
|
||||
{
|
||||
path: 'error',
|
||||
loadComponent: () => import('../pages/error/error.component').then((m) => m.ErrorComponent)
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('../pages/console/console.component').then((m) => m.ConsoleComponent),
|
||||
canActivate: [checkUserAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'overview',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
...consoleChildRoutes.map((config) => config.route),
|
||||
{ path: '**', redirectTo: 'overview' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
import { WebComponentProperty } from '@openvidu-meet/typings';
|
||||
import { extractRoomQueryParamsGuard } from '../../../shared/guards/extract-query-params.guard';
|
||||
import { removeQueryParamsGuard } from '../../../shared/guards/remove-query-params.guard';
|
||||
import { runGuardsSerially } from '../../../shared/guards/run-serially.guard';
|
||||
import { DomainRouteConfig } from '../../../shared/models/domain-routes.model';
|
||||
import { validateRoomAccessGuard } from '../../rooms/guards/room-validate-access.guard';
|
||||
|
||||
/**
|
||||
* Meeting domain route configurations
|
||||
*/
|
||||
export const meetingDomainRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'room/:room-id',
|
||||
loadComponent: () => import('../pages/meeting/meeting.component').then((m) => m.MeetingComponent),
|
||||
canActivate: [
|
||||
runGuardsSerially(
|
||||
extractRoomQueryParamsGuard,
|
||||
validateRoomAccessGuard,
|
||||
removeQueryParamsGuard(['secret', WebComponentProperty.E2EE_KEY])
|
||||
)
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
route: {
|
||||
path: 'disconnected',
|
||||
loadComponent: () => import('../pages/end-meeting/end-meeting.component').then((m) => m.EndMeetingComponent)
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,35 @@
|
||||
import { DomainRouteConfig } from '../../../shared/models/domain-routes.model';
|
||||
import { validateRecordingAccessGuard } from '../guards/recording-validate-access.guard';
|
||||
|
||||
/**
|
||||
* Recordings domain public route configurations
|
||||
*/
|
||||
export const recordingsDomainRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'recording/:recording-id',
|
||||
loadComponent: () =>
|
||||
import('../pages/view-recording/view-recording.component').then((m) => m.ViewRecordingComponent),
|
||||
canActivate: [validateRecordingAccessGuard]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Console child routes for recordings domain
|
||||
*/
|
||||
export const recordingsConsoleRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'recordings',
|
||||
loadComponent: () => import('../pages/recordings/recordings.component').then((m) => m.RecordingsComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Recordings',
|
||||
route: 'recordings',
|
||||
icon: 'video_library',
|
||||
iconClass: 'ov-recording-icon',
|
||||
order: 3
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,59 @@
|
||||
import { WebComponentProperty } from '@openvidu-meet/typings';
|
||||
import { extractRecordingQueryParamsGuard } from '../../../shared/guards/extract-query-params.guard';
|
||||
import { removeQueryParamsGuard } from '../../../shared/guards/remove-query-params.guard';
|
||||
import { runGuardsSerially } from '../../../shared/guards/run-serially.guard';
|
||||
import { DomainRouteConfig } from '../../../shared/models/domain-routes.model';
|
||||
import { checkEditableRoomGuard } from '../guards/room-edit-check.guard';
|
||||
import { validateRoomRecordingsAccessGuard } from '../guards/room-validate-access.guard';
|
||||
|
||||
/**
|
||||
* Rooms domain route configurations
|
||||
*/
|
||||
export const roomsDomainRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'room/:room-id/recordings',
|
||||
loadComponent: () =>
|
||||
import('../pages/room-recordings/room-recordings.component').then((m) => m.RoomRecordingsComponent),
|
||||
canActivate: [
|
||||
runGuardsSerially(
|
||||
extractRecordingQueryParamsGuard,
|
||||
validateRoomRecordingsAccessGuard,
|
||||
removeQueryParamsGuard(['secret', WebComponentProperty.E2EE_KEY])
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Console child routes for rooms domain
|
||||
*/
|
||||
export const roomsConsoleRoutes: DomainRouteConfig[] = [
|
||||
{
|
||||
route: {
|
||||
path: 'rooms',
|
||||
loadComponent: () => import('../pages/rooms/rooms.component').then((m) => m.RoomsComponent)
|
||||
},
|
||||
navMetadata: {
|
||||
label: 'Rooms',
|
||||
route: 'rooms',
|
||||
icon: 'video_chat',
|
||||
iconClass: 'ov-room-icon',
|
||||
order: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
route: {
|
||||
path: 'rooms/new',
|
||||
loadComponent: () => import('../pages/room-wizard/room-wizard.component').then((m) => m.RoomWizardComponent)
|
||||
}
|
||||
},
|
||||
{
|
||||
route: {
|
||||
path: 'rooms/:roomId/edit',
|
||||
loadComponent: () => import('../pages/room-wizard/room-wizard.component').then((m) => m.RoomWizardComponent),
|
||||
canActivate: [checkEditableRoomGuard]
|
||||
}
|
||||
}
|
||||
];
|
||||
@ -0,0 +1,39 @@
|
||||
import { Route } from '@angular/router';
|
||||
|
||||
/**
|
||||
* Navigation metadata for a domain route that should appear in the console navigation
|
||||
*/
|
||||
export interface DomainNavMetadata {
|
||||
/** Display label for the navigation link */
|
||||
label: string;
|
||||
/** Route path (relative to console) */
|
||||
route: string;
|
||||
/** Material icon name */
|
||||
icon: string;
|
||||
/** Optional CSS class for the icon */
|
||||
iconClass?: string;
|
||||
/** Optional order for sorting navigation items */
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete route configuration for a domain
|
||||
* Includes both the route definition and optional navigation metadata
|
||||
*/
|
||||
export interface DomainRouteConfig {
|
||||
/** Angular route configuration */
|
||||
route: Route;
|
||||
/** Optional navigation metadata (if this route should appear in console nav) */
|
||||
navMetadata?: DomainNavMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain routes registry
|
||||
* Maps domain identifiers to their route configurations
|
||||
*/
|
||||
export interface DomainRoutesRegistry {
|
||||
/** Console child routes (appear in the authenticated console area) */
|
||||
consoleRoutes: DomainRouteConfig[];
|
||||
/** Public routes (standalone routes outside console) */
|
||||
publicRoutes: DomainRouteConfig[];
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
export * from './app.model';
|
||||
export * from './config.model';
|
||||
export * from './domain-routes.model';
|
||||
export * from './navigation.model';
|
||||
export * from './notification.model';
|
||||
export * from './sidenav.model';
|
||||
export * from './storage.model';
|
||||
|
||||
|
||||
@ -1,132 +1,25 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { WebComponentProperty } from '@openvidu-meet/typings';
|
||||
import { checkUserAuthenticatedGuard, checkUserNotAuthenticatedGuard } from '../../domains/auth/guards/auth.guard';
|
||||
import { validateRecordingAccessGuard } from '../../domains/recordings/guards/recording-validate-access.guard';
|
||||
import { checkEditableRoomGuard } from '../../domains/rooms/guards/room-edit-check.guard';
|
||||
import {
|
||||
validateRoomAccessGuard,
|
||||
validateRoomRecordingsAccessGuard
|
||||
} from '../../domains/rooms/guards/room-validate-access.guard';
|
||||
import { extractRecordingQueryParamsGuard, extractRoomQueryParamsGuard } from '../guards/extract-query-params.guard';
|
||||
import { removeQueryParamsGuard } from '../guards/remove-query-params.guard';
|
||||
import { runGuardsSerially } from '../guards/run-serially.guard';
|
||||
export const baseRoutes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
loadComponent: () => import('../../domains/auth/pages/login/login.component').then((m) => m.LoginComponent),
|
||||
canActivate: [checkUserNotAuthenticatedGuard]
|
||||
},
|
||||
{
|
||||
path: 'room/:room-id',
|
||||
loadComponent: () =>
|
||||
import('../../domains/meeting/pages/meeting/meeting.component').then((m) => m.MeetingComponent),
|
||||
canActivate: [
|
||||
runGuardsSerially(
|
||||
extractRoomQueryParamsGuard,
|
||||
validateRoomAccessGuard,
|
||||
removeQueryParamsGuard(['secret', WebComponentProperty.E2EE_KEY])
|
||||
)
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'room/:room-id/recordings',
|
||||
loadComponent: () =>
|
||||
import('../../domains/rooms/pages/room-recordings/room-recordings.component').then(
|
||||
(m) => m.RoomRecordingsComponent
|
||||
),
|
||||
canActivate: [
|
||||
runGuardsSerially(
|
||||
extractRecordingQueryParamsGuard,
|
||||
validateRoomRecordingsAccessGuard,
|
||||
removeQueryParamsGuard(['secret', WebComponentProperty.E2EE_KEY])
|
||||
)
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'recording/:recording-id',
|
||||
loadComponent: () =>
|
||||
import('../../domains/recordings/pages/view-recording/view-recording.component').then(
|
||||
(m) => m.ViewRecordingComponent
|
||||
),
|
||||
canActivate: [validateRecordingAccessGuard]
|
||||
},
|
||||
{
|
||||
path: 'disconnected',
|
||||
loadComponent: () =>
|
||||
import('../../domains/meeting/pages/end-meeting/end-meeting.component').then((m) => m.EndMeetingComponent)
|
||||
},
|
||||
{
|
||||
path: 'error',
|
||||
loadComponent: () => import('../../domains/console/pages/error/error.component').then((m) => m.ErrorComponent)
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () =>
|
||||
import('../../domains/console/pages/console/console.component').then((m) => m.ConsoleComponent),
|
||||
canActivate: [checkUserAuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'overview',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'overview',
|
||||
loadComponent: () =>
|
||||
import('../../domains/console/pages/overview/overview.component').then((m) => m.OverviewComponent)
|
||||
},
|
||||
{
|
||||
path: 'rooms',
|
||||
loadComponent: () =>
|
||||
import('../../domains/rooms/pages/rooms/rooms.component').then((m) => m.RoomsComponent)
|
||||
},
|
||||
{
|
||||
path: 'rooms/new',
|
||||
import { authDomainRoutes } from '../../domains/auth/routes/auth.routes';
|
||||
import { consoleDomainRoutes } from '../../domains/console/routes/console.routes';
|
||||
import { meetingDomainRoutes } from '../../domains/meeting/routes/meeting.routes';
|
||||
import { recordingsDomainRoutes } from '../../domains/recordings/routes/recordings.routes';
|
||||
import { roomsDomainRoutes } from '../../domains/rooms/routes/rooms.routes';
|
||||
|
||||
loadComponent: () =>
|
||||
import('../../domains/rooms/pages/room-wizard/room-wizard.component').then(
|
||||
(m) => m.RoomWizardComponent
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'rooms/:roomId/edit',
|
||||
loadComponent: () =>
|
||||
import('../../domains/rooms/pages/room-wizard/room-wizard.component').then(
|
||||
(m) => m.RoomWizardComponent
|
||||
),
|
||||
canActivate: [checkEditableRoomGuard]
|
||||
},
|
||||
{
|
||||
path: 'recordings',
|
||||
loadComponent: () =>
|
||||
import('../../domains/recordings/pages/recordings/recordings.component').then(
|
||||
(m) => m.RecordingsComponent
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'embedded',
|
||||
loadComponent: () =>
|
||||
import('../../domains/console/pages/embedded/embedded.component').then((m) => m.EmbeddedComponent)
|
||||
},
|
||||
{
|
||||
path: 'users-permissions',
|
||||
loadComponent: () =>
|
||||
import('../../domains/console/pages/users-permissions/users-permissions.component').then(
|
||||
(m) => m.UsersPermissionsComponent
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'config',
|
||||
loadComponent: () =>
|
||||
import('../../domains/console/pages/config/config.component').then((m) => m.ConfigComponent)
|
||||
},
|
||||
// {
|
||||
// path: 'about',
|
||||
// component: AboutComponent
|
||||
// },
|
||||
{ path: '**', redirectTo: 'overview' }
|
||||
]
|
||||
},
|
||||
export const baseRoutes: Routes = [
|
||||
// Auth domain routes
|
||||
...authDomainRoutes.map((config) => config.route),
|
||||
|
||||
// Meeting domain routes
|
||||
...meetingDomainRoutes.map((config) => config.route),
|
||||
|
||||
// Rooms domain public routes
|
||||
...roomsDomainRoutes.map((config) => config.route),
|
||||
|
||||
// Recordings domain public routes
|
||||
...recordingsDomainRoutes.map((config) => config.route),
|
||||
|
||||
// Console domain routes (includes console shell, child routes, and guards)
|
||||
...consoleDomainRoutes,
|
||||
|
||||
// Redirect all other routes to the console
|
||||
{ path: '**', redirectTo: '' }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user