LCOV - code coverage report
Current view: top level - dashql-app/src/demos - demos.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 90.2 % 61 55
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : import { createRoot } from 'react-dom/client';
       3              : import { HashRouter, Link, Navigate, Route, Routes, useParams } from 'react-router-dom';
       4              : 
       5              : import { LoggerProvider } from '../platform/logger/logger_provider.js';
       6              : import { EmbeddedDatabaseProvider } from '../platform/database/embedded_database_provider.js';
       7              : import { HttpClientProvider } from '../platform/http/http_client_provider.js';
       8              : import { GitHubTheme } from '../styles/github_theme.js';
       9              : import { LoggerToast } from '../ui/logger/logger_toast.js';
      10              : import { FlavorProvider } from '../config/flavor_provider.js';
      11              : import { FLAVOR_QUERY_PARAMETER, getRequestedFlavor, resolveFlavor } from '../config/flavor_resolution.js';
      12              : import { DASHQL_FLAVOR, type AppFlavor } from '../config/flavors.js';
      13              : import { DEMOS, type DemoEntry } from './demo_registry.js';
      14              : import * as styles from './demos.module.css';
      15              : 
      16              : import '@ankoh/dashql-ui/fonts/fonts.css';
      17              : import '@ankoh/dashql-ui/styles/colors.css';
      18              : import '@ankoh/dashql-ui/styles/tokens.css';
      19              : import '../styles/globals.css';
      20              : import '@ankoh/dashql-ui/styles/flavors/sidb.css';
      21              : 
      22              : /// The pages of the demos, loaded when they are opened
      23            1 : const PAGES = new Map(DEMOS.map(demo => [demo.id, React.lazy(demo.load)]));
      24              : 
      25              : /// The list of the demos
      26            1 : const DemoIndex: React.FC = () => (
      27            1 :     <div className={styles.index}>
      28            1 :         <h1 className={styles.index_title}>DashQL Demos</h1>
      29            1 :         <ul className={styles.index_list}>
      30            1 :             {DEMOS.map((demo: DemoEntry) => (
      31            1 :                 <li key={demo.id}>
      32            1 :                     <Link className={styles.index_entry} to={`/${demo.id}`}>
      33            1 :                         <span className={styles.index_entry_title}>{demo.title}</span>
      34            1 :                         <span className={styles.index_entry_description}>{demo.description}</span>
      35            1 :                     </Link>
      36            1 :                 </li>
      37            1 :             ))}
      38            1 :         </ul>
      39            1 :     </div>
      40              : );
      41              : 
      42              : /// The page of the demo of the route
      43            1 : const DemoPage: React.FC = () => {
      44            1 :     const { demoId } = useParams();
      45            1 :     const Page = demoId == null ? undefined : PAGES.get(demoId);
      46            1 :     if (Page == null) return <Navigate to="/" replace />;
      47            1 :     return (
      48            1 :         <React.Suspense fallback={<div className={styles.loading}>Loading…</div>}>
      49            1 :             <Page />
      50            1 :         </React.Suspense>
      51              :     );
      52            1 : };
      53              : 
      54              : /// Demos of DashQL on Hyper, every demo is a page of its own.
      55              : /// The routes are hashes, `demos.html#/<id>`, so that every host serves the page without rewrites.
      56              : /// A flavor is requested in front of the hash, `demos.html?flavor=sidb#/<id>`, or in the query of the route.
      57            1 : export const Demos: React.FC = () => (
      58            1 :     <HashRouter>
      59            1 :         <LoggerProvider>
      60            1 :             <>
      61            1 :                 <LoggerToast />
      62            1 :                 <HttpClientProvider>
      63            1 :                     <EmbeddedDatabaseProvider>
      64            1 :                         <GitHubTheme>
      65            1 :                             <div className={styles.root}>
      66            1 :                                 <Routes>
      67            1 :                                     <Route index element={<DemoIndex />} />
      68            1 :                                     <Route path="/:demoId" element={<DemoPage />} />
      69            1 :                                 </Routes>
      70            1 :                             </div>
      71            1 :                         </GitHubTheme>
      72            1 :                     </EmbeddedDatabaseProvider>
      73            1 :                 </HttpClientProvider>
      74            1 :             </>
      75            1 :         </LoggerProvider>
      76            1 :     </HashRouter>
      77              : );
      78              : 
      79              : /// The flavor requested by the query of the route, `#/<id>?flavor=sidb`, or else by the query in front of the hash
      80            1 : function getRequestedDemoFlavor(): AppFlavor | null {
      81            1 :     const hash = globalThis.location?.hash ?? '';
      82            1 :     const query = hash.indexOf('?');
      83            1 :     const requested = query < 0 ? null : new URLSearchParams(hash.slice(query + 1)).get(FLAVOR_QUERY_PARAMETER);
      84            1 :     if (requested == null) return getRequestedFlavor();
      85            0 :     const resolution = resolveFlavor(requested);
      86            0 :     if (resolution.unknownId !== undefined) console.warn(`unknown app flavor: ${resolution.unknownId}`);
      87            0 :     return resolution.flavor;
      88            1 : }
      89              : 
      90              : // The demos are branded as DashQL, only a flavor other than the default one rebrands them, e.g. their chart colors
      91            1 : const requested = getRequestedDemoFlavor();
      92            1 : const flavor = requested?.id === DASHQL_FLAVOR.id ? null : requested;
      93              : 
      94            1 : const element = document.getElementById('root');
      95            1 : createRoot(element!).render(flavor == null ? <Demos /> : (
      96            0 :     <FlavorProvider requested={flavor}>
      97            0 :         <Demos />
      98            0 :     </FlavorProvider>
      99            1 : ));
        

Generated by: LCOV version 2.0-1