From 254c393fbb1d0946af911ebb6a46b5c0166b3213 Mon Sep 17 00:00:00 2001 From: Michael Haufe Date: Sun, 7 Jan 2024 19:08:51 -0600 Subject: [PATCH] Refactored routing --- src/lib/zipWith.mts | 9 +++ src/presentation/Application.mts | 77 +++++++++++++------ src/presentation/Router.mts | 63 --------------- .../pages/{Home.mts => HomePage.mts} | 3 +- .../pages/{NotFound.mts => NotFoundPage.mts} | 3 +- src/presentation/pages/Page.mts | 21 +++-- src/presentation/pages/SlugPage.mts | 27 ------- .../{Environment.mts => EnvironmentPage.mts} | 3 +- ...{Environments.mts => EnvironmentsPage.mts} | 3 +- .../{Glossary.mts => GlossaryPage.mts} | 7 +- ...Environment.mts => NewEnvironmentPage.mts} | 3 +- ...unctionality.mts => FunctionalityPage.mts} | 7 +- .../pages/goals/{Goal.mts => GoalPage.mts} | 3 +- .../pages/goals/{Goals.mts => GoalsPage.mts} | 3 +- .../{Limitations.mts => LimitationsPage.mts} | 7 +- .../goals/{NewGoals.mts => NewGoalsPage.mts} | 3 +- .../{Rationale.mts => RationalePage.mts} | 9 ++- ...{Stakeholders.mts => StakeholdersPage.mts} | 7 +- .../goals/{UseCases.mts => UseCasesPage.mts} | 7 +- .../{Projects.mts => ProjectsPage.mts} | 4 +- 20 files changed, 121 insertions(+), 148 deletions(-) create mode 100644 src/lib/zipWith.mts delete mode 100644 src/presentation/Router.mts rename src/presentation/pages/{Home.mts => HomePage.mts} (76%) rename src/presentation/pages/{NotFound.mts => NotFoundPage.mts} (79%) delete mode 100644 src/presentation/pages/SlugPage.mts rename src/presentation/pages/environments/{Environment.mts => EnvironmentPage.mts} (82%) rename src/presentation/pages/environments/{Environments.mts => EnvironmentsPage.mts} (88%) rename src/presentation/pages/environments/{Glossary.mts => GlossaryPage.mts} (91%) rename src/presentation/pages/environments/{NewEnvironment.mts => NewEnvironmentPage.mts} (96%) rename src/presentation/pages/goals/{Functionality.mts => FunctionalityPage.mts} (92%) rename src/presentation/pages/goals/{Goal.mts => GoalPage.mts} (93%) rename src/presentation/pages/goals/{Goals.mts => GoalsPage.mts} (87%) rename src/presentation/pages/goals/{Limitations.mts => LimitationsPage.mts} (91%) rename src/presentation/pages/goals/{NewGoals.mts => NewGoalsPage.mts} (97%) rename src/presentation/pages/goals/{Rationale.mts => RationalePage.mts} (93%) rename src/presentation/pages/goals/{Stakeholders.mts => StakeholdersPage.mts} (96%) rename src/presentation/pages/goals/{UseCases.mts => UseCasesPage.mts} (95%) rename src/presentation/pages/projects/{Projects.mts => ProjectsPage.mts} (75%) diff --git a/src/lib/zipWith.mts b/src/lib/zipWith.mts new file mode 100644 index 00000000..086eea1a --- /dev/null +++ b/src/lib/zipWith.mts @@ -0,0 +1,9 @@ +/** + * Zips two arrays together with a function. + * @param xs The first array. + * @param ys The second array. + * @param f The function to zip the arrays with. + * @returns An array of the merged values. + */ +export default (xs: X[], ys: Y[], f: (x: X, y: Y) => Z) => + xs.map((x, i) => f(x, ys[i])); \ No newline at end of file diff --git a/src/presentation/Application.mts b/src/presentation/Application.mts index 10b2a828..41ddf769 100644 --- a/src/presentation/Application.mts +++ b/src/presentation/Application.mts @@ -1,5 +1,5 @@ import type Page from './pages/Page.mjs'; -import Router from './Router.mjs'; +import NotFoundPage from './pages/NotFoundPage.mjs'; import html from './lib/html.mjs'; import { Breadcrumb, Container, GlobalNav } from '~components/index.mjs'; @@ -8,16 +8,14 @@ export default class Application extends Container { customElements.define('x-application', this); } #currentPage: Page | null = null; - #router!: Router; + #pages!: typeof Page[]; constructor() { super({}, []); document.body.innerHTML = ''; this._installOrUpdateServiceWorker(); - this._initRouter().then(() => { - self.navigation.navigate(location.pathname); - }); + this._initPages().then(() => self.navigation.navigate(location.href)); } protected override _initShadowHtml() { @@ -62,25 +60,27 @@ export default class Application extends Container { }; } - protected async _initRouter() { - this.#router = new Router([ - ['/', (await import('./pages/Home.mjs')).Home], - ['/not-found', (await import('./pages/NotFound.mjs')).NotFound], - ['/projects', (await import('./pages/projects/Projects.mjs')).Projects], - ['/environments', (await import('./pages/environments/Environments.mjs')).Environments], - ['/environments/new-entry', (await import('./pages/environments/NewEnvironment.mjs')).NewEnvironment], - ['/environments/:slug', (await import('./pages/environments/Environment.mjs')).Environment], - ['/environments/:slug/glossary', (await import('./pages/environments/Glossary.mjs')).Glossary], - ['/goals', (await import('./pages/goals/Goals.mjs')).Goals], - ['/goals/new-entry', (await import('./pages/goals/NewGoals.mjs')).NewGoals], - ['/goals/:slug', (await import('./pages/goals/Goal.mjs')).Goal], - ['/goals/:slug/rationale', (await import('./pages/goals/Rationale.mjs')).Rationale], - ['/goals/:slug/functionality', (await import('./pages/goals/Functionality.mjs')).Functionality], - ['/goals/:slug/stakeholders', (await import('./pages/goals/Stakeholders.mjs')).Stakeholders], - ['/goals/:slug/use-cases', (await import('./pages/goals/UseCases.mjs')).UseCases], - ['/goals/:slug/limitations', (await import('./pages/goals/Limitations.mjs')).Limitations], - ]); - this.#router.addEventListener('route', this); + protected async _initPages() { + this.#pages = [ + (await import('./pages/HomePage.mjs')).default, + NotFoundPage, + (await import('./pages/projects/ProjectsPage.mjs')).default, + (await import('./pages/environments/NewEnvironmentPage.mjs')).default, + (await import('./pages/environments/EnvironmentPage.mjs')).default, + (await import('./pages/environments/EnvironmentsPage.mjs')).default, + (await import('./pages/environments/GlossaryPage.mjs')).default, + (await import('./pages/goals/NewGoalsPage.mjs')).default, + (await import('./pages/goals/GoalPage.mjs')).default, + (await import('./pages/goals/GoalsPage.mjs')).default, + (await import('./pages/goals/RationalePage.mjs')).default, + (await import('./pages/goals/FunctionalityPage.mjs')).default, + (await import('./pages/goals/StakeholdersPage.mjs')).default, + (await import('./pages/goals/UseCasesPage.mjs')).default, + (await import('./pages/goals/LimitationsPage.mjs')).default, + ]; + + self.navigation.addEventListener('navigate', this); + this.addEventListener('route', this); } protected async _installServiceWorker() { @@ -122,6 +122,35 @@ export default class Application extends Container { } } + onNavigate(event: NavigateEvent): void { + if (!event.canIntercept || event.hashChange) + return; + + const origin = document.location.origin, + url = new URL(event.destination.url, origin), + Page = this.#pages.find(Page => { + const route = Page.route, + pattern = route.split('/'), + pathname = url.pathname.split('/'); + + if (pattern.length !== pathname.length) + return false; + + return pattern.every((segment, index) => { + if (segment.startsWith(':')) + return true; + + return segment === pathname[index]; + }); + }) ?? NotFoundPage; + event.intercept({ + handler: async () => { + event.preventDefault(); + this.dispatchEvent(new CustomEvent('route', { detail: Page })); + } + }); + } + onRoute(event: CustomEvent) { const Cons = event.detail; this.#currentPage = new Cons({}, []); diff --git a/src/presentation/Router.mts b/src/presentation/Router.mts deleted file mode 100644 index 2f8368a7..00000000 --- a/src/presentation/Router.mts +++ /dev/null @@ -1,63 +0,0 @@ -// Utilizes the Navigation API to intercept navigation events and handle them -// As of 2023-11-01, the Navigation API is still experimental and supported -// by only Chromium-based browsers (~71% coverage) -// https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API -// https://developer.chrome.com/docs/web-platform/navigation-api/ -// https://caniuse.com/mdn-api_navigation -// Types are polyfilled via dom-navigation package -import { HandleEvent } from './HandleEvent.mjs'; -import { NotFound } from './pages/NotFound.mjs'; -import Page from './pages/Page.mjs'; - -export default class Router extends HandleEvent(EventTarget) { - #routeTable: Map; - - constructor(routes: [string, typeof Page][]) { - super(); - this.#routeTable = new Map(routes); - self.navigation.addEventListener('navigate', this); - } - - addRoute(path: string, PageCons: typeof Page): void { - this.#routeTable.set(path, PageCons); - } - - onNavigate(event: NavigateEvent): void { - if (!event.canIntercept || event.hashChange) - return; - - const origin = document.location.origin, - url = new URL(event.destination.url, origin), - // Page = this.#routeTable.get(url.pathname) ?? NotFound; - - // Search for a matching route pattern in the route table. Patterns - // are of the form /:param1/:param2/:param3, where the colon - // indicates a parameter. - candidate = [...this.#routeTable.keys()].find(path => { - const pattern = path.split('/'), - pathname = url.pathname.split('/'); - - if (pattern.length !== pathname.length) - return false; - - return pattern.every((segment, index) => { - if (segment.startsWith(':')) - return true; - - return segment === pathname[index]; - }); - }), - Page = candidate ? this.#routeTable.get(candidate) : NotFound; - - event.intercept({ - handler: async () => { - event.preventDefault(); - this.dispatchEvent(new CustomEvent('route', { detail: Page })); - } - }); - } - - async route(pathname: string): Promise { - await self.navigation.navigate(pathname).finished; - } -} \ No newline at end of file diff --git a/src/presentation/pages/Home.mts b/src/presentation/pages/HomePage.mts similarity index 76% rename from src/presentation/pages/Home.mts rename to src/presentation/pages/HomePage.mts index c263a9e9..0dcf42b3 100644 --- a/src/presentation/pages/Home.mts +++ b/src/presentation/pages/HomePage.mts @@ -3,7 +3,8 @@ import Page from './Page.mjs'; const { p } = html; -export class Home extends Page { +export default class HomePage extends Page { + static override route = '/'; static { customElements.define('x-page-home', this); } diff --git a/src/presentation/pages/NotFound.mts b/src/presentation/pages/NotFoundPage.mts similarity index 79% rename from src/presentation/pages/NotFound.mts rename to src/presentation/pages/NotFoundPage.mts index 59679820..c84b215f 100644 --- a/src/presentation/pages/NotFound.mts +++ b/src/presentation/pages/NotFoundPage.mts @@ -3,7 +3,8 @@ import html from '../lib/html.mjs'; const { h1, p, a } = html; -export class NotFound extends Page { +export default class NotFoundPage extends Page { + static override route = '/not-found'; static { customElements.define('x-page-not-found', this); } diff --git a/src/presentation/pages/Page.mts b/src/presentation/pages/Page.mts index 52aa0004..3ed4fc6a 100644 --- a/src/presentation/pages/Page.mts +++ b/src/presentation/pages/Page.mts @@ -1,18 +1,27 @@ +import zipWith from '~/lib/zipWith.mjs'; import type { Properties } from '~/types/Properties.mjs'; import buttonTheme from '~/presentation/theme/buttonTheme.mjs'; import { Container } from '~components/index.mjs'; import type { Theme } from '~/types/Theme.mjs'; export default class Page extends Container { - protected override _initShadowStyle() { - return { - ...super._initShadowStyle() - }; - } + static route = '{undefined}'; - constructor(properties: Properties, children: (Element | string)[]) { + urlParams; + + constructor(properties: Exclude, 'urlParams'>, children: (Element | string)[]) { super(properties, children); + const url = new URL(location.href, document.location.origin), + pattern = (this.constructor as typeof Page).route.split('/'), + pathname = url.pathname.split('/'); + this.urlParams = Object.fromEntries(url.searchParams.entries()); + + zipWith(pattern, pathname, (p, n) => { + if (p.startsWith(':')) + this.urlParams[p.slice(1)] = n; + }); + const sheet = new CSSStyleSheet(), pageStyle = this._initPageStyle(), styleElement = document.createElement('style'); diff --git a/src/presentation/pages/SlugPage.mts b/src/presentation/pages/SlugPage.mts deleted file mode 100644 index 8c0d3730..00000000 --- a/src/presentation/pages/SlugPage.mts +++ /dev/null @@ -1,27 +0,0 @@ -import Page from './Page.mjs'; -import html, { renderIf } from '../lib/html.mjs'; -import type { Properties } from '~/types/Properties.mjs'; - -const { p } = html; - -/** - * A page that utilizes a slug identifier. - */ -export default abstract class SlugPage extends Page { - // /parent/:slug/foo - #slug = new URL(location.href, document.location.origin).pathname.split('/')[2]; - - constructor(properties: Properties, children: (string | Element)[]) { - super(properties, children); - - this.appendChild( - p({ - [renderIf]: !this.#slug - }, 'No slug identifier provided') - ); - } - - get slug() { - return this.#slug; - } -} \ No newline at end of file diff --git a/src/presentation/pages/environments/Environment.mts b/src/presentation/pages/environments/EnvironmentPage.mts similarity index 82% rename from src/presentation/pages/environments/Environment.mts rename to src/presentation/pages/environments/EnvironmentPage.mts index f836d46b..a034aa6b 100644 --- a/src/presentation/pages/environments/Environment.mts +++ b/src/presentation/pages/environments/EnvironmentPage.mts @@ -1,7 +1,8 @@ import { MiniCards, MiniCard } from '~/presentation/components/index.mjs'; import Page from '../Page.mjs'; -export class Environment extends Page { +export default class EnvironmentPage extends Page { + static override route = '/environments/:slug'; static { customElements.define('x-environment-page', this); } diff --git a/src/presentation/pages/environments/Environments.mts b/src/presentation/pages/environments/EnvironmentsPage.mts similarity index 88% rename from src/presentation/pages/environments/Environments.mts rename to src/presentation/pages/environments/EnvironmentsPage.mts index 05b432b9..452fef1a 100644 --- a/src/presentation/pages/environments/Environments.mts +++ b/src/presentation/pages/environments/EnvironmentsPage.mts @@ -5,7 +5,8 @@ import EnvironmentRepository from '~/data/EnvironmentRepository.mjs'; const { p } = html; -export class Environments extends Page { +export default class EnvironmentsPage extends Page { + static override route = '/environments'; static { customElements.define('x-environments-page', this); } diff --git a/src/presentation/pages/environments/Glossary.mts b/src/presentation/pages/environments/GlossaryPage.mts similarity index 91% rename from src/presentation/pages/environments/Glossary.mts rename to src/presentation/pages/environments/GlossaryPage.mts index fc7eb7e0..3d3b6f0f 100644 --- a/src/presentation/pages/environments/Glossary.mts +++ b/src/presentation/pages/environments/GlossaryPage.mts @@ -1,14 +1,15 @@ import html from '~/presentation/lib/html.mjs'; import { DataTable } from '~/presentation/components/DataTable.mjs'; -import SlugPage from '../SlugPage.mjs'; import GlossaryTerm from '~/domain/GlossaryTerm.mjs'; import EnvironmentRepository from '~/data/EnvironmentRepository.mjs'; import GlossaryRepository from '~/data/GlossaryRepository.mjs'; import type Environment from '~/domain/Environment.mjs'; +import Page from '../Page.mjs'; const { p } = html; -export class Glossary extends SlugPage { +export default class GlossaryPage extends Page { + static override route = '/environments/:slug/glossary'; static { customElements.define('x-glossary-page', this); } @@ -59,7 +60,7 @@ export class Glossary extends SlugPage { this.#environmentRepository.addEventListener('update', () => dataTable.renderData()); this.#glossaryRepository.addEventListener('update', () => dataTable.renderData()); - this.#environmentRepository.getBySlug(this.slug).then(environment => { + this.#environmentRepository.getBySlug(this.urlParams['slug']).then(environment => { this.#environment = environment; dataTable.renderData(); }); diff --git a/src/presentation/pages/environments/NewEnvironment.mts b/src/presentation/pages/environments/NewEnvironmentPage.mts similarity index 96% rename from src/presentation/pages/environments/NewEnvironment.mts rename to src/presentation/pages/environments/NewEnvironmentPage.mts index c8e91346..e7da5621 100644 --- a/src/presentation/pages/environments/NewEnvironment.mts +++ b/src/presentation/pages/environments/NewEnvironmentPage.mts @@ -8,7 +8,8 @@ import requiredTheme from '~/presentation/theme/requiredTheme.mjs'; const { form, label, input, span, button } = html; -export class NewEnvironment extends Page { +export default class NewEnvironmentPage extends Page { + static override route = '/environments/new-entry'; static { customElements.define('x-new-environment-page', this); } diff --git a/src/presentation/pages/goals/Functionality.mts b/src/presentation/pages/goals/FunctionalityPage.mts similarity index 92% rename from src/presentation/pages/goals/Functionality.mts rename to src/presentation/pages/goals/FunctionalityPage.mts index a30e7100..b2a8e918 100644 --- a/src/presentation/pages/goals/Functionality.mts +++ b/src/presentation/pages/goals/FunctionalityPage.mts @@ -4,11 +4,12 @@ import GoalsRepository from '~/data/GoalsRepository.mjs'; import BehaviorRepository from '~/data/BehaviorRepository.mjs'; import html from '~/presentation/lib/html.mjs'; import { DataTable } from '~/presentation/components/DataTable.mjs'; -import SlugPage from '../SlugPage.mjs'; +import Page from '../Page.mjs'; const { p, strong } = html; -export class Functionality extends SlugPage { +export default class FunctionalityPage extends Page { + static override route = '/goals/:slug/functionality'; static { customElements.define('x-functionality-page', this); } @@ -58,7 +59,7 @@ export class Functionality extends SlugPage { this.#goalsRepository.addEventListener('update', () => dataTable.renderData()); this.#behaviorRepository.addEventListener('update', () => dataTable.renderData()); - this.#goalsRepository.getBySlug(this.slug).then(goals => { + this.#goalsRepository.getBySlug(this.urlParams['slug']).then(goals => { this.#goals = goals; dataTable.renderData(); }); diff --git a/src/presentation/pages/goals/Goal.mts b/src/presentation/pages/goals/GoalPage.mts similarity index 93% rename from src/presentation/pages/goals/Goal.mts rename to src/presentation/pages/goals/GoalPage.mts index 2d3a8590..9d453e45 100644 --- a/src/presentation/pages/goals/Goal.mts +++ b/src/presentation/pages/goals/GoalPage.mts @@ -1,7 +1,8 @@ import Page from '../Page.mjs'; import { MiniCards, MiniCard } from '~/presentation/components/index.mjs'; -export class Goal extends Page { +export default class GoalPage extends Page { + static override route = '/goals/:slug'; static { customElements.define('x-goal-page', this); } diff --git a/src/presentation/pages/goals/Goals.mts b/src/presentation/pages/goals/GoalsPage.mts similarity index 87% rename from src/presentation/pages/goals/Goals.mts rename to src/presentation/pages/goals/GoalsPage.mts index 3248ac04..0c2c493c 100644 --- a/src/presentation/pages/goals/Goals.mts +++ b/src/presentation/pages/goals/GoalsPage.mts @@ -5,7 +5,8 @@ import GoalsRepository from '~/data/GoalsRepository.mjs'; const { p } = html; -export class Goals extends Page { +export default class GoalsPage extends Page { + static override route = '/goals'; static { customElements.define('x-goals-page', this); } diff --git a/src/presentation/pages/goals/Limitations.mts b/src/presentation/pages/goals/LimitationsPage.mts similarity index 91% rename from src/presentation/pages/goals/Limitations.mts rename to src/presentation/pages/goals/LimitationsPage.mts index ec9b1785..5489bfae 100644 --- a/src/presentation/pages/goals/Limitations.mts +++ b/src/presentation/pages/goals/LimitationsPage.mts @@ -4,11 +4,12 @@ import GoalsRepository from '~/data/GoalsRepository.mjs'; import LimitRepository from '~/data/LimitRepository.mjs'; import html from '~/presentation/lib/html.mjs'; import { DataTable } from '~/presentation/components/DataTable.mjs'; -import SlugPage from '../SlugPage.mjs'; +import Page from '../Page.mjs'; const { p } = html; -export class Limitations extends SlugPage { +export default class LimitationsPage extends Page { + static override route = '/goals/:slug/limitations'; static { customElements.define('x-limitations-page', this); } @@ -60,7 +61,7 @@ export class Limitations extends SlugPage { this.#goalsRepository.addEventListener('update', () => dataTable.renderData()); this.#limitRepository.addEventListener('update', () => dataTable.renderData()); - this.#goalsRepository.getBySlug(this.slug).then(goals => { + this.#goalsRepository.getBySlug(this.urlParams['slug']).then(goals => { this.#goals = goals; dataTable.renderData(); }); diff --git a/src/presentation/pages/goals/NewGoals.mts b/src/presentation/pages/goals/NewGoalsPage.mts similarity index 97% rename from src/presentation/pages/goals/NewGoals.mts rename to src/presentation/pages/goals/NewGoalsPage.mts index 3d2d9ff2..5323bdad 100644 --- a/src/presentation/pages/goals/NewGoals.mts +++ b/src/presentation/pages/goals/NewGoalsPage.mts @@ -8,7 +8,8 @@ import Page from '../Page.mjs'; const { form, label, input, span, button } = html; -export class NewGoals extends Page { +export default class NewGoalsPage extends Page { + static override route = '/goals/new-entry'; static { customElements.define('x-new-goals-page', this); } diff --git a/src/presentation/pages/goals/Rationale.mts b/src/presentation/pages/goals/RationalePage.mts similarity index 93% rename from src/presentation/pages/goals/Rationale.mts rename to src/presentation/pages/goals/RationalePage.mts index 45b60324..0941c089 100644 --- a/src/presentation/pages/goals/Rationale.mts +++ b/src/presentation/pages/goals/RationalePage.mts @@ -1,11 +1,12 @@ import Goals from '~/domain/Goals.mjs'; import GoalsRepository from '~/data/GoalsRepository.mjs'; import html from '~/presentation/lib/html.mjs'; -import SlugPage from '../SlugPage.mjs'; +import Page from '../Page.mjs'; const { form, h3, p, textarea } = html; -export class Rationale extends SlugPage { +export default class RationalePage extends Page { + static override route = '/goals/:slug/rationale'; static { customElements.define('x-rationale-page', this); } @@ -16,10 +17,10 @@ export class Rationale extends SlugPage { constructor() { super({ title: 'Rationale' }, []); - this.#repository.getBySlug(this.slug)!.then(goals => { + this.#repository.getBySlug(this.urlParams['slug'])!.then(goals => { if (!goals) { this.replaceChildren( - p(`No goals found for the provided slug: ${this.slug}`) + p(`No goals found for the provided slug: ${this.urlParams['slug']}`) ); } else { diff --git a/src/presentation/pages/goals/Stakeholders.mts b/src/presentation/pages/goals/StakeholdersPage.mts similarity index 96% rename from src/presentation/pages/goals/Stakeholders.mts rename to src/presentation/pages/goals/StakeholdersPage.mts index 3bf5fe76..1c434843 100644 --- a/src/presentation/pages/goals/Stakeholders.mts +++ b/src/presentation/pages/goals/StakeholdersPage.mts @@ -4,14 +4,15 @@ import GoalsRepository from '~/data/GoalsRepository.mjs'; import StakeholderRepository from '~/data/StakeholderRepository.mjs'; import html from '~/presentation/lib/html.mjs'; import { DataTable } from '~/presentation/components/DataTable.mjs'; -import SlugPage from '../SlugPage.mjs'; +import Page from '../Page.mjs'; import { Tabs } from '~components/Tabs.mjs'; import mermaid from 'mermaid'; import groupBy from '~/lib/groupBy.mjs'; const { h2, p, div } = html; -export class Stakeholders extends SlugPage { +export default class StakeholdersPage extends Page { + static override route = '/goals/:slug/stakeholders'; static { customElements.define('x-stakeholders-page', this); mermaid.initialize({ @@ -87,7 +88,7 @@ export class Stakeholders extends SlugPage { dataTable.renderData(); this.#renderStakeholderMap(); }); - this.#goalsRepository.getBySlug(this.slug).then(async goals => { + this.#goalsRepository.getBySlug(this.urlParams['slug']).then(async goals => { this.#goals = goals; dataTable.renderData(); this.#renderStakeholderMap(); diff --git a/src/presentation/pages/goals/UseCases.mts b/src/presentation/pages/goals/UseCasesPage.mts similarity index 95% rename from src/presentation/pages/goals/UseCases.mts rename to src/presentation/pages/goals/UseCasesPage.mts index 65dfe025..22decce1 100644 --- a/src/presentation/pages/goals/UseCases.mts +++ b/src/presentation/pages/goals/UseCasesPage.mts @@ -1,6 +1,6 @@ import html from '~/presentation/lib/html.mjs'; import { DataTable } from '~/presentation/components/DataTable.mjs'; -import SlugPage from '../SlugPage.mjs'; +import Page from '../Page.mjs'; import { Tabs } from '~components/Tabs.mjs'; import mermaid from 'mermaid'; import UseCase from '~/domain/UseCase.mjs'; @@ -12,7 +12,8 @@ import UseCaseRepository from '~/data/UseCaseRepository.mjs'; const { h2, p, div, br } = html; -export class UseCases extends SlugPage { +export default class UseCasesPage extends Page { + static override route = '/goals/:slug/use-cases'; static { customElements.define('x-use-cases-page', this); mermaid.initialize({ @@ -76,7 +77,7 @@ export class UseCases extends SlugPage { this.#goalsRepository.addEventListener('update', update); this.#stakeholderRepository.addEventListener('update', update); - this.#goalsRepository.getBySlug(this.slug) + this.#goalsRepository.getBySlug(this.urlParams['slug']) .then(goals => { this.#goals = goals; }) .then(update); this.#useCaseRepository.addEventListener('update', update); diff --git a/src/presentation/pages/projects/Projects.mts b/src/presentation/pages/projects/ProjectsPage.mts similarity index 75% rename from src/presentation/pages/projects/Projects.mts rename to src/presentation/pages/projects/ProjectsPage.mts index 7261c377..b779d5af 100644 --- a/src/presentation/pages/projects/Projects.mts +++ b/src/presentation/pages/projects/ProjectsPage.mts @@ -3,10 +3,12 @@ import Page from '../Page.mjs'; const { p } = html; -export class Projects extends Page { +export default class ProjectsPage extends Page { + static override route = '/projects'; static { customElements.define('x-projects-page', this); } + constructor() { super({ title: 'Projects' }, [ p('{Projects}')