Skip to content

Commit

Permalink
upgrade routing: use hashmap instead of array for storing routes #13
Browse files Browse the repository at this point in the history
  • Loading branch information
DominikHorn committed Feb 27, 2020
1 parent 97393f6 commit d62da94
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 32 deletions.
6 changes: 3 additions & 3 deletions packages/frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import history from '../util/history';
import { FeatureFlagsProvider } from 'elite-feature-flags';
import { Configuration } from 'elite-types';
import { getConfiguration } from 'elite-configuration';
import { APP_ROUTES } from '../util/routing';
import { getAllRegisteredAppRoutes } from '../util/routing';

// Files must be required for decorator to work
// Files must be required (early!) for decorator to work
require('../components/pages/HomePage');
require('../components/pages/LinkPage');

Expand All @@ -18,7 +18,7 @@ export const AppComponent = () => (
<FeatureFlagsProvider value={configuration.featureMap}>
<Router history={history}>
<Switch>
{APP_ROUTES.map((routeProps, index) => (
{getAllRegisteredAppRoutes().map((routeProps, index) => (
<Route key={index} {...routeProps} />
))}
{/* Error 404 Fallback */}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as React from 'react';
import { Link } from 'react-router-dom';
import { APP_ROUTES, getLinkForPage, getLinkDisplayNameForPage } from '../../../util/routing';
import { getLinkForRoute, getDisplayNameForRoute, getAllRegisteredAppRoutes } from '../../../util/routing';

export const LinkDirectory = () => (
<ul>
{APP_ROUTES.map((route, index) => (
{getAllRegisteredAppRoutes().map((route, index) => (
<li key={index}>
<Link to={getLinkForPage(route)}>{getLinkDisplayNameForPage(route)}</Link>
<Link to={getLinkForRoute(route)}>{getDisplayNameForRoute(route)}</Link>
</li>
))}
</ul>
Expand Down
75 changes: 49 additions & 26 deletions packages/frontend/src/util/routing.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,66 @@
import * as React from 'react';
import { RouteProps } from 'react-router';

// TODO: move to separate package
// If necessary, add support for: H.LocationDescriptor | ((location: H.Location) => H.LocationDescriptor);
type LinkType = string;

/**
* Each Approute can have a specific link (i.e., path with filled parameter placeholders),
* a display Name, i.e., text of the link and a nonoptional (!) path
*/
export interface AppRouteProps extends RouteProps {
// Use this if the link target differs from the path specification,
// i.e., if the path url contains paramter specifications etc
readonly link?: LinkType;

// link text (Human readable!)
readonly displayName?: string;

// AppRoutes must have a path - deoptionalize this property
readonly path: string;
}

/**
* The Routed decorator automatically creates a route for
* the annotated top level page component
*
* @param props route properties
*/
export function Routed(props: AppRouteProps) {
console.log('producing route decorator:', props);
return (constructor: any) => {
APP_ROUTES.push({
export function Routed<T extends React.Component<P> & { render: () => any }, P = any>(
props: AppRouteProps,
): (c: new (props: any) => T) => new (props: any) => T {
return constructor => (
registerAppRoute({
render: p => React.createElement(constructor, p),
...props,
});
console.log('added route for', constructor.name);
return constructor;
};
}),
constructor
);
}

// If necessary, add support for: H.LocationDescriptor | ((location: H.Location) => H.LocationDescriptor);
type LinkType = string;
/**
* Container for all registered app routes
*/
const appRoutes: { [path: string]: AppRouteProps } = {};

// TODO: Add documentation
export interface AppRouteProps extends RouteProps {
// Use this if the link target differs from the path specification,
// i.e., if the path url contains paramter specifications etc
readonly link?: LinkType;
/**
* Function to retrieve all currently registered app routes
*/
export function getAllRegisteredAppRoutes() {
return Object.values(appRoutes);
}

// link text (Human readable!)
readonly displayName?: string;
/**
* Function for registering a new App route
* @param props AppRouteProps. Note that a render() function must be provided
*/
export function registerAppRoute(props: AppRouteProps & Required<Pick<AppRouteProps, 'render'>>) {
if (appRoutes[props.path]) {
throw new Error(`ERROR: detected illegal duplicate app route ${props.path}`);
}

// AppRoutes must have a path - deoptionalize this property
readonly path: string;
appRoutes[props.path] = props;
console.log('added route ', props.path);
}

// TODO: replace with proper container/service class
Expand All @@ -43,7 +69,7 @@ export interface AppRouteProps extends RouteProps {
* to link to a certain route
* @param route the route to link to
*/
export function getLinkForPage(route: AppRouteProps): LinkType {
export function getLinkForRoute(route: AppRouteProps): LinkType {
return route.link || route.path;
}

Expand All @@ -54,9 +80,6 @@ export function getLinkForPage(route: AppRouteProps): LinkType {
*
* @param route
*/
export function getLinkDisplayNameForPage(route: AppRouteProps): string {
return route.displayName || getLinkForPage(route);
export function getDisplayNameForRoute(route: AppRouteProps): string {
return route.displayName || getLinkForRoute(route);
}

// TODO: replace with proper container/service class
export const APP_ROUTES: AppRouteProps[] = [];

0 comments on commit d62da94

Please sign in to comment.