Skip to main content

Routing

Internal navigation derives the /{locale}/org/{organizationId}/v2/ prefix from the ambient URL organization. Row variables named organizationId can template the path tail but cannot replace that prefix. Reusable component definitions also load from the ambient organization. A data grid may explicitly query another tenant with props.options.variables.organizationId; only a resolved positive integer overrides the ambient query organization.

Browser requests whose path does not begin with a supported locale (en-US, fr-FR, or ar-EG) redirect the complete path to the en-US prefix. This applies to deep links as well as single-segment pathsβ€”for example, /orders/123/events becomes /en-US/orders/123/events. Public asset directories (/images, /favicons, and /documents), static files, service-worker files, sitemap/robots files, and front-pages are excluded so asset requests remain at their original URLs. Platform-owned paths (/api, /admin, /.swa, /.auth, and /.well-known) also bypass locale redirects so Azure Static Web Apps health checks, authentication, Functions host requests, and API routes reach their handlers unchanged.

Routes define the navigation structure and access control for different screens within CXTMS. They are a crucial part of the AppModule configuration, determining how users interact with various components of the system.

Introduction​

Routing in CXTMS establishes the hierarchical structure of the application, linking URLs to specific components and managing access permissions. This system ensures efficient navigation and proper security measures throughout the application.

When to Use Routes​

  • When defining the overall structure of your CXTMS application
  • To create new screens or sections within the system
  • When setting up access control for different parts of the application
  • To establish relationships between different components and views

Routes Example​

Transportation Management​

routes:
- name: "Shipments/List"
path: "shipments"
component: "Shipments/ListComponent"
props:
title:
en-US: "Shipments"
requiredPermissions:
- "Shipments/Read"
children: # Nested routes
- name: "Shipments/Details"
path: ":id" # Route path with a dynamic parameter
component: "Shipments/DetailsComponent"

Route Fields​

FieldDescription
nameUnique identifier for the route. Shown on the unauthorized page.
pathURL path, relative to the organization prefix. Supports :param segments.
componentName of the component to render (e.g. Shipments/DetailsComponent).
propsRoute metadata read by the shell (see below). Not passed to the component.
childrenNested routes. The child path is appended to the parent path.
platformsOptional list of platforms (web, mobile). Defaults to both.

Route props​

The route's props object holds metadata that the application shell reads. It is not merged into the component's variables.

PropTypeDescription
titlestring / localizedPage title and browser tab title. Supports template expressions.
requiredPermissionsstring[]The user must hold all listed permissions, otherwise the unauthorized page is shown.
permissionsstring[]Alias of requiredPermissions (used when requiredPermissions is not set).
permissionstringSingle permission. Honored only when the route is opened from a notification link β€” use requiredPermissions for page access control.
iconstringIcon shown for the route in global search.
isSearchablebooleanSet to false to hide a top-level route from global search. Default true.
warning

Permissions must be declared inside props. A permission or requiredPermissions key placed at the route's top level is not checked by the web application.

Component Variables on a Route​

A component rendered by a route receives these variables:

VariableSource
Route parameters:param segments of the matched path. Always strings.
Query parametersThe URL query string. Numeric values are converted to numbers losslessly.
organizationIdThe organization in the current URL.
localeThe locale in the current URL.
currentUserThe signed-in user, including permissionSet.

Because route parameters are strings, cast them in queries: "{{ number orderId }}".

Path Matching​

  • Paths are matched case-insensitively against the part of the URL after /{locale}/org/{organizationId}/v2/. Leading and trailing slashes are ignored.
  • Routes are evaluated in order, and the first match wins.
  • A :param segment matches any single path segment except the literal create, unless the route's own path contains create. This lets orders/create and orders/:orderId coexist.
  • Nesting resolves one level: a child's full path is parent.path/child.path. For deeper hierarchies, give the grandchild route its full path explicitly instead of relying on nested children.
  • If no route matches, a "not found" page is shown. If the user lacks a required permission, an "unauthorized" page is shown.

How to Create Routes​

  1. Open your AppModule configuration file
  2. Locate the routes section
  3. Add a new route entry with the required fields:
routes:
- name: "ExampleRoute"
path: "example"
component: "Example/ExampleComponent"
props:
title:
en-US: "Example Route"
requiredPermissions:
- "ExampleModule/Read"
  1. For nested routes, add them under the children property of a parent route
  2. Save your configuration file

A component can be opened in two ways:

  • As a page β€” through a route, using the navigate action or the redirect component.
  • As a dialog β€” on top of the current screen, using the dialog action. The component is referenced by the same name used in the route's component field.

Design detail and edit components so they work in both contexts: finish with navigateBackOrClose, which closes the dialog (returning result to the caller) or navigates back when the component is a page.

# Open as a page
- navigate: "orders/{{ orderId }}"

# Open the same component as a dialog
- dialog:
component: "Orders/Detail"
props:
title: { en-US: "Order Details" }
orderId: "{{ orderId }}" # dialog props become the component's variables
onClose:
- if: "{{ result }}"
then:
- refresh: ordersGrid

Route Matching for Linked Notifications and Dialogs​

CXTMS route matching supports entity-style paths such as Order/12345 or Terminal/42. When a notification includes entityType and entityId, the UI resolves the target route by matching the generated path (entityType/entityId) against configured app routes. If a matching route exists and the current user has all route permissions, the target component opens in a dialog with route parameters converted to numbers when possible.

The web notification bell only lists notifications delivered through the Web channel. Push-only notifications remain in the mobile notification experience and do not appear in the web bell. To make a linked notification available on both renderers, include both Web and Push in its delivery channels.

Notification access checks read these shapes from the route's props (first match wins):

  • requiredPermissions: ["Terminal/Read"]
  • permissions: ["Terminal/Read", "Port/Read"]
  • permission: "Terminal/Read"

For notification dialogs, matched route parameters are converted to numbers only when the conversion is lossless. (On a regular page, route parameters stay strings β€” see Component Variables on a Route.) Ordinary values such as 42 become numbers, while leading-zero identifiers, exponential notation, hexadecimal strings, whitespace-padded values, and integers larger than JavaScript's safe range remain strings. This prevents tracking numbers and external IDs from being rounded or rewritten when passed into a linked screen or dialog.

Use dynamic route parameters for entity detail screens so notifications can deep-link cleanly:

routes:
- name: "Terminals/Detail"
path: "Terminal/:terminalId"
component: "Terminals/TerminalDetail"
props:
title: "Terminal {{ terminalId }}"
requiredPermissions:
- "Terminal/Read"

Mobile back navigation​

The mobile renderer keeps an application-level route history and dispatches stack navigation actions through the container ref. navigateBack returns to the previous SDUI screen when one exists and falls back cleanly when the app was cold-started or the history is empty. This preserves nested stack behavior without requiring module authors to change route definitions.

On phones, modal routes use the native iOS-style slide-from-bottom transition. Tablets continue to use the standard screen transition. This renderer behavior requires no route YAML changes.

Reactive Page Titles​

Route props.title and root component displayName can be template expressions. The screen title and browser document.title are evaluated against the app module store and update when store values change.

routes:
- name: "Orders/Detail"
path: "orders/:orderId"
component: "Orders/Detail"
props:
title: "Order {{ order.orderNumber }}"

Prefer route props.title for route-specific labels and component displayName for reusable component defaults. Unauthorized-route messages use the route name/path rather than parsing templated titles, because store data may not be available when access is denied.

Best Practices​

  1. Use descriptive and consistent naming conventions for route names
  2. Keep URL paths (the path property) short and meaningful
  3. Organize routes hierarchically to reflect the structure of your application
  4. Always set props.requiredPermissions to ensure proper access control
  5. Pass data to a routed component through :param path segments or query parameters, not route props
  6. Use entity-style detail paths (Order/:orderId) so notification links can open them as dialogs